1. 程式人生 > >【iOS開發】開啟另一個APP(URL Scheme與openURL)

【iOS開發】開啟另一個APP(URL Scheme與openURL)

目標

平常我們做iOS開發,會經常遇到開啟其他的APP的功能。本篇文章講的就是開啟別人的APP的一些知識。我們的目標是:

  • 開啟別人的APP
  • 讓別人開啟我們的APP
  • iOS9的適配問題
  • 使用URL Schemes傳遞資料

準備工作

  • 建立一個名為OpenApp的工作空間,用來存放我們的兩個工程
    建立這個工作空間主要是為了讓我們後面建立的兩個工程能在一個Xcode頁面上管理,方便講解和管理。挺簡單的,不清楚的可以看我之前的文章【iOS開發】在一個Xcode頁面建立多個工程
建立一個workspace來存放我們的工程
  • 建立一個名為MyApp的iOS工程。這個MyApp是“我的app”,用來開啟另一個APP的。
    新增工程到我們剛才建立的OpenApp.xcworkspace。並且在工程的Main.storyboard新增一個button,待會兒我們會用來寫方法。


    MyApp工程
  • 建立一個名為WXApp的iOS工程。這個工程是我們模擬的“微信APP”,是被人開啟的那個APP。
    為了區分兩個應用,我們在Main.storyboard上加一個label,“我是微信App”。


    在workspace建立WXApp工程
WXApp

好了,準備工作就這麼簡單。

開啟別人的APP與讓別人開啟我們的APP

想要開啟別人的APP或者讓別人開啟我們的APP,那就需要通過URL Schemes了。

什麼是URL Schemes?

URL Schemes是蘋果給出的用來跳轉到系統應用或者跳轉到別人的應用的一種機制。同時還可以在應用之間傳資料。

通過對比網頁連結來理解 iOS 上的 URL Schemes,應該就容易多了。
URL Schemes 有兩個單詞:

  • Schemes,表示的是一個 URL 中的一個位置——最初始的位置,即 ://
    之前的那段字元。比如 http://www.apple.com
    這個網址的 Schemes是 http
    根據我們上面對 URL Schemes 的使用,我們可以很輕易地理解,在以本地應用為主的 iOS 上,我們可以像定位一個網頁一樣,用一種特殊的 URL 來定位一個應用甚至應用裡某個具體的功能。而定位這個應用的,就應該是這個應用的 URL 的 Schemes 部分,也就是開頭兒那部分。

在WXApp上設定一個URL Schemes

為了能讓別的App(包括我們剛才建立的MyApp)能夠開啟WXApp,我們需要為WXApp新增一個URL Schemes。
步驟:選中WXApp工程->Info->URL Types->點選“+”->在URL Schemes欄填上 weixin

新增一個URL Schemes

備註:一個應用是可以有多個URL Schemes的。你可以再次點選“+”來新增一個URL Schemes

我們看看info.plist檔案裡面是怎樣的。

info.plist檔案裡面的URL Schemes

然後我們run一下WXApp。(注意一下你run的target是哪個)

在模擬器run一下WXApp

這樣,WXApp就向系統“註冊”了一個URL Schemes,其他的應用可以通過openurl:方法來開啟WXApp了。

MyApp開啟WXApp

現在我們在MyApp裡面開啟WXApp。方法非常簡單。
在ViewController裡面新增一個方法

- (IBAction)openWXApp:(UIButton *)sender {
    [self demo1];
}
- (void)demo1 {
    //建立一個url,這個url就是WXApp的url,記得加上://
    NSURL *url = [NSURL URLWithString:@"weixin://"];
    
    //開啟url
    [[UIApplication sharedApplication] openURL:url];
}

然後run一下MyApp

run MyApp

運行了之後點選“開啟微信”button,會彈出“MyApp”想要開啟“WXApp”提示框,點確認之後就可以跳轉到WXApp了。

點選“開啟微信”button打開了WXApp

iOS9之後,在一個應用跳轉到了另一個應用之後,左上角會有個返回到上一個應用的按鈕。這樣,我們在MyApp裡面點選“開啟微信”按鈕,跳轉到WXApp之後,再點選“Back to MyApp”,又回到MyApp了。閒著無聊就可以反覆點選這兩個按鈕來兩個應用間跳轉了,哈哈。

值得一說的是,這個URL Schemes並不是唯一的。也就是說,多個應用之間設定的URL Schemes是可以相同的。
那麼問題來了,假如兩個應用的URL Schemes相同的話,使用openURL:方法會開啟哪個應用呢?
樓主親自用手機試了一下。
步驟是:

  • 將MyApp安裝到手機上,點選“開啟微信”button,微信打開了。
  • 然後將WXApp也安裝到手機上。再次點選MyApp的“開啟微信”button,結果開啟的是WXApp。
    結論:如果兩個應用有URL Schemes是相同的,後安裝的應用的URL Schemes會把早安裝的應用的URL Schems覆蓋掉。

在safari開啟WXApp

沒錯,註冊了URL Schemes的應用,用safari瀏覽器也是可以開啟的。我就經常用這個來驗證應用是否設定了我想要的URL Schemes
在safari開啟WXApp,直接在safari的位址列輸入weixin://,enter就可以打開了

用safari開啟WXApp用safari開啟WXApp

iOS9中的適配

  • 配置URL Schemes白名單
    其實在開啟WXApp的時候,正常情況下,我們應該是先用canOpenURL:方法先判斷能否開啟這個url,然後再用openURL方法開啟該URL的。這樣可以帶來更好的使用者體驗。因為使用者不一定安裝了WXApp。假如使用者沒有安裝的話點選“開啟微信”button是沒有任何反應的。這時候我們應該先判斷是否能夠開啟這個url(也就是判斷使用者有沒有安裝WXApp),沒有安裝的話就給個溫馨提示,比如:“U四不四灑,沒安裝WXApp,怎麼開啟啊!”。
    更重要的是,假如點選之後沒效果,很有可能被蘋果拒絕哦。
