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


 




 

你可能感兴趣的:(页面跳转)