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

2万+

被折叠的 条评论
为什么被折叠?