- (IBAction)openWXApp:(UIButton *)sender {
//    [self demo1];
    [self demo2];
}
//先判斷再開啟WXApp
- (void)demo2 {
    //建立一個url,這個url就是WXApp的url,記得加上://
    NSURL *url = [NSURL URLWithString:@"weixin://"];

    //先判斷是否能開啟該url
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        //開啟url
        [[UIApplication sharedApplication] openURL:url];
    }else {
        //給個提示或者做點別的事情
        NSLog(@"U四不四灑,沒安裝WXApp,怎麼開啟啊!");
}

但是我們發現用了canOpenURL:方法之後,並沒有如我們想像中打開了WXApp。一看,Xcode控制檯提示:

Xcode控制檯錯誤提示

為什麼會這樣呢?
因為iOS9的時候蘋果加強了許可權,只有在info.plist檔案中加入了URL Schemes白名單才能使用canOpenURL:方法來判斷是否能開啟該url。該白名單的上限是50個。也就是說,你最多隻能使用canOpenURL:方法判斷50個URL Schemes。當然,平常我們都用不了那麼多,就算是整合分享功能,50個肯定夠了。

備註:只是對canOpenURL:方法有限制,openURL:方法是沒有限制的。

言歸正傳,我們需要在MyApp的info.plist裡面將weixin設定為白名單。
步驟:點選info.plist->右鍵->Open As->Source Code->新增下面的程式碼

    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>weixin</string>
    </array>

這樣就可以了。

使用URL Schems傳遞資料

URL Schemes除了可以用來開啟APP之外,還可以用來在兩個App之間傳遞少量的資料。
在百度上搜索“ios”,會生成一個url,下面來以這個url來大概介紹url的組成。

  • https就是協議,也就是scheme
  • /s是路徑
  • ?後面的是query,也就是查詢引數。這個url有兩個引數,分別是ie=UTF-8wd=ios

我們iOS的URL Schemes中也是差不多的。
而且,在openURL的時候,如果url中帶有引數,只要URL Schemes是正確的,那同樣可以開啟App,而且,後面的引數也會帶到我們開啟的App那裡。
咱們做個Demo就一目瞭然了。
在MyApp中,寫個demo3方法,url為weixin://www.shixueqian.com/abc?title=hello&content=helloworld

- (IBAction)openWXApp:(UIButton *)sender {
//    [self demo1];
//    [self demo2];
    [self demo3];
}
//使用URL Schemes傳遞資料
- (void)demo3 {
    //建立一個url,這個url就是WXApp的url,記得加上://
    NSURL *url = [NSURL URLWithString:@"weixin://www.shixueqian.com/abc?title=hello&content=helloworld"];
    //開啟url
    [[UIApplication sharedApplication] openURL:url];  
}

在WXApp的AppDelegate.m中,實現application: openURL:(NSURL *)url sourceApplication: annotation:回撥

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    
    NSLog(@"url=====%@ \n  sourceApplication=======%@ \n  annotation======%@", url, sourceApplication, annotation);
    return YES;
}

run了之後,我們發現,我們依舊可以通過點選openURL:方法開啟WXApp。而且在WXApp被開啟的時候,會執行application: openURL:(NSURL *)url sourceApplication: annotation:回撥方法。在這個回撥方法中,我們可以得到MyApp傳過來的url等資訊。
控制檯列印如下:

log結果

完整的url資訊都傳過來了,我們就可以利用這個url裡面的路徑和引數等資訊了,想幹嘛就幹嘛。這就實現了從MyApp向WXApp傳遞資料了。

備註:
蘋果一共給了3個openURL的回撥。
分別是:

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation NS_DEPRECATED_IOS(4_2, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options NS_AVAILABLE_IOS(9_0); // no equiv. notification. return NO if the application can't open for some reason

為什麼會有3個呢?這3個回撥又有什麼區別?(為方面講解,分別設定ABC3個回撥)

  • 3個回撥的功能基本一樣,都是在別人通過URL Schemes開啟應用的時候會執行的。
    不同之處:
  • A回撥是在iOS2.0的時候推出的,引數只有url
  • B回到是在iOS4.2的時候推出的,引數有url sourceApplication annotation.
  • C回撥是iOS9.0的時候推出的,引數有url optionsoptions有下面幾個key
// Keys for application:openURL:options:
UIKIT_EXTERN NSString *const UIApplicationOpenURLOptionsSourceApplicationKey NS_AVAILABLE_IOS(9_0);   // value is an NSString containing the bundle ID of the originating application
UIKIT_EXTERN NSString *const UIApplicationOpenURLOptionsAnnotationKey NS_AVAILABLE_IOS(9_0);   // value is a property-list typed object corresponding to what the originating application passed in UIDocumentInteractionController's annotation property
UIKIT_EXTERN NSString *const UIApplicationOpenURLOptionsOpenInPlaceKey NS_AVAILABLE_IOS(9_0);   // value is a bool NSNumber, set to YES if the file needs to be copied before use
  • 這幾個回撥是有優先順序的。C>B>A。也就是說,如果你3個回撥都實現了,那麼程式只會執行C回撥。其他回撥是不會執行的。(當然,iOS9以下只會執行B回撥)。

參考

歡迎觀看我的另一篇文章,是這篇文章的進階版。
【iOS開發】仿微信分享功能

謙言萬語

用通俗的語言,講述動人的程式碼故事。