我對“是否安裝某App”問題的第一反應是,調用系統UIApplication對象的實例方法canOpenURL:來判斷,一般在自己得出習慣性的思維答案后,就覺得滿足,所以今天得一反常態,重新認識一下這個功能需求背后到底隱藏了哪些不曾為我所知的秘?秘密秘?在里面
一、為啥要判斷系統是否安裝了這個App?(為什么)
總的來說,就是為了提升用戶體驗
,摒除額外操作造成的時間浪費
。
結合目前自己做過的項目我覺得這個需求點的應用場景有如下幾個:
- 公司內的 App 產品數多于2個,并且業務間有聯系,各自的App信息界面有共享功能,如:
A 中有商家店鋪的
基本信息
,但不具備修改功能
B 中則有商家的店鋪詳細信息
,且具有可修改功能
那么使用A app 的商家,如需更改其店鋪信息則需要切換到 B app 上執行相關動作。
- 公司為導流業務,維護一些馬甲App,需從馬甲 App 跳到 或 推薦安裝自己的主運營 App 上。
- 調用系統App,如:短息,Email,通訊錄,iTunes...等相關情況。
二、用到了哪些API?(是什么)
就從我的第一反應源(canOpenURL:)入手吧。
- (BOOL)canOpenURL:(NSURL *)url NS_AVAILABLE_IOS(3_0);`
沒有更詳細信息,那去https://developer.apple.com查查canopenurl:,看有無新發現。
映入眼簾的描述啊:
Returns a Boolean value indicating whether or not the URL’s scheme can be handled by some app installed on the device.
大概意思是:
判斷該方法傳入的URL’s scheme參數是否能夠被已安裝在此設備上的一些App處理。
那 URL'scheme
是啥呢?
同樣我們順便看看 Discussion 部分吧,因為一般注意事項都會羅列這個 section,不看就虧了不是嗎:
- URL Scheme是類似 http://,ftp://,afp:// 這樣的東西,通常是用傳輸協議作為URL Scheme。
- 不過事實上,你可以在iOS注冊任何類型的URL Scheme。當用戶通過系統 API 訪問你的自定義URL Scheme的鏈接的時候,操作系統就會打開你的程序,響應這個請求。
注意點大概有:
- 當該方法返的結果是 YES 的話,iOS 會保證之后通過調用相同 URL 參數的
openURL:
方法成功啟動的 App 一定能夠處理該 URL 參數 -
canOpenURL:
方法返回的結果不代表URL 的正確性
或者URL 描述的資源存在性
Important:
- 如果 App 的 version >= iOS 9.0, 則必須先聲明作為參數傳入canOpenURL:方法的 URL schemes;
- 通過在 app 的 Info.plist 文件上添加LSApplicationQueriesSchemes key對 URL 聲明 ;
- 如果未執行先聲明動作,而調用canOpenURL:時則會一直返回 FALSE;無論是否有已安裝且可處理該 URL 的 App 在本設備上
- 如果你的 app linked 的版本低于 iOS9.0,卻運行在 iOS9.0或以上的話,那你只能正確調用canOpenURL:方法50次,超過次數之后的調用會一直返回 NO; 除非用戶重新安裝或升級App,則會重置該限制,
-
openURL:
與canOpenURL:
不同的是,openURL:
方法不受LSApplicationQueriesSchemes 要求限制,即不管你有無先聲明該 URL schemes 在 Info.plist 的 LSApplicationQueriesSchemes內,只要有 app 能夠打開該 URL 即有效;
如下是openURL:
(iOS 2 ~ 10可用)方法聲明:
- (BOOL)openURL:(NSURL*)url NS_DEPRECATED_IOS(2_0, 10_0, "Please use openURL:options:completionHandler: instead")NS_EXTENSION_UNAVAILABLE_IOS("");
如下是 openURL:options:completionHandler:
(iOS 10+可用)方法聲明
// Options are specified in the section below for openURL options. An empty options dictionary will result in the same
// behavior as the older openURL call, aside from the fact that this is asynchronous and calls the completion handler rather
// than returning a result.
// The completion handler is called on the main queue.
- (void)openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion NS_AVAILABLE_IOS(10_0) NS_EXTENSION_UNAVAILABLE_IOS("");
既然出現自己不熟悉的LSApplicationQueriesSchemes key,今天就要一窺到底!
說的是:
- 這個 key 用于 iOS 9.0 and later;
- 該key對應的類型為數組,用于存放通過 canOpenURL:方法( UIApplication類的實例方法)判斷的能否跳轉的 URL Schemes;(此描述不太恰當,詳細情況文檔)
同樣還有一個我們之前就一直在用的與跳轉白名單相關概念 CFBundleURLTypes key
截個圖讓大家與我一起復習一下吧:
CFBundleURLTypes key
三、怎么去執行以上步驟(配置 LSApplicationQueriesSchemes 與 CFBundleURLTypes)?(怎么做)
1、配置LSApplicationQueriesSchemes 。
聲明:
“1、配置LSApplicationQueriesSchemes (添加Scheme白名單)。”摘自《mob的適配 ios - 9 必讀》
問題描述:在iOS 9下涉及到平臺客戶端跳轉,系統會自動到項目info.plist下檢測是否設置平臺Scheme。對于需要配置的平臺,如果沒有配置,就無法正常跳轉平臺客戶端。因此要支持客戶端的分享和授權等,需要配置Scheme名單。
具體方法:
1)、在項目的info.plist中添加一LSApplicationQueriesSchemes,類型為Array。
2)、然后給它添加一個需要支持的項目,類型為字符串類型;
必看注意
1.在iOS9中,如果沒有添加上述白名單,系統會打印類似如下提示:.-canOpenURL: failed for URL: “sinaweibohdsso://xxx” – error: “This app is not allowed to query for scheme sinaweibohdsso”(如下圖)如沒有添加相關白名單,有可能導致分享失敗,例如不會跳轉微信,不會跳轉****QQ****等。
2.添加完上述所需的名單,系統依然會打印類似信息:.-canOpenURL: failed for URL: “sinaweibohdsso://xxx” – error: “null”這是系統打印的信息,目前是無法阻止其打印,即無法消除的
添加完后,系統是依然會打印的,不過error會變成null:
2、配置CFBundleURLTypes 。(估計這個你也做過好多遍了吧??)
- 設置URL Schemes (在需要跳轉的APP中設置自己的Scheme)
圖片引《自判斷iOS設備上是否安裝某個應用以及應用跳轉》
圖片引《自判斷iOS設備上是否安裝某個應用以及應用跳轉》 - 接上配置LSApplicationQueriesSchemes的配置圖(因為如果在 iOS 9+ 環境下調用 canOpenURL:方法需要同時配置LSApplicationQueriesSchemes )
圖片引《自判斷iOS設備上是否安裝某個應用以及應用跳轉》
四、應用間跳轉
-
在 One App 中注冊設置需要跳轉的URL Scheme
設置URL Types -
可以在Safari 中測試該 URL Scheme 是否能被跳轉
Safari中測試URLScheme.gif
注意:APP URL格式為: URL Scheme://urlidentifier,直接調用URL Scheme也可打開程序, url identifier是可選的。
-
在Two App 中的 info Plist 中添加白名單 URL Scheme
Two App 中的 info Plist 中添加白名單 Url 在 Two App 中添加跳轉到One App代碼
- (IBAction)jumpToOneApp:(id)sender {
NSString *urlscheme = @"oneapp://";
[self checkIfInstalledAppWithUrlSchemes:urlscheme];
}
#pragma mark - 判斷是否安裝了APP 如安裝則跳轉到對應 App
- (void)checkIfInstalledAppWithUrlSchemes:(NSString *)urlScheme {
NSURL *URL = [NSURL URLWithString:urlScheme];
UIApplication *application = [UIApplication sharedApplication];
/*
// 方式一 :
// 判斷是否安裝了APP
if ([application canOpenURL:URL]) {
NSLog(@"已經安裝,并且可以打開");
if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
// iOS10及以上判斷方式
[application openURL:URL options:@{} completionHandler:^(BOOL success) {
NSLog(@"iOS10及以上Open %@: 是否成功%d",urlScheme,success);
if (!success) {
// 沒有成功
NSLog(@"iOS10 進入app失敗");
}
}];
} else {
BOOL success = [application openURL:URL];
NSLog(@"Open %@: %d",urlScheme,success);
if (!success) {
// 沒有成功
NSLog(@"進入app失敗");
}
}
} else {
NSLog(@"不能打開");
}
*/
// 方式二:
// 直接進入,不成功就彈出提示即可, 建議使用這種方式
if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
// iOS10及以上判斷方式
[application openURL:URL options:@{} completionHandler:^(BOOL success) {
NSLog(@"iOS10及以上Open %@: 是否成功%d",urlScheme,success);
if (!success) {
// 沒有成功
NSLog(@"iOS10 進入app失敗");
}
}];
} else {
BOOL success = [application openURL:URL];
NSLog(@"Open %@: %d",urlScheme,success);
if (!success) {
// 沒有成功
NSLog(@"進入app失敗");
}
}
}
運行效果:
使用 URL Scheme 注意點
- URL Identifier 的唯一性
- iOS9 之后的白名單 (LSApplicationQueriesSchemes)
- iOS 10 之后的 OpenURL 被棄用情況判斷
五、總結
- 個人覺得要實現一個 App間 跳轉功能確實不難,而且網絡上已經有很多先關的 demo,同時如果有使用過一些較有名的分享 SDK (Mob share 、友盟分享等) 的話都會碰到這些配置操作的詳細相關描述,只要跟著一步一步走就能實現,而難點就在于,知其然而不知其所以然吧,特別是一些概念性的問題,有些專業名詞確實理解起來有點難,還是那一句話,多看官方文檔描述,這樣子就能以不變應萬變吧。(由于本人英語理解力有限,怕誤人子弟,所以都貼上了圖及連接,以上個人文字僅從個人理解所寫)
- 原本只想自己總結一下是“判斷否安裝xApp”這個問題,雖知道,判斷之后就是跳轉啊之類的,那就索性隨便寫一下啰,希望能夠給各位閱讀者有一點點的幫助