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”这个问题,虽知道,判断之后就是跳转啊之类的,那就索性随便写一下啰,希望能够给各位阅读者有一点点的帮助

六、参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容