URL Scheme / 系統(tǒng)是否安裝某App / 應(yīng)用間跳轉(zhuǎn) 整理

我對(duì)“是否安裝某App”問(wèn)題的第一反應(yīng)是,調(diào)用系統(tǒng)UIApplication對(duì)象的實(shí)例方法canOpenURL:來(lái)判斷,一般在自己得出習(xí)慣性的思維答案后,就覺(jué)得滿足,所以今天得一反常態(tài),重新認(rèn)識(shí)一下這個(gè)功能需求背后到底隱藏了哪些不曾為我所知的秘?秘密秘?在里面

我只想知道真相

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

總的來(lái)說(shuō),就是為了提升用戶體驗(yàn),摒除額外操作造成的時(shí)間浪費(fèi)。

結(jié)合目前自己做過(guò)的項(xiàng)目我覺(jué)得這個(gè)需求點(diǎn)的應(yīng)用場(chǎng)景有如下幾個(gè):

  1. 公司內(nèi)的 App 產(chǎn)品數(shù)多于2個(gè),并且業(yè)務(wù)間有聯(lián)系,各自的App信息界面有共享功能,如:

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

那么使用A app 的商家,如需更改其店鋪信息則需要切換到 B app 上執(zhí)行相關(guān)動(dòng)作。

  1. 公司為導(dǎo)流業(yè)務(wù),維護(hù)一些馬甲App,需從馬甲 App 跳到推薦安裝自己的主運(yùn)營(yíng) App 上。
  2. 調(diào)用系統(tǒng)App,如:短息,Email,通訊錄,iTunes...等相關(guān)情況。

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

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

