APP唤醒与场景还原
在App投放推广中,唤醒用户是常见的运营策略。想要让用户重新活跃起来,转化用户的行为,必须从场景上还原用户的路径,从根本上找到用户增长的奥秘。
在这个广告漫天的时代,相信大多数用户在使用App的时候都遇到类似的场景:在使用某资讯类App的时候,浏览到了淘宝的商品广告,当你点击该广告内容时,自动打开了你手机上已经安装的淘宝App并且定位到了该商品的详情页。
- 作为用户,心里一定在想:“这购物真方便,都不要自己打开淘宝搜索商品了”。
- 作为广告主,心里在想:“又拉活了一个用户,说不定还能带来一笔转化”。
那么,资讯类App是如何唤醒淘宝App的呢,淘宝App又是如何跳转至用户浏览的广告页面呢?
唤醒&场景还原,作为运营常用的拉活增长手段,有利于提升老用户在App的活跃度,场景化的唤醒更能激发用户的转化意愿。
其适用于如下几个营销场景:
- 浏览器 -> 唤醒APP:用户A在手机上通过浏览器打开了某APP的M站或者官网,则引导用户打开该APP或者下载该APP。
- 微信、QQ等 -> 唤醒APP:用户通过某APP分享了一条链接至微信或QQ,用户B点开该链接后,引导用户B打开该APP或者下载该APP。
- 短信、邮件、二维码等-> 唤醒APP:用户A打开了某APP的推广短信,邮件或者扫描二维码等,引导用户打开该APP或者下载该APP。
- 其他APP -> 唤醒APP:用户A通过第三方APP分享了一条链接至用户B,用户B点开该链接后,引导用户B打开指定APP或者下载指定APP。
常见唤醒APP方式
URL Scheme
URI Schema 是这几种调起方式中最原始的一种,只需要原生APP开发时注册scheme, 那么用户点击到此类链接时,会自动唤醒APP,借助于URL Router机制,则还可以跳转至指定页面。这种方式是当前使用最广泛,也是最简单的,但是需要手机APP支持URL Scheme。
iOS URL Scheme
iOS的沙盒机制
iOS选择沙盒来保障用户的隐私和安全,但沙盒也阻碍了应用间合理的信息共享,于是有了 Url Schemes 这个解决办法。一般来说,我们使用的智能设备上有许多我们的个人信息。比如:联系方式、银行卡/信用卡信息、支付宝/Paypal/各大商城的账户密码、照片甚至行程与位置信息等。
如果说,你设备上的每一个应用,不管是官方的还是你从任何商城安装的应用都可以随意地获取这些信息,那么你轻则收到骚扰信息和邮件、重则后果不堪设想。如何让这些信息不被其它应用随意使用,或者说,如何让这些信息仅在设备所有者本人知情并允许的情况下被使用,是所有智能设备与操作系统所要在乎的核心安全问题。
在 iOS 这个操作系统中,针对这个问题,苹果使用了名为「沙盒」的机制:应用只能访问它声明可能访问的资源。一切提交到 App Store 的应用都必须遵守这个机制。
在安全方面沙盒是个很好的解决办法,但是有些矫枉过正。敏感的个人信息我们不愿意透露,却不代表所有的信息我们都不想与其它应用共享。比如说我们要一次性地(没错,只按一次)把多个事件放到日历中,这些事件包含日期时间以及持续时间等信息,如果 App 之间信息不能沟通,就无法做到这点。类似于一次性添加多个日历事件这样的,我们在使用智能设备的过程中会遇到很多不必要的重复的步骤。大多数人对这些重复的步骤是不自觉的,就像当自己电脑里有一批文件需要批量重命名的时候,他们机械地重复着重命名的过程。但是当我们掌握了这些设备运行的模式,或者有了一些工具,我们就能将这些重复的步骤全部节省下来。在 iOS 上,我们可以利用的工具就是 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 部分,也就是开头儿那部分。比如短信,就是 sms:
你可以完全按照理解一个网页的 URL ——也就是它的网址——的方式来理解一个 iOS 应用的 URL,拿苹果的网站和 iOS 上的微信来做个简单对比:
网页(苹果) | iOS 应用(微信) | |
网站首页/打开应用 | http://www.apple.com | weixin:// |
子页面/具体功能 | http://www.apple.com/mac/ | weixin://dl/moments |
在这里,http://www.apple.com 和 weixin:// 都声明了这是谁的地盘。然后在 http://www.apple.com 后面加上 /mac 就跳转到从属于 http://www.apple.com 的一个网页(Mac 页)上;同样,在 weixin:// 后面加上 dl/moments 就进入了微信的一个具体的功能——朋友圈。
但是,两者还有几个重要的区别:
- 所有网页都一定有网址,不管是首页还是子页。但未必所有的应用都有自己的 URL Schemes,更不是每个应用的每个功能都有相应的 URL Schemes。实际上,现状是,大多数的应用只有用于打开应用的 URL Schemes,而有一些应用甚至没有用于打开应用的 URL Schemes。几乎没有所有功能都有对应 URL 的应用。所以,不要说某某应用烂,不支持国内应用。一个 App 是否支持 URL Schemes 要看那个 App 的作者是否在自己的作品里添加了 URL Schemes 相关的代码。
- 一个网址只对应一个网页,但并非每个 URL Schemes 都只对应一款应用。这点是因为苹果没有对 URL Schemes 有不允许重复的硬性要求,所以曾经出现过有 App 使用支付宝的 URL Schemes 拦截支付帐号和密码的事件。
- 一般网页的 URL 比较好预测,而 iOS 上的 URL Schemes 因为没有统一标准,所以非常难猜,通过猜来获取 iOS 应用的 URL Schemes 是不现实的。
基本 URL Schemes
基本 URL Schemes 的能力虽然简单有限,但使用情境却是最普遍的。所谓的基本 URL Schemes,是指一个 URL 的 Schemes 部分,比如上文提到的微信的 weixin:。这个部分的唯一功能,就是打开相应应用,而不能够跳转到任何功能。
绝大多数所谓支持 URL Schemes 的应用,一般都是只有这么一个部分,它一般是这个应用的名称,比如 OmniFocus 这款应用,它的基本 URL Schemes 就是 Omnifocus:。如果应用的主名称是个中文名的话,它的 URL Schemes 也许会是应用名的拼音,比如 墨客 这款应用,它的基本 URL Schemes 是 moke:。但网页 URL 和 iOS 应用的 URL 的三个重要区别,其中第三项,就是 iOS 上的 URL Schemes 并不规范,一个应用的 URL 可以是各种各样的:
- Coursera 的 URL 是:coursera-mobile:
- Duet 这款游戏的 URL 是:x-kumo-duet:
- Monument 这款游戏的 URL 是:fb690517270143345:
- Feedly 的 URL 是:fb129765800430121:
- 扇贝新闻的 URL 是:wx95962d02b9c3e2f7:
它们目前并没有统一的规则,所以猜测一个应用的意义并不太大,你可以试试,但不要过于指望这种方式。下文会提到如何查找一个应用的基本 URL Schemes,只要那个应用支持 URL Schemes 就能找到。基本 URL Schemes 的能力虽然简单有限,但使用情境却是最普遍的。
复杂 URL Schemes
掌握复杂 URL Schemes 你才算初步有了打造适应自己使用情境的自动化流程的能力。iOS 应用的复杂 URL Schemes 就像网站的子页面的链接一样,在首页网址的基础上进行延伸。
具体来看,复杂 URL Schemes 有两种:一种是直接打开某个应用的某个功能,另一种是打开某个功能后直接填写预设的字符。就成为了一个更加实用的 URL Schemes,因为它不光直接让你进入了某个你需要的功能界面,还直接帮你填好了你需要的内容,而跳转后,你需要的只是按一下完成。
有了这样的 URL Schemes,应用之间才可以互相地协作。比如说,当我们在Mr. Reader上看到一篇文章里面写了一个不错的软件的时候,我们可以利用OmniFocus的 URL Schemes 将文章名保存到任务名的部分,把链接保存到备注的部分。在 iOS 8 的 Share Sheet 出现之前,这是唯一在 App 间传输信息的方式。
复杂 URL Schemes 有一个特殊的用例是 Jumpback,字典类 App 用它的很多,比如欧路词典。传统的使用欧陆字典查询单词的 URL Schemes 是:
eudic://dict/想查的单词
在这个基础上,加上一句 Jumpback:
eudic://dict/想查的单词?jumpback=指定URL
就能够做到查完单词以后,按左上角或左下角的返回按钮,回到你想要回到的 App。
并不是每个应用都有它的复杂 URL Schemes,但一般来说,有系统规范的复杂 URL Schemes 的应用都是同类应用中的佼佼者。
x-callback-URL
从一个应用的界面跳转到了另一个应用后,就会在左上角看到回到上一个应用的字样,轻触就能返回到上一个应用。这样的事情我们在打造自己的自动化操作的时候毫无疑问也会想要做到,前面说过的Jumpback是一个选择,除此之外还有更强力的代替者——x-callback-URL,它还有 iOS 9 上「返回上个应用」这一功能不能代替的地方。但是不可否认的是,x-callback-URL 的使用情境比较少,使用难度却又比较高。
我们前面谈到的 URL Schemes 都只有一个目的,不管结果是什么,跳转完成后就会停留在跳转后的应用的界面。但在使用 URL Schemes 的时候,运行结果有时候可能成功,有时候可能失败,有时候我们也会手动将其取消。
如果我们还想让应用根据不同的结果有对应的反应,就要用到 x-callback-URL。比如当上一个 URL Schemes 运行成功以后,我是要回到跳转前的应用?还是要接另一个动作(接上另一段 URL Schemes,打开另一个应用的某个功能)?无论是跳转回上个应用还是打开另一个动作,只要你在运行完一个 URL Schemes 后还想再利用一段新的 URL Schemes 做下一件事,就要靠 x-callback-URL,它的固定语法是:
- 在一个 URL Schemes 后面接&x-success,表示前一个 URL 成功以后下一步做什么;
- 在一个 URL Schemes 后面接&x-error,表示前一个 URL 失败以后下一步做什么;
- 在一个 URL Schemes 后面接&x-cancel,表示取消前一个 URL 的操作结果后下一步做什么;
- 还有一个&x-source 我们遇到了再说。
URL 编码(Encode)
URL 中的字符可以分为两类,一部分可以在链接中正常显示,比如字母、数字还有/等一部分符号。除此之外,全部不能正常显示,需要进行编码才能够作为 URL 的一部分出现。比如空格,在 URL 中就必须表示为%20转换的规则不用深究,网上有很多工具提供 URL 的编码和解码功能,可以把编码过的乱七八糟的 URL 解码为我们看得清爽的字符。这些工具当然也可以反过来把我们常用的字符转换成可以在 URL 中使用的字符。
所以理论上,所有 URL 不支持的字符,都要编码。
自定义 URL Scheme 进行跳转
如果我们希望别人打开我们的 app(名字叫做 SchemeDemo),需要注册自定义 URL Scheme,通过 info.plist –> URL Types –> item0 –> URL Schemes –> 你的TestScheme 来设置,详细步骤如下:
1、点击工程中的 info.plist 文件,当该文件显示在如下窗口时,在列表顶部鼠标选中 Information Property List,选择 +,然后向下滚动弹出的列表并选择 URL types,类型为 NSArray。
2、点击 URL types 左边剪头打开列表,可以看到 Item 0,一个字典实体。展开 Item 0,可以看到 URL Identifier,一个字符串对象。该字符串是你自定义的 URL scheme 的名字。建议采用反转域名的方法保证该名字的唯一性,比如 com.yourCompany.yourApp。
3、点击 Item 0 新增一行,从下拉列表中选择 URL Schemes,敲击键盘回车键完成插入。注意 URL Schemes 是一个数组,允许应用定义多个 URL schemes。
4、展开 URL Schemes 该数据并点击 Item 0。你将在这里定义自定义 URL scheme 的名字。只需要名字,不要在后面追加 ://,比如,如果你输入 iOSDevApp,你的自定义 url 就是 iOSDevApp://。
此时,整个定义如下图:
Android URL Scheme
Android中的自定义的URL Scheme是一种页面内跳转协议,也可以被称为URLRouter,就是通过类似打开网页的方式去通过路由打开一个Activity,而非直接通过显式Intent方式去进行跳转。这样隐式intent的方法跳转好处如下:
- 降低耦合性:不需要知道具体要跳转哪个界面,只需要根据需求,按照约定好的URL路由协议发送Intent即可;
- 更为安全:不显示Intent跳转,只要是符合协议的Intent都会有对应的Activity来匹配,避免了跳转到不该出现的页面;
- 更为灵活: 有着更为广泛的应用场景,多种场景中都可以使用URL Scheme
URL Scheme协议格式
上文已经说过,URL Scheme是就通过类似打开网页的方式去通过路由打开一个Activity,其协议格式和我们打开网页输入的网址类似。
一个完整的完整的URL Scheme协议格式由scheme、host、port、path和query组成,其结构如下所示:
:// : / ?
其中scheme既可以是Android中常见的协议,也可以是我们自定义的协议。Android中常见的协议包括content协议、http协议、file协议等,自定义协议可以使用自定义的字符串,当我们启动第三方的应用时候,多是使用自定义协议。
如下是一个自定义协议的URI:xl://goods:8888/goodsDetail?goodsId=10011002
通过上面的路径 Scheme、Host、port、path、query全部包含:
- xl,即为Scheme,代表该Scheme 协议名称
- goods,即为Host,代表Scheme作用于哪个地址域
- 8888,即为port,代表该路径的端口号
- goodsDetail,即为path, 代表Scheme指定的页面
- goodsId,即为query,代表传递的参数
URL Scheme的使用方法
URL Scheme的使用方法简要言之就是先在manifest中配置能接受Scheme方式启动的activity;当需要调用时,将Scheme协议的URi以Data的形式加入到Intent中,隐式调用该activity。
1)在AndroidManifest.xml中对标签增加
上面的设置中可以看到,MainActivity包含多个
这里需要说明下,URL Scheme协议格式中,组成URI的这些属性在标签中都是可选的 ,但存在如下的依赖关系:
- 如果没有指定scheme,那么host参数会被忽略
- 如果没有指定host,那么port参数会被忽略
- 如果scheme和host都没有指定,path参数会被忽略
当我们将intent对象中的Uri参数与intent-filter中的标签指定的URI格式进行对比时,我们只对比intent-filter的标签指定的部分,例如:
- 如果intent-filter中只指定了scheme,那么所有带有该sheme的URI都能匹配到该intent-filter。
- 如果intent-filter中只指定了scheme和authority(authority包括host和port两部分)而没有指定path,那么所有具有相同scheme和authority的URI都能匹配到该intent-filter,而不用考虑path为何值。
- 如果intent-filter中同时指定了scheme、authority和path,那么只有具有相同scheme、authority和path的URI才能匹配到该intent-filter。
需要注意的是,intent-filter的标签在指定path的值时,可以在里面使用通配符*,起到部分匹配的效果。
2)使用URL启动Activity
Uri data = Uri.parse("urlschemel://auth_activity"); Intent intent = new Intent(Intent.ACTION_VIEW,data); //保证新启动的APP有单独的堆栈,如果希望新启动的APP和原有APP使用同一个堆栈则去掉该项 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityForResult(intent, RESULT_OK); } catch (Exception e) { e.printStackTrace(); Toast.makeText(MainActivity.this, "没有匹配的APP,请下载安装",Toast.LENGTH_SHORT).show(); }
当然可以在网页中调用:
打开新的应用
或者是在JS中调用:
window.location = "urlschemel://auth_activity";
3)如何判断URL Scheme是否有效
boolean checkUrlScheme(Intent intent){ PackageManager packageManager = getPackageManager(); Listactivities = packageManager.queryIntentActivities(intent, 0); return !activities.isEmpty(); }
将子APP在Home Launcher中隐藏
有时候需要把一些辅助性的、较为独立的APP在Home Launcher中隐藏起来,只允许一些特定的APP调用。这个时候,我们可以利用URL Scheme协议来做到这一点,设置AndroidManifest.xml中对标签如下:
因为Home Launcher列出的应用图标要求必须有Activity同时满足:
上面的配置中有多余的category和data限制存在,所以并不匹配,不会在Home Launcher出现,但是可以使用URL Scheme来启动。
Uri data = Uri.parse("urlschemel://auth_activity"); Intent intent = new Intent(Intent.ACTION_MAIN,data); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
这样就可以将一组APP设置一个统一的入口,然后根据实际需要在调用不同子APP,即所谓的APP业务组件化。
URL Scheme的缺点
提示框
我们只能通过固定协议格式的链接来实现跳转,而且打开H5页面时,会出现一个提示框:“是否打开XXX”。用户确认了才会跳转到App中,增加了用户流程。
未安装APP导致的异常
错误处理情况因平台不同,难以统一处理,部分APP会直接跳错误页(比如Android Chrome/41,iOS中老版的Lofter);也有的停留在原页面,但弹出提示“无法打开网页”(比如iOS7);iOS8以及最新的Android Chrome/43 目前都是直接停留在当前页,不会跳出错误提示。
场景支持情况
iOS在实际使用中,腾讯系的微信,QQ明确禁止使用,iOS9以后Safari不再支持通过js,iframe等来触发scheme跳转,并且还加入了确认机制,使得通过js超时机制来自动唤醒APP的方式基本不可用;Android平台则各个app厂商差异很大,比如Chrome从25及以后就同Safari情况一样。
命名冲突或劫持
如果手机中同時存在有两个应用都使用相同的 URL Scheme,那么唤起目标应用时,系统会优先唤起哪一个呢?Apple在后续iOS版本(iOS 11)采用了先到先得原则,如果使用了同一个URL Scheme,只有先安装的app会被启动。然而,攻击者还是可以通过其他方法来利用这个漏洞。
打开方式被禁
微信、QQ等把URL Scheme 打开App这种方式给禁了,但是它们都各自维护着一个白名单,如果Scheme不在该白名单内,那么就不能在他们的App内打开这个App(如果被封锁了那么用户只能通过右上角浏览器内打开App)
iOS Universal Links
Universal Link 是苹果在 WWDC 上提出的 iOS9 的新特性之一。此特性类似于深层链接,并能够方便地通过打开一个 Https 链接来直接启动您的客户端应用(手机有安装 App)。对比起以往所使用的 URL Scheme,这种新特性在实现 web-app 的无缝链接时能够提供极佳的用户体验。
当你的应用支持 Universal Link(通用链接),当用户点击一个链接是可以跳转到你的网站并获得无缝重定向到对应的 APP,且不需要通过 Safari 浏览器。如果你的应用不支持的话,则会在 Safari 中打开该链接。
使用 Universal Link(通用链接)可以让用户在 Safari 浏览器或者其他 APP 的 webview 中拉起相应的 APP,也可以在 APP 中使用相应的功能,从而来把用户引流到 APP 中。这具体是一种怎样的情景呢?举个例子,你的用户 safari 里面浏览一个你们公司的网页,而此时用户手机也同时安装有你们公司的 App;而 Universal Link 能够使得用户在打开某个详情页时直接打开你的 app 并到达 app 中相应的内容页面,从而实施用户想要的操作(例如查看某条新闻,查看某个商品的明细等等)。比如在 Safari 浏览器中进入淘宝网页点击打开 APP 则会使用 Universal Link(通用链接)来拉起淘宝 APP。
Universal link 的特点:
- 唯一性: 不像自定义的 URL Scheme,因为它使用标准的 HTTPS 协议链接到你的 web 站点,所以一般不会被其它的 APP 所声明。另外,URL scheme 因为是自定义的协议,所以在没有安装 app 的情况下是无法直接打开的(在 Safari 中还会出现一个不可打开的弹窗),而 Universal Link(通用链接)本身是一个 HTTPS 链接,所以有更好的兼容性;
- 安全: 当用户的手机上安装了你的 APP,那么系统会去你配置的网站上去下载你上传上去的说明文件(这个说明文件声明了当前该 HTTPS 链接可以打开那些 APP)。因为只有你自己才能上传文件到你网站的根目录,所以你的网站和你的 APP 之间的关联是安全的;
- 可变: 当用户手机上没有安装你的 APP 的时候,Universal Link(通用链接)也能够工作。如果你愿意,在没有安装你的 app 的时候,用户点击链接,会在 safari 中展示你网站的内容;
- 简单: 一个 HTTPS 的链接,可以同时作用于网站和 APP;
- 私有: 其它 APP 可以在不需要知道你的 APP 是否安装了的情况下和你的 APP 相互通信。
Universal Link的优点:
- Custom URL scheme是自定义的协议,因此在没有安装该app的情况下是无法直接打开的。而Universal Links本身也就是一个能够指向一个web页面或者app中的内容页的标准的web link(形如https://example.com) 因此能够很好的兼容其他情况。也就是说,当已经安装了这个app的时候,不需要加载任何web页面,app就会立即启动;当这个app没有安装的时候,就会默认地从当前浏览器中重定向到App Store中引导用户去下载安装这个app。
- Universal links是从服务器上查询是哪个app需要被打开,因此不存在Custom URL scheme那样名字被抢占、冲突的情况。
- Universal links支持从其他app中的UIWebView中跳转到目标app
- 安全性,用universl link去打开的时候,只有你可以通过创建和上传一个允许这个网页去通过这个URL去打开你的app的文件。
- 隐私性,提供Universal link给别的app进行app间的交流,然而对方并不能够用这个方法去检测你的app是否被安装。
Universal link 配置和运行
1) 配置 App ID 支持 Associated Domains
登录https://developer.apple.com/ 苹果开发者中心,找到对应的 App ID,在 Application Services 列表里有 Associated Domains 一条,把它变为 Enabled 就可以了。
2 )配置 iOS App 工程
Xcode 11.0 版本:工程配置中相应功能:targets->Signing&Capabilites->Capability->Associated Domains,在其中的 Domains 中填入你想支持的域名,也必须必须以 applinks:为前缀。
Xcode 11.0 以下版本:工程配置中相应功能:targets->Capabilites->Associated Domains,在其中的 Domains 中填入你想支持的域名,必须以 applinks:为前缀。
3) 配置和上传 apple-app-association
究竟哪些的 url 会被识别为 Universal Link,全看这个 apple-app-association 文件 Apple Document UniversalLinks.html
- 你的域名必须支持 Https
- 域名根目录或者.well-known目录下放这个文件apple-app-association,不带任何后缀。
- 文件为 json 保存为文本即可
- json 按着官网要求填写即可
apple-app-site-association模板:
{ "applinks": { "apps": [], "details": [ { "appID": "9JA89QQLNQ.com.apple.wwdc", "paths": [ "/wwdc/news/", "/videos/wwdc/2015/*"] }, { "appID": "ABCD1234.com.apple.wwdc", "paths": [ "*" ] } ] } }
说明:
- appID:组成方式是yourapp’s bundle identifier。如上面的 9JA89QQLNQ 就是 teamId。登陆开发者中心,在 Account -> Membership 里面可以找到 Team ID。
- paths:设定你的 app 支持的路径列表,只有这些指定的路径的链接,才能被 app 所处理。星号的写法代表了可识 别域名下所有链接。
上传指定文件:上传该文件到你的域名所对应的根目录或者.well-known 目录下,这是为了苹果能获取到你上传的文件。上传完后,自己先访问一下,看看是否能够获取到,当你在浏览器中输入这个文件链接后,应该是直接下载 apple-app-site-association 文件。
验证 Universal link 生效
可以使用 iOS 自带的备忘录程序,输入链接,长按链接,如果弹出菜单中有”在‘xxx’中打开”,即表示配置生效。或者将要测试的网址在Safari中打开,在出现的网页上方下滑,可以看到有在”xxx”应用中打开, 出现菜单。
当点击某个链接,直接可以进我们的 app 了,但是我们的目的是要能够获取到用户进来的链接,根据链接来展示给用户相应的内容。
在AppDelegate里中实现代理方法,官方链接: Handling Universal Links
Objective-C:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler { if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { NSURL *url = userActivity.webpageURL; if (url是我们希望处理的) { //进行我们的处理 } else { [[UIApplication sharedApplication] openURL:url]; } } return YES; }
Swift:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingURL = userActivity.webpageURL, let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true), let path = components.path, let params = components.queryItems else { return false } print("path = \(path)") if let albumName = params.first(where: { $0.name == "albumname" } )?.value, let photoIndex = params.first(where: { $0.name == "index" })?.value { print("album = \(albumName)") print("photoIndex = \(photoIndex)") return true } else { print("Either album name or photo index missing") return false } }
Universal link跨域问题
Universal Link有跨域问题,Universal Link必须要求跨域,如果不跨域,就不会跳转(iOS 9.2之后的改动)要求具备跨域能力即可, 假如当前网页的域名是A,当前网页发起跳转的域名是B,必须要求B和A是不同域名才会触发Universal Link,如果B和A是相同域名,只会继续在当前WebView里面进行跳转,哪怕你的Universal Link一切正常,根本不会打开App 2. Universal Link请求apple-app-site-association时机
- 当我们的App在设备上第一次运行时,如果支持Associated Domains功能,那么iOS会自动去GET定义的Domain下的apple-app-site-association文件
- iOS会先请求https://domain.com/.well-known/apple-app-site-association,如果此文件请求不到,再去请求https://domain.com/apple-app-site-association,所以如果想要避免服务器接收过多GET请求,可以直接把apple-app-site-association放在./well-known目录下
Universal Link更新
apple-app-association的更新时机有以下两种:
- 每次App安装后的第一次Launch,会拉取apple-app-association
- Appstore每次App的版本更新后的第一次Launch,也会更新apple-app-association
所以反复重新杀APP重开完全没用,删了App重装确实有用,但不可能让用户这么去做。也就是说,一旦不小心因为意外apple-app-association,想要挽回又让那部分用户无感,App再发一个版本就好了。
Universal Link用户行为
Universal Link 触发后打开App,这时候App的状态栏右上角会有文字提示来自XXApp,可以点状态栏的文字快速返回原来的AP
如果用户点了返回微信,就会被苹果记住,认为用户并不需要跳出原App打开新App,因此这个App的Universal Link会被关闭,再也无效。
想要开启也不是不行,让用户重新用safari打开,universal link的页面,然后会出现很像苹果smart bar的东西,那个东西点了后就能打开
H5 端的 Universal Link 业务部署
H5 端的 Universal Link 跳转,从产品经理的角度看,需要满足以下 2 个需求:
- 如果已安装 App,跳转对应界面
- 如果没安装 App,跳转 App 下载界面
H5 端部署 Universal Link 示例:
router.use('/view', function (req, res, next) { var path = req.path; res.redirect('https://www.xxx.com/view' + path + '?xxx=xxx'); });
整个效果就是
- 跳转https://www.xxx.com/view/*
- 已安装 App
- 打开 App 触发 handleUniversalLink
- 走到/view/分支,拼接阅读页路由跳转
- 未安装 AppWebView
- 原地跳转https://www.xxx.com/view/*
- 命中服务器的重定向逻辑
- 重定向到https://www.xxx.com/view/*
- 打开相应的 H5 页面
- 已安装 App
Chrome Intent
在很多应用中需要我们从浏览器中直接启动应用,大多数采用的是上面提到的第一种scheme的方式,问题是如果手机中没有应用,该url会跳转到一个错误的界面。
Google官方在chrome中推出了一种Android Intents的方式来实现应用启动,通过在iframe中设置src为:
- intent:HOST/URI-path // Optional host
- #Intent;
- package=[string];
- action=[string];
- category=[string];
- component=[string];
- scheme=[string];
- end;
mainfest文件中定义要启动的activity:
定义一个a标签为
open Android App
在浏览器中点击a标签,就可以启动应用程序的对应activity了。如果手机中没有相应的应用,防止跳转到错误页面,将a标签设置为:
open Android App
这样如果没有对应应用,该链接就会跳转到==S.browser_fallback_url==指定的url上。
备注:很多第三方浏览器会拦截掉chrome intent启动应用的请求。
Android App Link
类似 Universal Links, Android App Link采取类似的机制:使用标准的 Web 页面 URL,同时绑定对应的 App。在 Android >= 6 的系统中支