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:[email protected] [email protected]写邮件 邮件地址必传
短信 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。例如:

CFBundleURLTypes

    
        CFBundleTypeRole
        Editor
        CFBundleURLIconFile
        iconGinx
        CFBundleURLName
        cn.com.rap.ginx
        CFBundleURLSchemes
        
            wb2522720237
            wxd3a1541d4423bf8f
            ddyc
            tencent1101352712
            navigationMapBack
        
    
    

一个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定义图片。图片命名格式如下:

 -  .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 *)options

注意事项:

  • 此方法自iOS9引入,低版本请使用application:openURL:sourceApplication:annotation:
  • url是调用者传入的url,利用NSURL解析,获取所需信息;
  • options是字典,通过键值对UIApplicationOpenURLOptionsSourceApplicationKey可以获取调用者的Bundle ID;
  • 此方法返回一个布尔值,代表处理成功与否;但不影响调用者的回调结果(方法openURL:completionHandler:)。所以这个值的具体作用不详。

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不在此列),开发者需要通过键值对LSApplicationQueriesSchemes在Info.plist中定义这个名单。例如:

LSApplicationQueriesSchemes

    alipay
    tencentweibo
    sinaweibo
    weibo
    mqq
    iosamap
    baidumap
    wechat
    weixin
    sinaweibohd
    weibosdk
    weibosdk2.5
    BestPay

另外,还要注意:

  • 方法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 使用详解

你可能感兴趣的:(iOS应用间通信:URL Schemes)