URL Schemes深度剖析(上)

自定義URL Schemes

1、引言

URL Schemes 應用在 iOS 上已經很久了。對於使用者來說,在沙盒機制下的 iOS 中,如果想做到一定程度上的自動化就不可避免地要用到 URL Schemes。但因爲 URL Schemes 的使用方式不像傳統 iOS 使用者接觸到的圖形界面那樣可以直觀地點來點去,造成了對它有興趣的人(尤其是對英文有恐懼的人)一定程度上理解的困難。

2、簡介蘋果的沙盒機制

蘋果選擇沙盒來保障用戶的隱私和安全,但沙盒也阻礙了應用間合理的信息共享,於是有了 URL Schemes 這個解決辦法。

一般來說,我們使用的智能設備上有許多我們的個人信息。比如:聯繫方式、銀行卡/信用卡信息、支付寶/Paypal/各大商城的賬戶密碼、照片甚至行程與位置信息等。

如果說,你設備上的每一個應用,不管是官方的還是你從任何商城安裝的應用都可以隨意地獲取這些信息,那麼你輕則收到騷擾信息和郵件、重則後果不堪設想。如何讓這些信息不被其它應用隨意使用,或者說,如何讓這些信息僅在設備所有者本人知情並允許的情況下被使用,是所有智能設備與操作系統所要在乎的核心安全問題。

在 iOS 這個操作系統中,針對這個問題,蘋果使用了名爲「沙盒」的機制:應用只能訪問它聲明可能訪問的資源。一切提交到 App Store 的應用都必須遵守這個機制。

在安全方面沙盒是個很好的解決辦法,但是有些矯枉過正。敏感的個人信息我們不願意透露,卻不代表所有的信息我們都不想與其它應用共享。

比如說我們要一次性地(沒錯,只按一次)把多個事件放到日曆中,這些事件包含日期時間以及持續時間等信息,如果 App 之間信息不能溝通,就無法做到這點。(在下文中的 x-callback-URL 的部分會詳述整個過程)

類似於一次性添加多個日曆事件這樣的,我們在使用智能設備的過程中會遇到很多不必要的重複的步驟。大多數人對這些重複的步驟是不自覺的,就像當自己電腦裏有一批文件需要批量重命名的時候,他們機械地重複着重命名的過程。但是當我們掌握了這些設備運行的模式,或者有了一些工具,我們就能將這些重複的步驟全部節省下來。在 iOS 上,我們可以利用的工具就是 URL Schemes。

3、URL Schemes 是什麼

Custom URL scheme 的好處就是,你可以在其它程序中通過這個url打開應用程序。如A應用程序註冊了一個url scheme:myApp, 那麼就在mobile瀏覽器中就可以通過

注意

1、所有的網頁都有url;但未必所有的應用都有自己的 URL Schemes,更不是每個應用的每個功能都有相應的 URL Schemes

2、一個網址只對應一個網頁,但並非每個 URL Schemes 都只對應一款應用。這點是因爲蘋果沒有對 URL Schemes 有不允許重複的硬性要求

3、一般網頁的 URL 比較好預測,而 iOS 上的 URL Schemes 因爲沒有統一標準,所以非常難猜,通過猜來獲取 iOS 應用的 URL Schemes 是不現實的。(我推薦將Bundle identifier反轉)

上乾貨

1、註冊自定義 URL Scheme

1)註冊自定義 URL Scheme 的第一步是創建 URL Scheme — 在 Xcode Project Navigator 中找到並點擊工程 info.plist 文件。當該文件顯示在右邊窗口,在列表上點擊鼠標右鍵,選擇 Add Row:

url scheme1.png

2)點擊左邊剪頭打開列表,可以看到 Item 0,一個字典實體。展開 Item 0,可以看到 URL Identifier,一個字符串對象。該字符串是你自定義的 URL scheme 的名字。建議採用反轉Bundle idenmtifier的方法保證該名字的唯一性

url scheme2.png

3)點擊 Item 0 新增一行,從下拉列表中選擇 URL Schemes,敲擊鍵盤回車鍵完成插入。(注意 URL Schemes 是一個數組,允許應用定義多個 URL schemes。)展開該數據並點擊 Item 0。你將在這裏定義自定義 URL scheme 的名字。只需要名字,不要在後面追加 ://

url scheme3.png

2、拿瀏覽器坐簡單驗證

在地址欄中熟入自定的url scheme。此時必須保證該瀏覽器所在設備上已經安裝了具有自定義url scheme的App。

IMG_5739.PNG

3、新建Xcode工程,做個App試試看,這裏我就放一個Button,點擊打開url
代碼。

- (IBAction)open:(id)sender {
    NSString *url = @"zhunaer://?name=lbp&age=22";
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:url]]) {
           [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
    }else{
        NSLog(@"打不開");
    }
}

結果打不開,爲什麼?
因爲在新建App的plist中沒加query schemes

<key>LSApplicationQueriesSchemes</key>
<array>
<string>zhunaer</string>
</array>

4、如果需要在2個App之間傳值,怎麼辦?可以用URL Scheme解決。

在被打開的App的Appdelegate.m中實現-(BOOL)application:(UIApplication )application openURL:(nonnull NSURL )url sourceApplication:(nullable NSString *)sourceApplication annotation:(nonnull id)annotation;

-(BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(nonnull id)annotation{
    NSLog(@"calling application bundle id: %@",sourceApplication);
    NSLog(@"url shceme:%@",[url scheme]);
    NSLog(@"參數:%@",[url query]);
    if ([sourceApplication isEqualToString:@"com.geek.test1"]) {
        return YES;
    }
    return NO;

}

在需要打開第三方App的點擊事件處的url處後面加上參數,類似NSString *url = @”zhunaer://?name=lbp&age=22”;

注意:在URL Scheme後加?然後跟網頁的url的參數一樣寫法。

5、如何判斷是指定App打開,或者某些App不讓打開我們的App?
做了實驗。

A:在需要打開第三方App的工程中將Bundle identifier改爲“com.geek.test2”,其餘不變

B:在被打開的App的AppDelegate.m中

-(BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(nonnull id)annotation{
    NSLog(@"calling application bundle id: %@",sourceApplication);
    NSLog(@"url shceme:%@",[url scheme]);
    NSLog(@"參數:%@",[url query]);
    if ([sourceApplication isEqualToString:@"com.geek.test1"]) {
        return YES;
    }
    return NO;
}

Simulator Screen Shot 2017年5月1日 下午2.48.21.png

實驗結果

依舊可以打開App,即使斷點走入Return NO

結論:如果你想阻止其它應用調用你的應用,創建一個與衆不同的 URL scheme。儘管這不能保證你的應用不會被調用,但至少大大降低了這種可能性。

參考:https://sspai.com/post/31500#01

發佈了42 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章