iOS应用间通信:URL Schemes

iOS应用间通信:URL Schemes

抛开越狱不谈,URL Schemes几乎是iOS应用间通信(Inter-app Communication)的唯一选择(另一种是Air Drop,但主要用于共享大文件),其重要性毋庸置疑。

更新:Apple在iOS9推出了Universal Links,同样基于URL,力求统一原生应用和web服务的用户体验,可视为URL Schemes的全面升级。当然,其实现也更为复杂。

A. 什么是URL Schemes

URL用于定位资源,譬如网络资源。以下面的URL为例:

http://www.example.com/index.php?key1=value1&key2=value2

根据RFC1808标准,其包含如下组成部分:

内容 角色 作用
http scheme 服务类型。注意,http是一种互联网协议,但理论上任意合法字符串都可以充当scheme
www.example.com host 主机域名
index.php path 资源路径
key1=value1&key2=value2 query 参数

iOS中,你可以为自己的应用定义URL schemes,供外界调用。URL格式必须符合标准(即能够通过NSURL解析)。

总体来说,URL schemes可划分为两类:系统定义&自定义。

B. 系统定义的URL Schemes

有些系统应用天生支持URL schemes,例如电话,邮件,短信,Safari,地图等。

/ scheme 范例 效果 备注
电话 tel tel:16812345678 拨打号码16812345678 电话号码必传
邮件 mailto mailto:frank@163.com frank@163.com写邮件 邮件地址必传
短信 sms sms:16812345678 编写发送给号码16812345678的短信 电话号码不是必传,如不传,则仅打开短信应用
Safari http(s) https://www.baidu.com 在Safari中打开网页 绝大部分http地址都默认使用Safari打开
地图 http(s) http://maps.apple.com/?q=四川菜 搜索附近的四川菜。注意,url含有中文时要编码 地图的scheme并不是map,而是一个host为maps.apple.com的http地址

更多关于系统定义的URL schemes的信息,详见官方文档Apple URL Scheme Reference

C. 调用URL Scheme

调用URL scheme其实很简单,分为两步:

  1. 创建URL;
  2. 要求UIApplication打开它;

注意事项:

  • 调用特定app,必须事先知道其scheme;
  • 除scheme外,有些app还要求传递额外信息;信息错误,可能无法达到预期效果;
  • 自定义schemes与系统schemes发生冲突,默认以后者为准;
  • 多个app注册同一个scheme,调用结果未知;

打开URL的方法如下:

- (void)openURL:(NSURL *)URL completionHandler:(void (^)(BOOL success))completionHandler;
  • 此方法自iOS10引入,低版本请使用openURL:
  • 回调completionHandler携带一个布尔参数success,表示是否成功打开URL。注意,这里的成功意味着有app响应URL scheme,从而被调起;至于URL是否被成功处理,不得而知;
  • 也就是说,只要scheme正确,一定会有app被调起,回调一定显示成功;

我们可以尝试通过Safari调用某个scheme,具体做法为:在地址栏里输入targetScheme://,将targetScheme替换为具体scheme即可。注意,://不可省略;如果包含中文,必须编码。

D. 自定义URL Schemes

自定义URL schemes也可以分为两步:

  1. 注册schemes;
  2. 处理调用请求。

D.1 注册schemes

iOS以URL type为单位管理URL schemes。一个type下可以有多个scheme,但一个scheme只对应一个type。注册URL schemes,实际上是注册URL type。

Info.plist中添加键值对CFBundleURLTypes,其对应一个数组,每个元素都是一个字典,代表一个type。例如:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLIconFile</key>
        <string>iconGinx</string>
        <key>CFBundleURLName</key>
        <string>cn.com.rap.ginx</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>wb2522720237</string>
            <string>wxd3a1541d4423bf8f</string>
            <string>ddyc</string>
            <string>tencent1101352712</string>
            <string>navigationMapBack</string>
        </array>
    </dict>
    <!--其他URL type...-->
<array>

一个URL type字典包含如下键值对:

必填 备注
CFBundleURLSchemes 字符串数组,一个字符串代表一个scheme 一个type下可以有多个scheme
CFBundleURLName type的识别符,必须唯一。推介使用反向DNS风格的命名方式,如com.myhost.myscheme。 具体作用不详
CFBundleURLIconFile type的图标名称 图标用途不详
CFBundleTypeRole app在type中所扮演的角色 具体作用不详,使用默认值即可

更多关于CFBundleURLTypes的信息,详见Information Property List Key Reference中章节CFBundleURLTypes的叙述。

此外,还可以针对scheme定义启动图片。众所周知,app启动时会显示图片。如果app因为响应某个scheme而启动,可以根据scheme定义图片。图片命名格式如下:

<basename> -<url_scheme> <other_modifiers> .png

更多关于URL scheme启动图片的信息,详见App Programming Guide for iOS中章节Displaying a Custom Launch Image When a URL is Opened的叙述。

D.2 处理调用请求

D.2.1 处理逻辑

收到调用请求后,相应的UIApplication代理方法会被调用,所以这里也是处理逻辑的所在:

// UIApplicationDelegate
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options

注意事项:

D.2.2 生命周期

被调用时,app可能处于下列状态之一:

  1. app未运行;
  2. app运行中,但在后台或被挂起;

D.2.2.1 app未运行时被调用

app先启动,再处理请求,但受到下面方法影响:

// UIApplicationDelegate
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
  • 如果任意方法返回NO,则不处理请求(即方法application:openURL:options:不调用);
  • 如果只实现其中一个,则以实现的那个为准;
  • 即使不处理请求,app仍会启动,进入前台;调用者收到成功回调(方法openURL:completionHandler:回调参数显示成功);

D.2.2.1 app运行中被调用

app必定会处理请求,进入前台(即方法application:openURL:options:一定会被调用);

E. LSApplicationQueriesSchemes与canOpenURL:

UIApplication方法canOpenURL:可以判断当前设备上是否有能够响应特定URL的应用。

于是乎,有人利用这个方法过滤大量scheme,判断设备上安装了哪些应用。为防止滥用,自iOS9,Apple要求这个方法只能检测特定名单内的scheme(当然,系统定义的scheme不在此列),开发者需要通过键值对LSApplicationQueriesSchemesInfo.plist中定义这个名单。例如:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>alipay</string>
    <string>tencentweibo</string>
    <string>sinaweibo</string>
    <string>weibo</string>
    <string>mqq</string>
    <string>iosamap</string>
    <string>baidumap</string>
    <string>wechat</string>
    <string>weixin</string>
    <string>sinaweibohd</string>
    <string>weibosdk</string>
    <string>weibosdk2.5</string>
    <string>BestPay</string>
</array>

另外,还要注意:

  • 方法canOpenURL:的返回值仅表示当前设备上是否有能够响应特定URL的应用。并不能反映URL能否被成功处理;
  • 方法openURL:completionHandler:(或openURL:)不受此名单限制;

更多关于LSApplicationQueriesSchemes的信息,详见Information Property List Key Reference中章节LSApplicationQueriesSchemes的叙述。

参考资料

  1. App Programming Guide for iOS
  2. Apple URL Scheme Reference
  3. Information Property List Key Reference
  4. URL Schemes 使用详解
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容