URL Scheme / 系統是否安裝某App / 應用間跳轉 整理

我對“是否安裝某App”問題的第一反應是,調用系統UIApplication對象的實例方法canOpenURL:來判斷,一般在自己得出習慣性的思維答案后,就覺得滿足,所以今天得一反常態,重新認識一下這個功能需求背后到底隱藏了哪些不曾為我所知的秘?秘密秘?在里面

我只想知道真相

一、為啥要判斷系統是否安裝了這個App?(為什么)

總的來說,就是為了提升用戶體驗,摒除額外操作造成的時間浪費

結合目前自己做過的項目我覺得這個需求點的應用場景有如下幾個:

  1. 公司內的 App 產品數多于2個,并且業務間有聯系,各自的App信息界面有共享功能,如:

A 中有商家店鋪的基本信息,但不具備修改功能
B 中則有商家的店鋪詳細信息,且具有可修改功能

那么使用A app 的商家,如需更改其店鋪信息則需要切換到 B app 上執行相關動作。

  1. 公司為導流業務,維護一些馬甲App,需從馬甲 App 跳到推薦安裝自己的主運營 App 上。
  2. 調用系統App,如:短息,Email,通訊錄,iTunes...等相關情況。

二、用到了哪些API?(是什么)

就從我的第一反應源(canOpenURL:)入手吧。

先看看系統對canOpenURL:的描述:
摘自 UIApplication.h sdk(Xcode 8.3)
- (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 是啥呢?

  1. URL Scheme是類似 http://ftp://afp:// 這樣的東西,通常是用傳輸協議作為URL Scheme。
  2. 不過事實上,你可以在iOS注冊任何類型的URL Scheme。當用戶通過系統 API 訪問你的自定義URL Scheme的鏈接的時候,操作系統就會打開你的程序,響應這個請求。

同樣我們順便看看 Discussion 部分吧,因為一般注意事項都會羅列這個 section,不看就虧了不是嗎:
openURL: Discussion part

注意點大概有:

  1. 當該方法返的結果是 YES 的話,iOS 會保證之后通過調用相同 URL 參數的openURL:方法成功啟動的 App 一定能夠處理該 URL 參數
  2. canOpenURL:方法返回的結果不代表 URL 的正確性 或者 URL 描述的資源存在性

Important:

  1. 如果 App 的 version >= iOS 9.0, 則必須先聲明作為參數傳入canOpenURL:方法的 URL schemes;
  2. 通過在 app 的 Info.plist 文件上添加LSApplicationQueriesSchemes key對 URL 聲明 ;
  3. 如果未執行先聲明動作,而調用canOpenURL:時則會一直返回 FALSE;無論是否有已安裝且可處理該 URL 的 App 在本設備上
  1. 如果你的 app linked 的版本低于 iOS9.0,卻運行在 iOS9.0或以上的話,那你只能正確調用canOpenURL:方法50次,超過次數之后的調用會一直返回 NO; 除非用戶重新安裝或升級App,則會重置該限制
  2. 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,今天就要一窺到底!

LSApplicationQueriesSchemes

說的是:

  1. 這個 key 用于 iOS 9.0 and later;
  2. 該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:
沒設置白名單 系統 error 為 null

2、配置CFBundleURLTypes 。(估計這個你也做過好多遍了吧??)

  1. 設置URL Schemes (在需要跳轉的APP中設置自己的Scheme)
    圖片引《自判斷iOS設備上是否安裝某個應用以及應用跳轉》

    圖片引《自判斷iOS設備上是否安裝某個應用以及應用跳轉》
  2. 接上配置LSApplicationQueriesSchemes的配置圖(因為如果在 iOS 9+ 環境下調用 canOpenURL:方法需要同時配置LSApplicationQueriesSchemes )
    圖片引《自判斷iOS設備上是否安裝某個應用以及應用跳轉》

四、應用間跳轉

  1. 在 One App 中注冊設置需要跳轉的URL Scheme


    設置URL Types
  2. 可以在Safari 中測試該 URL Scheme 是否能被跳轉


    Safari中測試URLScheme.gif

注意:APP URL格式為: URL Scheme://urlidentifier,直接調用URL Scheme也可打開程序, url identifier是可選的。

  1. 在Two App 中的 info Plist 中添加白名單 URL Scheme


    Two App 中的 info Plist 中添加白名單 Url
  2. 在 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失敗");       
        }
    }
}

運行效果:


JumpToOne.gif

使用 URL Scheme 注意點

  • URL Identifier 的唯一性
  • iOS9 之后的白名單 (LSApplicationQueriesSchemes)
  • iOS 10 之后的 OpenURL 被棄用情況判斷

跳轉測試 Demo

五、總結

  1. 個人覺得要實現一個 App間 跳轉功能確實不難,而且網絡上已經有很多先關的 demo,同時如果有使用過一些較有名的分享 SDK (Mob share 、友盟分享等) 的話都會碰到這些配置操作的詳細相關描述,只要跟著一步一步走就能實現,而難點就在于,知其然而不知其所以然吧,特別是一些概念性的問題,有些專業名詞確實理解起來有點難,還是那一句話,多看官方文檔描述,這樣子就能以不變應萬變吧。(由于本人英語理解力有限,怕誤人子弟,所以都貼上了圖及連接,以上個人文字僅從個人理解所寫)
  2. 原本只想自己總結一下是“判斷否安裝xApp”這個問題,雖知道,判斷之后就是跳轉啊之類的,那就索性隨便寫一下啰,希望能夠給各位閱讀者有一點點的幫助

六、參考文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容