• ios app唤起页面跳转


    有些时候我们需要再其他地方把app唤起,并打开跳转到指定的vc上面。这里我自己写了一个vc的mgr,最主要的技术是method swizzle。原理就不详述,看代码吧。


    //
    //  ViewControllerMgr.h
    //  
    //
    //  Created by Tommy on 13-8-14.
    //  Copyright (c) 2013年 Tommy. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    
    @protocol ViewControllerMgrDelegate <NSObject>
    
    
    
    - (BOOL) willCreateVC:(NSURL*)url;
    - (BOOL) willPresentVC:(UIViewController*)onVc currentVC:(UIViewController*) presentVC url:(NSURL*)url;
    
    
    //if return no, will not dispatch delay url
    - (BOOL) willDispatchDelayedUrl:(NSURL*)url;
    //- (BOOL) needchangeToNextVC:(UIViewController*)onVc;
    
    
    @optional
    //if return no, will not set the param by vcmgr
    //please set param by yourself in delegate, and return no
    - (BOOL) willSetParamter:(UIViewController*)onVc key:(NSString*)key value:(NSString*)value;
    
    @optional
    
    - (UIViewController*) creatViewController:(NSString*)vcKey paramters:(NSDictionary*)parameters;
    
    @end
    
    #define  dispatch_delayed_notification_name @"_dispatchDelayedViewControllers"
    
    @interface ViewControllerMgr : NSObject
    
    @property(weak) id<ViewControllerMgrDelegate> delegate;
    
    +(id) sharedInstance;
    
    //如果当前的vc刚好和需要显示的vc是同一个类,如果不需要再这个之上弹出,而只是修改当前vc的内容,请设置为YES,否则为NO
    //默认为NO
    @property (assign) BOOL enablePresentOnSameVC;
    @property (strong) NSString * scheme;
    //保持需要被推迟的vc 的url
    @property (strong) NSMutableArray * delayedUrlArray;
    
    - (BOOL) handleUrl:(NSURL*)url;
    
    
    - (void) registerViewController:(NSString*)key  ClassName:(NSString*)vcName;
    - (void) registerViewController:(NSString*)key  Class:(Class) vcClass;
    - (void) registerViewController:(NSDictionary*)dic;
    
    //register vc init paramters
    - (void) registerInitParameters:(NSArray*) array ClassName:(NSString*)vcName;
    - (void) registerVCWithClassName:(NSString*)vcName;
    - (void) registerVCInitWithCoder:(NSCoder *)aDecoder ClassName:(NSString*)vcName;
    - (void) registerVCInitWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil ClassName:(NSString*)vcName;
    
    
    //delay
    - (void) addToDelay:(NSURL*)url;
    //call by
    - (void) dispatchDelayedViewControllers;
    - (void) addViewControllerToDispatchQueue:(UIViewController*)vc;
    
    //暂时不支持
    //- (void) presentViewController:(NSString*)key;
    //- (void) presentModalViewController:(NSString*)key paramters:(NSString*)paramters;
    
    - (void) presentModalViewController:(NSURL*)url;
    
    - (UIView*) topView;
    - (UIViewController*) topViewController;
    
    
    
    
    @end
    



    //
    //  ViewControllerMgr.m
    // 
    //
    //  Created by Tommy on 13-8-14.
    //  Copyright (c) 2013年 Tommy. All rights reserved.
    //
    
    #import "ViewControllerMgr.h"
    #import <objc/runtime.h>
    #import <objc/objc.h>
    
    
    //static TomStack* s_vcStack = nil;
    static NSMutableDictionary* s_vcInitParametersDic = nil;
    
    #pragma mark -
    #pragma mark implement BaseViewController
    UIViewController * g_lastViewController = nil;
    
    
    #pragma mark -
    #pragma mark implement ViewControllerMgr
    static ViewControllerMgr* s_vcmgr = nil;
    @implementation ViewControllerMgr
    {
        NSMutableDictionary* vcDic;
        
        BOOL dispatchOpened;
    }
    
    - (id) init
    {
        if(self =[super init])
        {
            vcDic = [NSMutableDictionary new];
            _enablePresentOnSameVC = NO;
            dispatchOpened = NO;
            
            [self installHook];
        }
        
        return self;
    }
    
    +(id) sharedInstance
    {
        
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            if (s_vcmgr == nil)
            {
                s_vcmgr = [[self alloc] init]; //autorelease];
                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dispatchDelayedViewControllers) name:dispatch_delayed_notification_name object:nil];
            }
        });
    
        return s_vcmgr;
    }
    
    +(id) allocWithZone:(NSZone *)zone
    {
        @synchronized(self)
        {
            if (s_vcmgr == nil)
            {
                s_vcmgr = [super allocWithZone:zone];
                return s_vcmgr;
            }
        }   
        return nil; 
    }
    
    - (BOOL) handleUrl:(NSURL*)url 
    {
        NSAssert(_scheme,@"scheme is null");
        NSAssert(_delegate,@"delegate is null");
        
        @try {
            if(url && _scheme && [_scheme isEqualToString:[url scheme]])
            {
                [[ViewControllerMgr sharedInstance] presentModalViewController:url];
                return YES;
            }
        }
        @catch (NSException *exception) {
            NSLog(@"严重错误!!!!!");
        }
        
        return NO;
    }
    
    //register vc
    -(void) registerViewController:(NSString*)key  ClassName:(NSString*)vcName
    {
        [self registerViewController:key  Class:NSClassFromString(vcName)];
    }
    -(void) registerViewController:(NSString*)key  Class:(Class) vcClass
    {
        //if([vcClass isKindOfClass:[UIViewController class]])
        [vcDic setObject:vcClass forKey:key];
    }
    - (void) registerViewController:(NSDictionary*)dic
    {
        for(id obj in dic)
        {
            [self registerViewController:obj ClassName:[dic valueForKey:obj]];
        }
    }
    
    //register
    #pragma mark -
    #pragma mark register vc init paramters
    - (void) registerInitParameters:(NSArray*) array ClassName:(NSString*)vcName
    {
        if(!s_vcInitParametersDic)
        {
            s_vcInitParametersDic = [NSMutableDictionary new];
        }
        
        [s_vcInitParametersDic setValue:array forKey:vcName];
    }
    
    - (void) registerVCWithClassName:(NSString*)vcName
    {
        [self registerInitParameters:@[[NSNull null]] ClassName:vcName];
       
    }
    - (void) registerVCInitWithCoder:(NSCoder *)aDecoder ClassName:(NSString*)vcName
    {
        [self registerInitParameters:@[aDecoder?aDecoder:[NSNull null],[NSNull null]] ClassName:vcName];
    }
    - (void) registerVCInitWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil ClassName:(NSString*)vcName
    {
        [self registerInitParameters:@[nibNameOrNil?nibNameOrNil:[NSNull null],nibBundleOrNil?nibBundleOrNil:[NSNull null],[NSNull null]] ClassName:vcName];
    }
    
    //presetn vc
    - (NSDictionary*) parseURIQueryString:(NSString*)query
    {
        NSMutableDictionary* param = [[NSMutableDictionary alloc] initWithCapacity:2];
        NSArray* array = [query componentsSeparatedByString:@"&"];
        for(NSString* ss in array)
        {
             NSArray* key = [ss componentsSeparatedByString:@"="];
            
            switch ([key count]) {
                case 1:
                    [param setValue:@"" forKey:[key objectAtIndex:0]];
                    break;
                case 2:
                    [param setValue:[key objectAtIndex:1] forKey:[key objectAtIndex:0]];
                    break;
                default:
                    break;
            }
        }
        return param;
    }
    - (UIViewController*) createViewController:(NSString*) key parameters:(NSDictionary*) paramters
    {
        UIViewController* vc = nil;
        Class vcClass = [vcDic objectForKey:key];
        
        if(vcClass)
        {
            if(_enablePresentOnSameVC && g_lastViewController && [g_lastViewController isKindOfClass:vcClass])
            {
                [self setParametersForVC:g_lastViewController paramters:paramters];  
            }
            else
            {
                vc  =  [[vcClass alloc] initByVCMgr];
                [self setParametersForVC:vc paramters:paramters];
            }
            
        }
        else
        {
             NSAssert(0, @"call error %@ or %@ not inhert from BaseViewController",key,key);
        }
        
        return  vc;
    }
    
    - (void) setParametersForVC:(UIViewController*)vc paramters:(NSDictionary*) paramters
    {   
        for (id  key in paramters) {
            
            @try {
                
                if(_delegate && [_delegate respondsToSelector:@selector(willSetParamter:key:value:)])
                {
                   if([_delegate willSetParamter:vc key:key value:[paramters valueForKey:key]])
                   {
                       [vc setValue:[paramters valueForKey:key] forKey:key];
                   }
                }
                
            }
            @catch (NSException *exception) {
                NSLog(@"param invalid %@",paramters);
    //            NSAssert(0, @"param invalid %@",paramters);
            }
            
        }
    }
    
    
    
    
    //- (void) presentViewController:(NSString*)key
    //{
    //    [self presentModalViewController:key paramters:nil];
    //}
    - (void) presentModalViewController:(NSURL*)url
    {
      if([_delegate willCreateVC:url ])
      {
          NSString* path = [[url pathComponents] lastObject];
          NSString* key = path?path:[url host];
          NSDictionary* parameters = [self parseURIQueryString:[url query]];
          UIViewController* vc = nil;
          
          if([_delegate respondsToSelector:@selector(creatViewController:paramters:)])
          {
              vc = [_delegate creatViewController:key paramters:parameters];
          }
          
          if(!vc)
              vc = [self createViewController:key parameters:parameters];
        
          if(vc && g_lastViewController)
          {
              UIViewController* onVC = g_lastViewController;
                                        
              if(onVC && [_delegate willPresentVC:onVC currentVC:vc url:url] && vc != onVC)
              {
                  if(onVC.navigationController)
                  {
                      [onVC.navigationController pushViewController:vc animated:YES];
                  }
                  else
                  {
                      //[vc setValue:@(YES) forKey:@"modalPresent"];
                      UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];                  
                      [onVC presentModalViewController:nav animated:YES];
                  }
              }
    
          }
      }
    
    }
    
    - (UIView*) topView
    {
        return [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
    }
    
    - (UIViewController*) topViewController
    {
        
        return g_lastViewController;    
    }
    
    - (void) addToDelay:(NSURL*)aurl
    {
        if(!_delayedUrlArray)
        {
            _delayedUrlArray = [NSMutableArray new];
        }
        
        for (NSURL* url in _delayedUrlArray) {
            if([[url absoluteString] isEqualToString:[aurl absoluteString]])
            {
                return;
            }
    
        }
        dispatchOpened = NO;
        [_delayedUrlArray addObject:aurl];
    }
    
    - (void) dispatchDelayedViewControllers
    {
        
        dispatchOpened = YES;
        [self dispatchDelayedViewController];
    }
    
    - (void) dispatchDelayedViewController
    {
        if ([_delayedUrlArray count])
        {
            NSURL * url = [_delayedUrlArray objectAtIndex:0];
            if([_delegate willDispatchDelayedUrl:url])
            {
                if ([_delayedUrlArray count] ) {
                    [_delayedUrlArray removeObject:url];
                    [self handleUrl:url];
                }
                
            }
        }
        
    }
    
    
    
    - (void) addViewControllerToDispatchQueue:(UIViewController*)vc
    {
        
    }
    
    #pragma mark -
    #pragma mark hooked method imp
    
    //define 
    
    #define Hooked_Orignal_Selector(_orgSelName) @selector(_vc_orignal_##_orgSelName)
    #define Hooked_Method(_name) _hooked_##_name
    
    
    #define Add_Method_To_Class(_class,_selName) do{    
        Method add_method = class_getInstanceMethod([self class], @selector(_selName)); 
        IMP    add_imp = method_getImplementation(add_method);      
        class_addMethod(_class, @selector(_selName), add_imp, method_getTypeEncoding(add_method));    
    }while(0)
    
    
    #define HOOK_OBJC_CLASS(_class,_orgSelName,_hookedSelName)  do{ 
        Method org_method = class_getInstanceMethod(_class, @selector(_orgSelName));  
        Method rep_method = class_getInstanceMethod([self class], @selector(_hookedSelName));  
        IMP    org_imp = method_getImplementation(org_method);      
        class_addMethod(_class, Hooked_Orignal_Selector(_orgSelName), org_imp, method_getTypeEncoding(org_method)); 
        IMP    rep_imp = method_getImplementation(rep_method); 
        class_replaceMethod(_class, @selector(_orgSelName), rep_imp, method_getTypeEncoding(org_method));   
    }while(0)
    
    
    #define Set_Instance_Var(_obj,_name,_value) objc_setAssociatedObject(_obj,"_append_"#_name,_value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    #define Get_Instance_Var(_obj,_name)        objc_getAssociatedObject(_obj,"_append_"#_name)
    
    #define REAL_SELF() UIViewController* realSelf = (UIViewController*)self
    
    
    - (void) installHook
    {
        
        @try {
            HOOK_OBJC_CLASS([UIViewController class],viewWillAppear:,Hooked_Method(viewDidAppearHooked:));
            HOOK_OBJC_CLASS([UIViewController class],viewDidAppear:,Hooked_Method(viewDidAppear:));
            HOOK_OBJC_CLASS([UIViewController class],presentModalViewController:animated:,Hooked_Method(presentModalViewController:animated:));
            
            Add_Method_To_Class([UIViewController class],initByVCMgr);
    //        Add_Method_To_Class([UIViewController class],_modalClose:);
    //        Add_Method_To_Class([UIViewController class],_addCloseBtn:);
    //        Add_Method_To_Class([UIViewController class],goBack);
    //        Add_Method_To_Class([UIViewController class],goHome);
            
            //class_addProperty need decalre in interface
            //class_addIvar cannot support for exist class 
    
        }
        @catch (NSException *exception) {
            NSLog(@"install hook occur exception");
        }
        @finally {
            
        }
       
        
    }
    
    
    
    //hooked method
    //note
    //self not viewcontrollermgr, is viewcontroller instance
    //
    
    -(id) initByVCMgr
    {
        REAL_SELF();
        NSArray * parameters = [s_vcInitParametersDic valueForKey:[NSString stringWithUTF8String:class_getName([self class])]];
        NSAssert(parameters, @"%@ initByVCMgr failed :init parameter error",self);
        
        id  bself = nil;
        switch ([parameters count]) {
            case 1:
                bself = [realSelf init];
                break;
            case 2:
                bself = [realSelf initWithCoder:[parameters objectAtIndex:0]==[NSNull null]?nil:[parameters objectAtIndex:0]];
                break;
            case 3:
                bself = [realSelf initWithNibName:[parameters objectAtIndex:0]==[NSNull null]?nil:[parameters objectAtIndex:0] bundle:[parameters objectAtIndex:1]==[NSNull null]?nil:[parameters objectAtIndex:1]];
                break;
            default:
                NSAssert(parameters, @"%@ initByVCMgr failed:too many paramter:%@",self,parameters);
                break;
        }
    
        if(bself)
        {
            Set_Instance_Var(self,presentByMgr, @(YES));
        }
        
        return bself;
    }
    
    - (void) Hooked_Method(viewWillAppear:(BOOL)animated)
    {
        [self performSelector:Hooked_Orignal_Selector(viewWillAppear:) withObject:@(animated)];
        if(!g_lastViewController)
        {
            g_lastViewController = (UIViewController*)self;
            [[ViewControllerMgr sharedInstance] performSelector:@selector(dispatchDelayedViewController)];
        }
    }
    
    - (void) Hooked_Method(viewDidAppearHooked:(BOOL)animated)
    {
        [self performSelector:Hooked_Orignal_Selector(viewDidAppear:) withObject:@(animated)];
        UIViewController* realSelf = (UIViewController*) self;
        CGRect frame = realSelf.view.frame;
        
        if(frame.origin.x == frame.origin.y && frame.origin.x == 0)
            g_lastViewController = realSelf;
        
        [[ViewControllerMgr sharedInstance] performSelector:@selector(dispatchDelayedViewController)];
    }
    
    
    - (void) Hooked_Method(presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated)
    {
        if([modalViewController isKindOfClass:[UINavigationController class]])
        {
            UINavigationController * nav = (UINavigationController*)modalViewController;
            
            if([nav.viewControllers count])
            {
                Set_Instance_Var([nav topViewController],modalPresent, @(YES));
            }
        }else
        {
             Set_Instance_Var(modalViewController,modalPresent, @(YES));
        }
        
        [self performSelector:Hooked_Orignal_Selector(presentModalViewController:animated:) withObject:modalViewController withObject:@(animated)];
    }
    
    
    @end
    





  • 相关阅读:
    工科物理实验()中国大学MOOC答案(已更新)
    类似jar文件使用java无法打开问题
    python9、10章
    nmap的理解与利用(初级)
    常见端口
    配置优化
    删除表操作
    万能的map
    测试
    Mapper.xml
  • 原文地址:https://www.cnblogs.com/riskyer/p/3328933.html
Copyright © 2020-2023  润新知