Tip:发现在真机运行中有触发handoff功能的案例,只需要在代理方法中适当返回NO即可。
关于iOS Universal Link 的资料不胜枚举,关于基础配置这里就不再详述。这里主要分享一下,解决其中一个坑位的过程...
之前在配置好通用连接后,觉得完事大吉。然而过了一段时间,产品同事来找茬咯~~~
话说,没想到通用链接也有失效这样一回事。万恶的苹果爸爸~~~
基于这个问题的描述如下:
iOS里面有个情况,打开APP的后在右上角形如:
xxx.com(面包屑导航)跳转到safari后,会导致Universal Link 跳转失效。
在认识这个问题的时候,首先需要考虑的是系统版本因素。发现在iOS11上通过通用链接启动APP后,右上角并没有发现面包屑导航。而在iOS10和iOS9 上会出现此问题,所以问题明朗了一点。
iOS11 下系统机制有所更改,所以本篇命题不会成立。
iOS10 以下,系统机制还不太成熟,这也是本篇命题存在的意义。
能够让产品大大乐此不疲的一定是,某某某家的APP怎么就没问题呢。所以我们不服气的研究了一下某某某家的APP。这里以两个具有代表性的为例。
eg:在微信中,跳转APP...
今日头条: 两颗星
表现:呼起APP后,点击右上角面包屑导航。会发现界面是向右侧跳转到Safari,这一点很像是使用 openURL 实现的效果。
网易: 一颗星
表现:呼起APP后,点击右上角面包屑导航。WTF!!! 不可点,这个解决方案就有点鸡贼了。
Universal Link:失效的表现,点击右上角面包屑导航会发现页面是向左侧pop到Safari。
向左走还是向右走,简直是人生难题。
对比以上的结论:
问题根源,面包屑导航打开的是配置好的通用链接。这会让系统误以为,我们以后都会使用Safari打开通用链接从而导致失效。所以解决问题的思路一定是要在,面包屑导航上做文章了。
能想到的方案如下:
获取采用从状态栏获取网络状态的类似方法,来获取面包屑导航的相关状态。从而问题的解决可以分化为两个方案。
1.在状态栏上,贴一层UIView 覆盖住面包屑导航。这样的好处是,iOS9--iOS11都可以获得一致的体验。难点是要在KeyWindow的最上层添加,否则容易破相。
2.获取面包屑导航的触发事件,使用运行时替换事件。主要目的是,为我们手动调用openURL 方法提供便利,并可以修改跳转链接为普通链接。
我这里采用了第二套方案,详细过程如下:
抓取面包屑导航:
UIApplication *application = [UIApplication sharedApplication];
NSArray* arrChilden;
arrChilden = [[[application valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
//查看subView 这个是没有面包屑导航时的情况
_subviewCache __NSArrayM * @"4 elements" 0x000060000065f6e0
[0] UIStatusBarServiceItemView * 0x7fa4eac8d310 0x00007fa4eac8d310
[1] UIStatusBarDataNetworkItemView * 0x7fa4ead01ec0 0x00007fa4ead01ec0
[2] UIStatusBarBatteryItemView * 0x7fa4ead1b070 0x00007fa4ead1b070
[3] UIStatusBarTimeItemView * 0x7fa4eae76ad0 0x00007fa4eae76ad0
//查看subView 这个是有面包屑导航时的情况
_subviewCache __NSArrayM * @"7 elements" 0x1562a850
[0] UIStatusBarBreadcrumbItemView * 0x16df8ff0
[1] UIStatusBarServiceItemView * 0x16875600
[2] UIStatusBarDataNetworkItemView * 0x16b73cd0
[3] UIStatusBarOpenInSafariItemView * 0x15556580
[4] UIStatusBarBatteryItemView * 0x16b594f0
[5] UIStatusBarBatteryPercentItemView * 0x169e0af0
[6] UIStatusBarTimeItemView * 0x16997bb0
其中 UIStatusBarBreadcrumbItemView 就是面包屑左导航
UIStatusBarOpenInSafariItemView 就是面包屑右导航
接下来深挖 UIStatusBarOpenInSafariItemView,一下就不详细说了。其中有一个事件是我们所关心的。
SEL: userDidActivateButton:
至此,入手点有了着落。
Final Result:
AppDelegate中修复方法如下:
///注意 - (void)applicationDidBecomeActive:(UIApplication*)application 方法中调用)
- (void)fixUniversalLink{
UIApplication *application = [UIApplication sharedApplication];
NSArray* arrChilden;
//是否是iPhoneX
if ([[application valueForKeyPath:@"statusBar"] isKindOfClass:NSClassFromString(@"UIStatusBar_Modern")]) {
arrChilden = [[[[application valueForKeyPath:@"statusBar"] valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
} else {
arrChilden = [[[application valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
}
for (id child in arrChilden) {
if ([child isKindOfClass:NSClassFromString(@"UIStatusBarOpenInSafariItemView")]) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class cls = [child class];
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wundeclared-selector"
//原方法
Method originalM = class_getInstanceMethod(cls, @selector(userDidActivateButton:));
#pragma clang diagnostic pop
//替换方法
Method exchangeM = class_getInstanceMethod([self class], @selector(myDidActivateButton:));
method_exchangeImplementations(originalM, exchangeM);
});
}
}
}
#pragma mark - 通用链接修复
- (void)myDidActivateButton:(UIButton*)btn{
NSLog(@"测试....");
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"http://www.baidu.com"]];
}