先看看系統(tǒng)對(duì)canOpenURL:的描述:
摘自 UIApplication.h sdk(Xcode 8.3)
- (BOOL)canOpenURL:(NSURL *)url NS_AVAILABLE_IOS(3_0);`

沒(méi)有更詳細(xì)信息,那去https://developer.apple.com查查canopenurl:,看有無(wú)新發(fā)現(xiàn)。
映入眼簾的描述啊:

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參數(shù)是否能夠被已安裝在此設(shè)備上的一些App處理。

URL'scheme 是啥呢?

  1. URL Scheme是類(lèi)似 http://ftp://,afp:// 這樣的東西,通常是用傳輸協(xié)議作為URL Scheme。
  2. 不過(guò)事實(shí)上,你可以在iOS注冊(cè)任何類(lèi)型的URL Scheme。當(dāng)用戶通過(guò)系統(tǒng) API 訪問(wèn)你的自定義URL Scheme的鏈接的時(shí)候,操作系統(tǒng)就會(huì)打開(kāi)你的程序,響應(yīng)這個(gè)請(qǐng)求。

同樣我們順便看看 Discussion 部分吧,因?yàn)橐话阕⒁馐马?xiàng)都會(huì)羅列這個(gè) section,不看就虧了不是嗎:
openURL: Discussion part

注意點(diǎn)大概有:

  1. 當(dāng)該方法返的結(jié)果是 YES 的話,iOS 會(huì)保證之后通過(guò)調(diào)用相同 URL 參數(shù)的openURL:方法成功啟動(dòng)的 App 一定能夠處理該 URL 參數(shù)
  2. canOpenURL:方法返回的結(jié)果不代表 URL 的正確性 或者 URL 描述的資源存在性

Important:

  1. 如果 App 的 version >= iOS 9.0, 則必須先聲明作為參數(shù)傳入canOpenURL:方法的 URL schemes;
  2. 通過(guò)在 app 的 Info.plist 文件上添加LSApplicationQueriesSchemes key對(duì) URL 聲明 ;
  3. 如果未執(zhí)行先聲明動(dòng)作,而調(diào)用canOpenURL:時(shí)則會(huì)一直返回 FALSE;無(wú)論是否有已安裝且可處理該 URL 的 App 在本設(shè)備上
  1. 如果你的 app linked 的版本低于 iOS9.0,卻運(yùn)行在 iOS9.0或以上的話,那你只能正確調(diào)用canOpenURL:方法50次,超過(guò)次數(shù)之后的調(diào)用會(huì)一直返回 NO; 除非用戶重新安裝或升級(jí)App,則會(huì)重置該限制,
  2. openURL:canOpenURL:不同的是,openURL:方法不受LSApplicationQueriesSchemes 要求限制,即不管你有無(wú)先聲明該 URL schemes 在 Info.plist 的 LSApplicationQueriesSchemes內(nèi),只要有 app 能夠打開(kāi)該 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("");

既然出現(xiàn)自己不熟悉的LSApplicationQueriesSchemes key,今天就要一窺到底!

LSApplicationQueriesSchemes

說(shuō)的是:

  1. 這個(gè) key 用于 iOS 9.0 and later;
  2. 該key對(duì)應(yīng)的類(lèi)型為數(shù)組,用于存放通過(guò) canOpenURL:方法( UIApplication類(lèi)的實(shí)例方法)判斷的能否跳轉(zhuǎn)的 URL Schemes;(此描述不太恰當(dāng),詳細(xì)情況文檔)
    同樣還有一個(gè)我們之前就一直在用的與跳轉(zhuǎn)白名單相關(guān)概念 CFBundleURLTypes key
    截個(gè)圖讓大家與我一起復(fù)習(xí)一下吧:
    CFBundleURLTypes key

三、怎么去執(zhí)行以上步驟(配置 LSApplicationQueriesSchemes 與 CFBundleURLTypes)?(怎么做)

1、配置LSApplicationQueriesSchemes 。
聲明:“1、配置LSApplicationQueriesSchemes (添加Scheme白名單)?!?a target="_blank" rel="nofollow">摘自《mob的適配 ios - 9 必讀》

問(wèn)題描述:在iOS 9下涉及到平臺(tái)客戶端跳轉(zhuǎn),系統(tǒng)會(huì)自動(dòng)到項(xiàng)目info.plist下檢測(cè)是否設(shè)置平臺(tái)Scheme。對(duì)于需要配置的平臺(tái),如果沒(méi)有配置,就無(wú)法正常跳轉(zhuǎn)平臺(tái)客戶端。因此要支持客戶端的分享和授權(quán)等,需要配置Scheme名單。
具體方法:
1)、在項(xiàng)目的info.plist中添加一LSApplicationQueriesSchemes,類(lèi)型為Array。
2)、然后給它添加一個(gè)需要支持的項(xiàng)目,類(lèi)型為字符串類(lèi)型;


必看注意

1.在iOS9中,如果沒(méi)有添加上述白名單,系統(tǒng)會(huì)打印類(lèi)似如下提示:.-canOpenURL: failed for URL: “sinaweibohdsso://xxx” – error: “This app is not allowed to query for scheme sinaweibohdsso”(如下圖)如沒(méi)有添加相關(guān)白名單,有可能導(dǎo)致分享失敗,例如不會(huì)跳轉(zhuǎn)微信,不會(huì)跳轉(zhuǎn)****QQ****等。

2.添加完上述所需的名單,系統(tǒng)依然會(huì)打印類(lèi)似信息:.-canOpenURL: failed for URL: “sinaweibohdsso://xxx” – error: “null”這是系統(tǒng)打印的信息,目前是無(wú)法阻止其打印,即無(wú)法消除的

如果沒(méi)有設(shè)置白名單的話,系統(tǒng)的打印信息如圖所示:


添加完后,系統(tǒng)是依然會(huì)打印的,不過(guò)error會(huì)變成null:
沒(méi)設(shè)置白名單 系統(tǒng) error 為 null

2、配置CFBundleURLTypes 。(估計(jì)這個(gè)你也做過(guò)好多遍了吧??)

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

    圖片引《自判斷iOS設(shè)備上是否安裝某個(gè)應(yīng)用以及應(yīng)用跳轉(zhuǎn)》
  2. 接上配置LSApplicationQueriesSchemes的配置圖(因?yàn)槿绻?iOS 9+ 環(huán)境下調(diào)用 canOpenURL:方法需要同時(shí)配置LSApplicationQueriesSchemes )
    圖片引《自判斷iOS設(shè)備上是否安裝某個(gè)應(yīng)用以及應(yīng)用跳轉(zhuǎn)》

四、應(yīng)用間跳轉(zhuǎn)

  1. 在 One App 中注冊(cè)設(shè)置需要跳轉(zhuǎn)的URL Scheme


    設(shè)置URL Types
  2. 可以在Safari 中測(cè)試該 URL Scheme 是否能被跳轉(zhuǎn)


    Safari中測(cè)試URLScheme.gif

注意:APP URL格式為: URL Scheme://urlidentifier,直接調(diào)用URL Scheme也可打開(kāi)程序, url identifier是可選的。

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


    Two App 中的 info Plist 中添加白名單 Url
  2. 在 Two App 中添加跳轉(zhuǎn)到One App代碼

- (IBAction)jumpToOneApp:(id)sender {
    
    NSString *urlscheme = @"oneapp://";
    [self checkIfInstalledAppWithUrlSchemes:urlscheme];
    
}

#pragma mark - 判斷是否安裝了APP 如安裝則跳轉(zhuǎn)到對(duì)應(yīng) App
- (void)checkIfInstalledAppWithUrlSchemes:(NSString *)urlScheme {
    
    NSURL *URL = [NSURL URLWithString:urlScheme];
    UIApplication *application = [UIApplication sharedApplication];
    /*
    // 方式一 :
    
    // 判斷是否安裝了APP
    
    if ([application canOpenURL:URL]) {
        
        NSLog(@"已經(jīng)安裝,并且可以打開(kāi)");
        if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
            
            // iOS10及以上判斷方式
            [application openURL:URL options:@{} completionHandler:^(BOOL success) {
                
                NSLog(@"iOS10及以上Open %@: 是否成功%d",urlScheme,success);
                if (!success) {
                    // 沒(méi)有成功
                    NSLog(@"iOS10 進(jìn)入app失敗");
                }
            }];
            
        } else {
            
            BOOL success = [application openURL:URL];
            NSLog(@"Open %@: %d",urlScheme,success);
            if (!success) {
                // 沒(méi)有成功
                NSLog(@"進(jìn)入app失敗");   
            }
        }
        
    } else {
        NSLog(@"不能打開(kāi)");
    }
    */
    
    // 方式二:
    
    // 直接進(jìn)入,不成功就彈出提示即可, 建議使用這種方式
    
    if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
        // iOS10及以上判斷方式
        
        [application openURL:URL options:@{} completionHandler:^(BOOL success) {
            
            NSLog(@"iOS10及以上Open %@: 是否成功%d",urlScheme,success);
            
            if (!success) {
                // 沒(méi)有成功
                NSLog(@"iOS10 進(jìn)入app失敗");
            }
            
        }];        
    } else {

        BOOL success = [application openURL:URL];        
        NSLog(@"Open %@: %d",urlScheme,success);
        if (!success) {
            // 沒(méi)有成功
            NSLog(@"進(jìn)入app失敗");       
        }
    }
}

運(yùn)行效果:


JumpToOne.gif

使用 URL Scheme 注意點(diǎn)

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

跳轉(zhuǎn)測(cè)試 Demo

五、總結(jié)

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

六、參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容