iOS - 关于对App跳转方法的hook

文章目录

App的跳转方法

实现app跳转有urlscheme以及universal Link(deep link) 跳转。

  • url scheme
    application:openURL:options:是最新的方法,其他两个都废弃了
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
    return NO;
}

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    return NO;
}

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    return NO;
}
// universal Link执行
- (BOOL) application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
  restorationHandler:(void (^)(NSArray<id <UIUserActivityRestoring>> *_Nullable))restorationHandler 

当我们需要进行hook时,只需要获取到appDelegate的示例,这个示例在 UIApplicationMain 之后就能够以 [UIApplication sharedApplication].delegate 来获取。

然后进行方法交换。

hook

相关的示例代码如下:

//url scheme 跳转
        if ([delegate respondsToSelector:@selector(application:openURL:options:)]) {
            SEL sel = @selector(application:openURL:options:);
            Method method = class_getInstanceMethod(delegate.class,sel);
            IMP originImp = method_getImplementation(method);
            method_setImplementation(method, imp_implementationWithBlock(^(id target,UIApplication *application,NSURL *url,NSDictionary<UIApplicationOpenURLOptionsKey, id> * options) {
                //处理url
                BOOL (*tempImp)(id obj, SEL sel,UIApplication *application,NSURL *url,NSDictionary<UIApplicationOpenURLOptionsKey, id> * options) = (void*)originImp;
                return tempImp(target,sel,application,url,options);
            }));
        }else if ([delegate respondsToSelector:@selector(application:openURL:sourceApplication:annotation:)]) {
            SEL sel = @selector(application:openURL:sourceApplication:annotation:);
            Method method = class_getInstanceMethod(delegate.class,sel);
            IMP originImp = method_getImplementation(method);
            method_setImplementation(method, imp_implementationWithBlock(^(id target,UIApplication *application,NSURL *url,NSString* sourceApplication,id annotation) {
                //处理url
                BOOL (*tempImp)(id obj, SEL sel,UIApplication *application,NSURL *url,NSString* sourceApplication,id annotation) = (void*)originImp;
                return tempImp(target,sel,application,url,sourceApplication,annotation);
            }));
        } else if ([delegate respondsToSelector:@selector(application:handleOpenURL:)]) {
            SEL sel = @selector(application:handleOpenURL:);
            Method method = class_getInstanceMethod(delegate.class,sel);
            IMP originImp = method_getImplementation(method);
            method_setImplementation(method, imp_implementationWithBlock(^(id target,UIApplication *application,NSURL *url) {
                //处理url
                BOOL (*tempImp)(id obj, SEL sel,UIApplication *application,NSURL *url) = (void*)originImp;
                return tempImp(target,sel,application,url);
            }));
        } else {
            @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"请在%@实例中实现application:openURL:options:以适配UrlScheme跳转",NSStringFromClass(delegate.class)] userInfo:nil];
            //no more anyone imp exist
            // TODO:add method: application:openURL:options:
            // 时序在UIApplicationMain之后,无法干预urlscheme跳转问题
        }
        
        //deeplink
        if ([delegate respondsToSelector:@selector(application:continueUserActivity:restorationHandler:)]) {
            SEL sel = @selector(application:continueUserActivity:restorationHandler:);
            Method method = class_getInstanceMethod(delegate.class,sel);
            IMP originImp = method_getImplementation(method);
            method_setImplementation(method, imp_implementationWithBlock(^(id target,UIApplication *application,NSUserActivity *userActivity,void (^restorationHandler)(NSArray<id <UIUserActivityRestoring>> *)) {
                //处理url
                BOOL (*tempImp)(id obj, SEL sel,UIApplication *application,NSUserActivity *userActivity,void (^restorationHandler)(NSArray<id <UIUserActivityRestoring>> *)) = (void*)originImp;
                return tempImp(target,sel,application,userActivity,restorationHandler);
            }));
        } else {
            @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"请在%@实例中实现application:continueUserActivity:restorationHandler:以适配DeepLink跳转",NSStringFromClass(delegate.class)] userInfo:nil];
        }

当appdelegate中,一个跳转代理都没有实现时,我们考虑的首先是使用runtime进行添加,但是遗憾的是在UIApplicationMain中就已经做好了urlscheme跳转的处理,即辨别是否能够响应跳转,存储状态,之后不再检测,所以之后使用runtime添加方法实现也无济于事。

所以方案只能用户手动实现代理方法中的一个,或者在UIApplicationMain之前就使用runtime进行添加方法实现,例如+load方法中,再着,hook main文件中的 UIApplicationMain ,获取传入的 appdelegate 类型 class 字符串,再使用 runtime 提前加入方法实现也可以。

对于iOS 13以上的处理,需要处理UIScene的跳转方法
可以参考我们SDK中的处理:https://github.com/growingio/growingio-sdk-ios-autotracker

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值