iOS开发 打开另一个APP(URL Scheme与openURL)

目标

平常我们做iOS开发,会经常遇到打开其他的APP的功能。本篇文章讲的就是打开别人的APP的一些知识。我们的目标是:

  • 打开别人的APP
  • 让别人打开我们的APP
  • 版本大于等于iOS9的适配问题
  • 使用URL Schemes传递数据

准备工作

  • 建立一个名为OpenApp的工作空间,用来存放我们的两个工程
    建立这个工作空间主要是为了让我们后面建立的两个工程能在一个Xcode页面上管理,方便讲解和管理。挺简单的,不清楚的可以看我之前的文章【iOS开发】在一个Xcode页面建立多个工程
image
  • 建立一个名为MyApp的iOS工程。这个MyApp是“我的app”,用来打开另一个APP的。
    添加工程到我们刚才创建的OpenApp.xcworkspace。并且在工程的Main.storyboard添加一个button,待会儿我们会用来写方法。

    image
  • 建立一个名为WXApp的iOS工程。这个工程是我们模拟的“微信APP”,是被人打开的那个APP。
    为了区分两个应用,我们在Main.storyboard上加一个label,“我是微信App”。

    image
image

好了,准备工作就这么简单。

打开别人的APP与让别人打开我们的APP

想要打开别人的APP或者让别人打开我们的APP,那就需要通过URL Schemes了。

什么是URL Schemes?

URL Schemes是苹果给出的用来跳转到系统应用或者跳转到别人的应用的一种机制。同时还可以在应用之间传数据。

通过对比网页链接来理解 iOS 上的 URL Schemes,应该就容易多了。
URL Schemes 有两个单词:

  • URL,我们都很清楚,http://www.apple.com
    就是个 URL,我们也叫它链接或网址;
  • 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

image

备注:一个应用是可以有多个URL Schemes的。你可以再次点击“+”来添加一个URL Schemes

我们看看info.plist文件里面是怎样的。

image

然后我们run一下WXApp。(注意一下你run的target是哪个)

image

这样,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

image

运行了之后点击“打开微信”button,会弹出“MyApp”想要打开“WXApp”提示框,点确认之后就可以跳转到WXApp了。

image
image

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覆盖掉。

20180528编辑:后安装的应用的URL Schemes会把早安装的应用的URL Schems覆盖掉,这个结论是不合理的。具体的话也没测试出结果。就当留个坑吧。

在safari打开WXApp

没错,注册了URL Schemes的应用,用safari浏览器也是可以打开的。我就经常用这个来验证应用是否设置了我想要的URL Schemes
在safari打开WXApp,直接在safari的地址栏输入weixin://,enter就可以打开了

image
image

版本大于等于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控制台提示:

image

为什么会这样呢?
因为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->添加下面的代码

    LSApplicationQueriesSchemes
    
        weixin
    

这样就可以了。

使用URL Schems传递数据

URL Schemes除了可以用来打开APP之外,还可以用来在两个App之间传递少量的数据。
在百度上搜索“ios”,会生成一个url,下面来以这个url来大概介绍url的组成。

url为:https://www.baidu.com/s?ie=UTF-8&wd=ios

  • https就是协议,也就是scheme
  • www.baidu.com 是域名
  • /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等信息。
控制台打印如下:

image

完整的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 *)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回调)。

参考

本篇文章的Demo已经上传到GitHub上了https://github.com/shixueqian/OpenApp

欢迎观看我的另一篇文章,是这篇文章的进阶版。
【iOS开发】仿微信分享功能

谦言万语

用通俗的语言,讲述动人的代码故事。

作者:谦言忘语
链接:https://www.jianshu.com/p/0811ccd6a65d
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(iOS开发 打开另一个APP(URL Scheme与openURL))