前言
最近正好在整治外投拉端拉下载的事,借这个机会整理了一下 URL SCHEME 唤端的应用和原理。本文主要会从手机系统层面、APP容器层面去讲解 URL SCHEME 的工作原理,比如在浏览器中输入一个scheme后为什么能够打开一个APP,中间到底发生了什么。本文主要涉及的知识点:
- url scheme 的组成结构
- app 如何注册 scheme 信息
- 对于一些不知名app,怎么去获取它的scheme信息
- 如何通过scheme打开一个app
- 为什么在有些平台scheme会被拦截
诞生背景
一般来说,我们的手机上会有很多的个人信息,比如联系人、银行卡、个人照片等,如果任何一个安装的应用都可以随意获取这些信息,就会造成严重的隐私泄漏。为了解决这个问题,苹果官方提出了一个叫做沙盒机制的方案,就是所有的应用只能去访问系统声明可访问的资源,这样就避免了用户隐私的泄漏,但是这个机制在保护用户隐私的同时,也阻断了多个应用间的信息共享和消息通信的能力。比如你想将一些事件添加到日历里,或者你想打开某个其他的app,就变得非常困难,于是就有了url scheme 的解决方案。起初url scheme只针对一些内置应用开放,比如日历、短信、邮件,后来才逐渐演变成了所有app都可以进行scheme注册和访问。
URL SCHEME 组成结构
一个完整的 url scheme 格式如下,它主要由四个部分组成,前面的 app 就是应用的一个 scheme 标识,比如淘宝的标识为 taobao,微信的标识为 weixin,后面的item就是打开应用后需要访问的路由,再后面就是一系列参数的key值和value值,其中scheme部分将被系统识别并完成app打开行为,后面的参数将由app自身完成解析和处理。
# {scheme}://{action}?{parameter}={value}&{parameter}={value}...
app://item?id=${itemId}&ut_sk=${utSk}&spm=widle.12011849.1.1
如何注册一个 SCHEME
scheme 的注册非常随意,以IOS为例,安装包中有一个标准的配置文件,文件名叫 info.plist,在应用被安装的时候会进行 scheme 的注册,注册的格式如截图所示,它的关键字叫 CFBundleURLSchemes,下面是具体的value值,这个截图是微信真实的配置文件,从这个文件里面可以看出,我们可以通过weixin://唤起微信客户端,也可以通过wechat://去唤起客户端,甚至可以通过QQ41C152CF去唤起客户端,比如浏览器输入QQ41C152CF://,就可以打开微信客户端。
如何查找其他APP的scheme
对于一些比较知名的app,比如微信微博淘宝,可以直接通过搜索就可以找到,但是对于一些小众的app,比如火山小视频、积目盒子等,可能就很难搜索到了,这个时候就只能自己去拆包。下面是详细的拆包教程:
-
需要安装一个应用助手,我使用的是爱思助手,在应用助手中搜索微信并下载
-
找到下载的文件,一般是ipa文件,右键进行解压
-
解压完成后我们找到payload里面的WeChat包,右键点击显示包内容
-
找到info.plist 文件,在编辑器中打开,然后搜索 CFBundleURLSchemes 就可以看到该APP所有的scheme信息了。
如何打开一个 APP
对于前端来说,唤端其实很容易,只需要通过 location.href 完成唤端跳转即可,如果跳转无反应,大概率是被拦截了
# 跳转微信
location.href = 'weixin://'
更底层的,ios系统提供了一个openURL的系统方法,可以用来打开一个链接,如果链接头是某app的scheme,就会打开对应的app,ios示例代码如下,如果你的唤端scheme在app的跳转白名单内,就会通过openURL完成跳转逻辑
# 创建一个url对象
NSURL *url = [NSURL URLWithString:@"weixin://"];
# 调用openURL打开url
[[UIApplication sharedApplication] openURL:url];
scheme被拦截
出于安全考虑或者出于商业目的,大部分app都会管控跳转白名单,比如微信就禁止跳转淘宝,如果你尝试在页面内访问 taobao:// ,是不会有任何反应的。这里的拦截逻辑通常出现在webview层面,当页面发起一次地址请求时,会触发webview的重新加载事件,而客户端就可以监听此次事件并决定是否要执行,以ios为例,通过shouldStartLoadWithRequest可以完成监听和拦截,如果返回YES,就表示允许本次加载,如果返回NO,则表示阻止本次加载,在这个方法中,客户端可以请求服务端校验地址是否在白名单内并决定是否要继续加载。
# YES表示允许加载url
# NO表示阻止加载url
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (特殊schema && 校验成功) {
# 打开第三方APP
return NO;
} else if (url校验成功) {
return YES;
} else{
return NO;
}
}
完整链路
当H5发起scheme跳转时,会触发webview的重新加载事件,此事件会被客户端劫持并进行白名单校验,如果通过则调用系统方法openURL完成app跳转(前提是该scheme被其他app注册过)
url scheme的缺陷
虽然url scheme是目前应用最广的唤端方案,但是它仍然存在很多的局限性。
- 无法判断是否唤起成功,虽然app可以通过canOpenURL来判断能否打开,但是数量有限,且只适用于ios,大部分场景下仍然不能正常判断。h5常见的应对方案是监听页面离开事件,比如2s内离开的认为跳转成功,2s后还停留在页面的认为跳转失败,可以进行一些下载引导。
- 用户流失率高,因为很多的app或者浏览器都会有一个弹窗来二次确认是否需要打开某某app,在这一步会有很高的用户流失率。
- 很容易被商业屏蔽,因为url scheme很容易就能被拦截,出于商业原因,很多平台都会限制跳转其他app。
url scheme的不安全性
url scheme其实是非常非常不安全的,因为苹果官方没有限制app定义的scheme名称,也就是说,任何一个app,都可以注册一个叫taobao的scheme,而且,苹果的原则是后来先上,就是越晚注册的app,优先被唤起,所以如果有恶意app进行scheme劫持,就会很容易出现钓鱼现象,比如模仿一个淘宝商城然后骗取用户资金。
那么要怎么样去防护呢?其实并没有很好的防护方式,因为scheme没有版权一说,谁都可以进行注册,但是可以在用户访问app的时候给自己发送一条消息,比如打开淘宝后向taobao://发起调用,如果能正常接收到信息就表示没有被劫持,如果没有收到就代表scheme已经被恶意劫持了,此时可以友善地提醒用户卸载冲突的app。