iOS應用間通信:URL Schemes
拋開越獄不談,URL Schemes幾乎是iOS應用間通信(Inter-app Communication)的唯一選擇(另一種是Air Drop,但主要用于共享大文件)逐工,其重要性毋庸置疑合搅。
更新:Apple在iOS9推出了Universal Links,同樣基于URL,力求統(tǒng)一原生應用和web服務的用戶體驗,可視為URL Schemes的全面升級。當然弧烤,其實現(xiàn)也更為復雜。
A. 什么是URL Schemes
URL用于定位資源蹬敲,譬如網(wǎng)絡資源暇昂。以下面的URL為例:
http://www.example.com/index.php?key1=value1&key2=value2
根據(jù)RFC1808標準莺戒,其包含如下組成部分:
內(nèi)容 | 角色 | 作用 |
---|---|---|
http | scheme | 服務類型。注意急波,http是一種互聯(lián)網(wǎng)協(xié)議从铲,但理論上任意合法字符串都可以充當scheme |
www.example.com | host | 主機域名 |
index.php | path | 資源路徑 |
key1=value1&key2=value2 | query | 參數(shù) |
iOS中,你可以為自己的應用定義URL schemes幔崖,供外界調(diào)用食店。URL格式必須符合標準(即能夠通過NSURL解析)。
總體來說赏寇,URL schemes可劃分為兩類:系統(tǒng)定義&自定義吉嫩。
B. 系統(tǒng)定義的URL Schemes
有些系統(tǒng)應用天生支持URL schemes,例如電話嗅定,郵件自娩,短信,Safari渠退,地圖等忙迁。
/ | scheme | 范例 | 效果 | 備注 |
---|---|---|---|---|
電話 | tel | tel:16812345678 | 撥打號碼16812345678 | 電話號碼必傳 |
郵件 | mailto | mailto:frank@163.com | 給frank@163.com寫郵件 | 郵件地址必傳 |
短信 | sms | sms:16812345678 | 編寫發(fā)送給號碼16812345678的短信 | 電話號碼不是必傳,如不傳碎乃,則僅打開短信應用 |
Safari | http(s) | https://www.baidu.com | 在Safari中打開網(wǎng)頁 | 絕大部分http地址都默認使用Safari打開 |
地圖 | http(s) | http://maps.apple.com/?q=四川菜 | 搜索附近的四川菜姊扔。注意,url含有中文時要編碼 | 地圖的scheme并不是map梅誓,而是一個host為maps.apple.com 的http地址 |
更多關(guān)于系統(tǒng)定義的URL schemes的信息恰梢,詳見官方文檔Apple URL Scheme Reference。
C. 調(diào)用URL Scheme
調(diào)用URL scheme其實很簡單梗掰,分為兩步:
- 創(chuàng)建URL嵌言;
- 要求UIApplication打開它;
注意事項:
- 調(diào)用特定app及穗,必須事先知道其scheme摧茴;
- 除scheme外,有些app還要求傳遞額外信息埂陆;信息錯誤苛白,可能無法達到預期效果;
- 自定義schemes與系統(tǒng)schemes發(fā)生沖突焚虱,默認以后者為準丸氛;
- 多個app注冊同一個scheme,調(diào)用結(jié)果未知著摔;
打開URL的方法如下:
- (void)openURL:(NSURL *)URL completionHandler:(void (^)(BOOL success))completionHandler;
- 此方法自iOS10引入,低版本請使用openURL:定续;
- 回調(diào)completionHandler攜帶一個布爾參數(shù)success谍咆,表示是否成功打開URL禾锤。注意,這里的成功意味著有app響應URL scheme摹察,從而被調(diào)起恩掷;至于URL是否被成功處理,不得而知供嚎;
- 也就是說黄娘,只要scheme正確,一定會有app被調(diào)起克滴,回調(diào)一定顯示成功逼争;
我們可以嘗試通過Safari調(diào)用某個scheme,具體做法為:在地址欄里輸入targetScheme://劝赔,將targetScheme替換為具體scheme即可誓焦。注意,://不可省略着帽;如果包含中文杂伟,必須編碼。
D. 自定義URL Schemes
自定義URL schemes也可以分為兩步:
- 注冊schemes仍翰;
- 處理調(diào)用請求赫粥。
D.1 注冊schemes
iOS以URL type為單位管理URL schemes。一個type下可以有多個scheme予借,但一個scheme只對應一個type越平。注冊URL schemes,實際上是注冊URL type蕾羊。
在Info.plist
中添加鍵值對CFBundleURLTypes
喧笔,其對應一個數(shù)組,每個元素都是一個字典龟再,代表一個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 | 字符串數(shù)組,一個字符串代表一個scheme | 是 | 一個type下可以有多個scheme |
CFBundleURLName | type的識別符利凑,必須唯一浆劲。推介使用反向DNS風格的命名方式,如com.myhost.myscheme哀澈。 | 是 | 具體作用不詳 |
CFBundleURLIconFile | type的圖標名稱 | 否 | 圖標用途不詳 |
CFBundleTypeRole | app在type中所扮演的角色 | 是 | 具體作用不詳牌借,使用默認值即可 |
更多關(guān)于CFBundleURLTypes的信息,詳見Information Property List Key Reference中章節(jié)CFBundleURLTypes的敘述割按。
此外膨报,還可以針對scheme定義啟動圖片。眾所周知,app啟動時會顯示圖片现柠。如果app因為響應某個scheme而啟動院领,可以根據(jù)scheme定義圖片。圖片命名格式如下:
<basename> -<url_scheme> <other_modifiers> .png
更多關(guān)于URL scheme啟動圖片的信息够吩,詳見App Programming Guide for iOS中章節(jié)Displaying a Custom Launch Image When a URL is Opened的敘述比然。
D.2 處理調(diào)用請求
D.2.1 處理邏輯
收到調(diào)用請求后,相應的UIApplication代理方法會被調(diào)用周循,所以這里也是處理邏輯的所在:
// UIApplicationDelegate
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
注意事項:
- 此方法自iOS9引入强法,低版本請使用application:openURL:sourceApplication:annotation:
; - url是調(diào)用者傳入的url湾笛,利用NSURL解析饮怯,獲取所需信息;
- options是字典迄本,通過鍵值對UIApplicationOpenURLOptionsSourceApplicationKey可以獲取調(diào)用者的Bundle ID硕淑;
- 此方法返回一個布爾值,代表處理成功與否嘉赎;但不影響調(diào)用者的回調(diào)結(jié)果(方法
openURL:completionHandler:
)置媳。所以這個值的具體作用不詳。
D.2.2 生命周期
被調(diào)用時公条,app可能處于下列狀態(tài)之一:
- app未運行拇囊;
- app運行中,但在后臺或被掛起靶橱;
D.2.2.1 app未運行時被調(diào)用
app先啟動寥袭,再處理請求,但受到下面方法影響:
// UIApplicationDelegate
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- 如果任意方法返回NO关霸,則不處理請求(即方法
application:openURL:options:
不調(diào)用)传黄; - 如果只實現(xiàn)其中一個,則以實現(xiàn)的那個為準队寇;
- 即使不處理請求膘掰,app仍會啟動,進入前臺佳遣;調(diào)用者收到成功回調(diào)(方法
openURL:completionHandler:
回調(diào)參數(shù)顯示成功)识埋;
D.2.2.1 app運行中被調(diào)用
app必定
會處理請求,進入前臺(即方法application:openURL:options:
一定會被調(diào)用)零渐;
E. LSApplicationQueriesSchemes與canOpenURL:
UIApplication方法canOpenURL:可以判斷當前設(shè)備上是否有能夠響應特定URL的應用窒舟。
于是乎,有人利用這個方法過濾大量scheme诵盼,判斷設(shè)備上安裝了哪些應用惠豺。為防止濫用银还,自iOS9,Apple要求這個方法只能檢測特定名單內(nèi)的scheme(當然洁墙,系統(tǒng)定義的scheme不在此列)见剩,開發(fā)者需要通過鍵值對LSApplicationQueriesSchemes在Info.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:
的返回值僅表示當前設(shè)備上是否有能夠響應特定URL的應用。并不能反映URL能否被成功處理固翰; - 方法
openURL:completionHandler:
(或openURL:
)不受此名單限制狼纬;
更多關(guān)于LSApplicationQueriesSchemes的信息,詳見Information Property List Key Reference中章節(jié)LSApplicationQueriesSchemes的敘述骂际。