最近在研究Deferred Deeplink,网上查了查资料,在这里整理记录一下,供大家学习参考。
Deferred Deeplink(延展的深度链接)
Deeplink有个局限,就是只能在已安装的APP之间进行跳转。如果没安装,就会出现下面的场景:用户在微信点击这个商品链接后,屏幕跳转到一个HTML5页面,页面右上角会有个按钮提示你到App Store下载。下载后打开应用,发现之前的商品页面找不到了。那么,用户很可能会直接卸载应用,商铺也会失去一次有效交易。
这时就需要Deeplink的进阶技术 —— Deferred Deeplink。当用户下载安装APP后,它可以直接打开此前显示的商品页面。
目前有3种方案(只说IOS,android 可以通过应用宝 applink实现)
H5页面在点击下载时自动调用剪切板复制当前用户渠道ID例如:#8283923023#,APP每次启动时调用剪切板内容格式符合则认定该用户和H5用户为同一用户;
但是要求用Safari浏览器打开,APP启动时去取safari种下的 ID,如果取到则认为是同一种方案;主要问题是微信安装或下载时要求用户Safari打开;
通过浏览器打开的 网络,ip,操作系统分辨率,语言等信息和APP拿到的 网络 ip 操作系统 等信息做模糊匹配,某时间段内匹配上则认为是同一个用户;
感兴趣的用户也可以尝试下1和2的结合。
Web链接不知道app的存在,当在手机上打开一个Jet.com这样一个网页链接,你会进入到浏览器中打开Jet.com网站,尽管你的手机上已经安装了Jet app。Deep Link解决的问题就点击一个网页链接,能够跳转到对应的app中。
传统的deep link当你在点击链接的时候,能够跳转到相应的app中,只要你已经安装了app。也就是如果手机上没有安装app,跳转至下载页。在iOS中,可以通过URL Scheme和Universe Link来实现。
deferred deep link是指用户打开一个web page的时候并没有安装对应的app,在用户安装app以后打开直接跳转到链接对应的内容。
实现思路:
H5需要上报设备的一些信息到服务器端进行保存,用户下载后,第一次启动也上报设备信息,去服务器端查找是否有匹配的H5页点击行为,如果匹配则进行app内部跳转。
应该上报哪些信息更获得比较高的匹配准确率?
Device Info
1> 前端获取尽可能多的信息上报后台进行存储
2> app启动时,同样提供尽可能多的设备信息,向后台查询
3> 后台根据相关设备信息以及前端和app端访问时间进行模糊匹配,匹配成功后向app返回数据
支持设备无限制,无侵入性,理论成功率低,实践成功率较高
Paste Board
1> 前端生成唯一标识符identifier,通过js脚本保存在剪贴板
2> 前端将identifier和其他数据上报后台,后台进行存储
3> app启动时读取剪贴板中的identifier,向后台查询数据
支持设备iOS10+,有侵入性,成功率高
网页和app共用Cookies
Github上的例子[2]
app内SFSafariViewController和系统的safari是同一个,共享同一个沙盒,可以操作同一个cookie。
1> 启动本地服务器,safari访问指定页面设置cookie,对应于为XXXHost
2> 前端将相关数据上报后台,后台解析cookie并与数据进行绑定保存
3> app启动时,先开启SFSafariViewController,访问特定url,并携带设备id
4> 后台解析上述访问url的设备id,并解析访问的cookie,将cookie与设备id绑定
5> app请求api接口,携带设备id,通过后台查询相关信息
app启动时SFSafariViewController设置为透明,用户无法感知这一流程:苹果审核指南:5.1.1
支持设备iOS9,iOS10,无侵入性
流程如下图所示:
整体流程示意图
简单的说就是用户点击一个链接,可以直接跳转的app里面的制定页面
这项技术在iOS App有新旧两种实现方案
Custom URL Scheme
Universal Links (iOS 9之后)
Universal Links 有许多 Custom URL Scheme不具备的优点
综合这些优点,Universal Links 大有取代前者的趋势。
然而以上所说的DeepLink,都建立在用户已经安装了App的前提下。
如果用户没用安装App,则需要引导用户到各种App Store去安装,等到用户安装完毕,打开App时就找不到之前的指定页面了,这条流程就被打断了。
安装之后,再一次引导用户点击链接,重走流程,这种体验显然是接受不了的。
因此,Deferred DeepLink应运而生。要解决的核心问题就是用户匹配,怎么知道现在打开App的用户就是刚才点击链接的那位用户。
常见使用场景:
1.在 Web 和 App 的切换过程中保留上下文。
(比如购物,用户在web浏览哪一件商品,跳转到App端继续浏览。记录登录信息自动登录等等)
2.好友邀请,点击链接即可,无需填写繁琐的邀请码
任何匹配的问题都可以转化到获取唯一标示的问题。
很容易联想到http里面的session和cookies。
但是iOS的沙盒模式,阻断了App之间的数据共享。也就是说App的cookies跟手机浏览器的cookies是分开的,无法互通。
直到iOS 9,Apple开放了SFSafariViewController
API,实现了App和Safari的cookies互通,那么一切问题迎刃而解了。首次启动App的时候,通过一个隐藏的SFSafariViewController
访问server,server通过cookies拿到唯一标示sessionID,从而得知用户之前访问过什么商品,进一步跳转到一个 Universal Links
,再进一步打开对应的商品详情页,完成了Deferred DeepLink的流程。
具体实现可参考 国外开源的Branch or VKSafariDomainBridge
这个方案仅仅解决了App和Safari之间的互通,手机上还有微信、手百、chrome等等第三方浏览器,并且项目还要支持iOS 9之前的系统版本。
下边讲另外一种方案,暂且叫做模糊匹配。
在用户点击web链接或打开app的时候,尽可能的收集跟设备相关的信息,例如
a.设备屏幕尺寸
b.设备操作系统版本号
c.ip地址
d.访问时间
e.使用的语言 等等
这些信息的每一项都不能作为唯一标示,但是如果把他们组合起来,作为一个集合,配合算法,进行模糊匹配,匹配成功的几率会大大提高。缺点也是显而易见的,也许世界上找不到两片同样的叶子,但是要找两部同样的手机还是挺容易的。匹配成功率取决于匹配策略,需要长期的去打磨匹配算法。
总结起来,两种方案都不是特别完美,与其自己去DIY,不如采用第三方提供Deferred DeepLink解决方案。
顾名思义,deferred deep linking 是指用户打开一个 web page 的时候并没有安装对应的 app,希望用户在安装 app 以后可以 deep link 到对应内容。这里有三个需要解决的问题:
判断是否已经安装了 app,如果已经安装了直接 deep link 到 app,否则跳转 App Store。
用户匹配(user matching),如何把一个 install 对应到某一次 web page view 或者某一次 click。
Deep linking
以前在使用 custom URL 的时候一般用类似这样的一段 JS 处理:
1 2 3 4 |
|
这是因为在 iOS 9.2 以前,Safari 里是否用 app 打开 custom URL 的提示是 blocking JS 的,所以如果用户同意用 app 打开链接以后就不会跳转 App Store,反之,用户选择取消或者并没有安装 app 的时候,会跳转 App Store。iOS 9.2 Apple 做了一个更新就是这个提示不再 block JS,所以无论如何都会跳转 App Store。
因此现在会推荐使用 universal links 来实现这样的逻辑,对于需要强制安装 app 后才能浏览的内容,可以提供一个直接跳转 App Store 的中转页面,如果装了 app,iOS 会自动跳转到 app 内处理。
这曾经是个老大难的问题,受系统所限,在 iOS 上很难追踪到一个安装的来源,但是这样的需求又很多,主要的场景有:
追踪广告效果
追踪用户推荐/邀请链接
在 app 内保持网页浏览的上下文,如登录信息,购物车等
对于这个问题,在 iOS 9 以前常见的做法是猜,没错,就是用猜的。在访问特定页面或点击特定链接的时候记录用户特征,如 IP,系统版本,手机型号,语言等等。然后在打开 app 的时候发送这些特征到服务器,查询一段时间内(如 1 小时内)有可以匹配的用户点击过的链接,然后处理这个链接。这样做的缺点很明显,因为是通过特征模糊匹配的,所以很容易匹配不到或匹配到错误的上下文。但是其实大部分第三方服务会从不同来源收集更多信息,所以这个准确率其实比想象中高很多,尤其是在打开了 IDFA 的情况下。
这个问题却在 iOS 9 引入 SFSafariViewController
以后得到了很好的解决,因为 SFSafariViewController
和 Safari 的 cookies 是互通的!所以理论上可以做到 100% 的 match。
解决方案也很简单,本地生成一个 UUID
并通过一个隐藏的 SFSafariViewController
传回给 server,server 就可以把这个 UUID
跟之前的 session 对应起来,然后通过一般的 API call 查询更多跟这个 session 有关的信息。
具体的 code 可以参考 Branch SDK 的实现。
上个章节已经提到,不再赘述,只是处理 URL 的入口换成了某个 API 请求的 callback 里。
有很多第三方提供了 deep linking 和 deferred deep linking 的服务,比如 AppsFlyer 和 Branch。目前在 Glow 的 app 里这两个 SDK 都有用到。
其中 AppsFlyer 的优势在于他们跟很多公司有合作关系,比如 Facebook,所以用于追踪 Facebook 广告效果表现较好。另外 AppsFlyer 支持很多第三方服务的 server callback,可以方便集成很多第三方服务。缺点是 AppsFlyer 按 non-organic install 量收费。而且 AppsFlyer 的 SDK 和 API doc 写的不是很好,在 track 安装以后的后续 deep link 的时候感觉有很多 bug。
Branch 的优势在于免费,SDK 和 API doc 都写的比较好,而且有一些特殊的功能比如用户邀请及奖励之类的,适合做一些运营活动。另外 Branch 可以实现一个 link 根据平台自动跳转不同 Store,甚至可以在 desktop 上通过短信发送可以追踪的链接。缺点是 Branch 运营时间不久,服务稳定性有待验证,dashboard 的功能也还比较轻量。
总的来说 AppsFlyer 更适合 track 广告效果,Branch 更适合实现 feature。必须一提的是,因为这两个服务都是主要面向海外市场的,所以曾经都遇到过国内短暂抽风的现象,所以国内的 app 如果要用的话风险自担 :) 如果国内有类似的服务的话也欢迎留言补充。
Branch 的集成比较简单,参见官方文档。一个需要注意的是,自己实现的时候在 handle URL 或者 user activity 的时候可以直接处理 URL,但是用 Branch 的时候,第一级的 URL 是 Branch 的 URL,所以要通过 [[Branch getInstance] handleDeepLink:url]
和/或 [[Branch getInstance] continueUserActivity:userActivity]
交由 Branch 处理,然后在 init Branch 时传入的 block (closure) 中处理各类参数:
1 2 3 4 5 6 7 8 |
|
前端开发经常面临跨域问题,恩Universal Link也有跨域问题,但不一样的是,Universal Link,必须要求跨域,如果不跨域,就不行,就失效,就不工作。(iOS 9.2之后的改动,苹果就这么规定这么设计的)
这也是上面拿知乎举例子的时候重点强调的一个问题,知乎为什么使用oia.zhihu.com
做Universal Link?
是不是不太好理解,那直接拿知乎举例子
有心人可能看到,知乎的Universal Link配置的是 oia.zhihu.com
这个域名,并且对这个域名下比如/answers /questions /people 等urlpath进行了识别,也就是说,知乎的universal link,只有当你访问 https://oia.zhihu.com/questions/xxxx
,在移动端会触发Universal Link,而知乎正经的Urlhttps//www.zhihu.com/questions/xxx
是不会触发Universal Link的,知乎为什么制作,为什么不把他的主域名配置Universal Link,就是由于Universal Link的跨域的原因。
知乎的一般网页URL都是www.zhihu.com
域名,你在微信朋友圈看到了知乎的问题分享,如果copy url 你就能看到这样的链接。
iOS Deep Links - 简书
Web端向App端导量神技Deferred DeepLink的实现思路 - 简书
Deferred Deeplink 如何做到用户下载应用后直接打开app内相应的页面? - 知乎
iOS 中的 Deferred Deep Linking(延迟深度链接) - itlover2013 - 博客园
The 5 Best Deferred Deep Linking Providers | Mobile Apps | Waracle