1024 程序猿节
节日前夕在此祝愿猿们
coding 不再苦,还没 bug 补
钱多事还少,而且不怕老(秃)
前言
我们先来谈论两个场景:
叮,收到一条push,是你感兴趣的内容,你点击了这个push,随后手机打开了网易新闻App,刚刚push的文章呈现在你眼前。
当你在微信观看朋友分享的搞笑视频时,看完之后意犹未尽,这时“点击查看更多”的按钮映入眼帘,点击之后,手机自动唤起了网易新闻App,并且打开了一个视频列表。
这样熟悉的场景每天都在发生,可是这是怎么实现的呢?H5页面是如何唤起应用程序(App)的呢?读完本文,你可以了解到以下几点:
唤起客户端的意义
URL Scheme
Universal Links
网易新闻唤端的实现逻辑
以网易新闻客户端为例,简单讲就是通过一个Web页面,手机打开了网易新闻App,或者打开了下载网易新闻的页面,这个过程称为唤端。我们通过gif图来直观的看一下唤端的过程:
如上图所示,微信中打开了一个Web页面,点击底部的“打开“按钮之后,微信提示“可能离开微信,打开第三方应用“,确认后网易新闻客户端被成功唤起,并打开了对应的功能页面。这是一个简单的唤端场景,为什么说简单呢,试想,如果微信(或其他第三方App)不支持唤起呢,如果用户没有安装网新闻客户端呢。问题先放在这里,后面将会一一回答。我们做一个产品的目标,粗俗来讲就是要获取用户,其次,获取用户的时间。如此一来,为什么要唤端就很明了了:
现在有两个通用的方案可以实现这种带有“磁力“的深度跳转,即URL Scheme 和 Universal Links。URL scheme 跳转可以说是在Web页面唤起 App 中,应用最广泛的途径。我们先从URL入手,每个有效的URL都指向Web上一个独特的资源,这个资源可以是一个HTML页面,一幅图像,一段视频等等。那么我们想访问手机上的应用程序,那就需要给App也分配一个URL,不同的是这是一个自定义的特殊格式的URL。一个ULR由协议、域名、端口、路径、参数等部分组成,其中一些是必须的,一些是可选的,这里把我们的关心都留给协议部分:相对于这个链接中,http:// 就是他的协议,同样,Web中还有其他的协议,比如邮件协议mailto:// 、文件传输协议:ftp:// 等。URL scheme 就可以理解为是一个自定义的URL,scheme就是协议部分,应用程序启动是通过协议来标识的。空洞的描述远不如举个例子来的实在:实际应用中,仅打开应用程序是不够的,还需要定位到用户需要的功能页面。URL必须是以自定义的协议名称开头,添加的参数是应用程序支持的,格式如下:[ scheme ] :// [ path ] [ ?query ]比如,打开微信的扫码:weixin://scanqrcode。URL scheme 提供了一种引用应用程序内资源的方法,已安装 App 的场景下是支持URL scheme 跳转的;如果未安装 App 就没有任何效果了。而且,实际上浏览器是没有能力判断手机里是否安装了某个App的。当然,要想从外部打开一个应用程序,仅仅约定好了协议是远不够的,还需要客户端一系列的配置才能实现。
universal links 是苹果在 WWDC2015 上为 iOS9 引入的新功能,iOS的官方文档中有如下描述:当支持universal links时,用户点击网页上的链接,会无缝跳转到已安装的应用程序,而无需通过Safari。即便未安装该应用程序,点击网站的链接后会在Safari中打开该地址指向的页面。
如果说universal links的意义就是把普通的 URL,赋予了打开 App 的能力,这样也是说的通的。相比于URL scheme,universal links有它独特的优势。- 第一,唯一性。不同于URL scheme, universal links是标准的HTTP协议或者HTTPS协议的链接,不会被其他应用程序定义而导致“撞地址”;
- 第二,灵活简单。即使手机未安装该应用程序,universal links也是可用的,即按用户期望,点击网站的链接可在Safari中打开内容。
- 第三,安全。当用户安装应用程序时,iOS会检查开发者已上传到Web服务器的文件,以确保允许应用程序打开该URL。只有开发者可以创建和上传此文件,因此我们的网站与应用程序的关联是安全的。
接下里的问题就变成了怎么配置universal links,看文档一步步配置就成啦,此处不再赘述。网易新闻的universal link是:https://m.163.com/newsapp/applinks.html?path=xxx,页面展示如下:
参数path的作用是特定的路径链接到特定页面,下表中所示几个常用的路径:
universal links 可以是个空页面,但是我们把它做成中间页(或称为下载页),为的就是当用户没有安装网易新闻客户端时,universal link被当做普通的页面链接进行跳转,我们可以引导用户去下载了。可不要小看这个页面,它是连接在用户和产品之间重要的桥梁。新闻客户端中间页具备较多的功能,主要有 唤醒、下载、自定义展示引导内容、自动跳转Web页。
通过前面的介绍,我们可以发现,无论是 URL scheme 还是 universal links ,他们都算是 URL ,只不过 URL scheme 算是特殊格式的 URL。所以我们可以拿使用 URL 的方法来使用它们。即window.location,<a>标签和<iframe>标签。但是需要注意的是,iOS9以上系统中, iframe 通过URL scheme均无法成功唤起 APP。
<a href="deepLink">
<iframe src="deepLink">
window.location.href = deepLink
我们必然面临选择,如果用户安装了我们的App,那自然有康庄大道可以走,如果没有安装,我们的终点就是下载了。安卓系统可以直接下载apk,或者到腾讯应用宝进行下载,如下图所示。iOS系统也是两个路子,一是在浏览器引导下载,二是直接跳转到App Store,见下图。虽然已安装,但也不是坦途,因为有的App不希望用户为了看一些分享和内容就跳走,所以他们进行拦截,使得URL scheme 和 universal links 不能生效。庆幸的是,虽然QQ不允许使用URL scheme进行跳转,但是腾讯的应用宝也是具备唤起客户端的功能的,所以我们要利用起来。如果将App进行分类的话,就分成:想让Web页面在这么多场景中都能成功唤起咱们的App,解决思路分成两部分,scheme方案和非scheme方案。首先我们把不允许使用URL scheme的App分拣出来,比如QQ,微博、微信、手机百度等等,此外其他的App都尝试使用URL scheme唤端,如果唤起失败就尝试非scheme的方法唤起。我们采用的是iframe标签来实现URL scheme跳转,首先准备好要打开的 App 内某一功能界面的路径,然后创建一个ifame标签,赋值给src。代码实现:const url = 'newsapp://doc/F6RAR7OF05179U0P'
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
document.body.appendChild(iframe)
iframe.src = url
页面展示
如果通过scheme跳转失败了,采用非scheme的方案。但是浏览器实际上是没有能力判断手机唤端是否成功了,所以一般方案是,监听页面是否在一定时间内隐藏来判断是否成功唤起 App。首先设置定时器,点击唤端后延时时间设为1.2秒,执行非scheme方案
监听页面隐藏事件,如果事件被触发,页面隐藏,则表示唤端成功,清除定时器,唤端结束;
如果事件没有被触发,那么就代表唤端失败,定时器延时到了就会执行非scheme方案进行唤端。
const loadTimer = setTimeout(() => {
unSchemaOpenApp()
}, time)
document.addEventListener('visibilitychange', function () {
if (document.hidden || document.webkitHidden) {
clearTimeout(loadTimer)
}}, false)
window.addEventListener('pagehide', function () {
clearTimeout(loadTimer)
}, false)
非scheme方案又分成三种,一是universal links,二是通过腾讯应用宝,进行曲线救国,达到或下载或唤端的目的,三是直接下载安卓apk。由于微信、QQ、QQ浏览器, 不支持ULR scheme唤醒客户端,为了避免用户体验不佳,直接跳转到腾讯应用宝。应用宝会引导用户打开对应客户端。
if (isTencentMarketCase) {
const pkgname = 'com.netease.newsreader.activity'
let tencent = `http://a.app.qq.com/o/simple.jsp?pkgname=${pkgname}&ckey=CK1331205846719&android_scheme=${wechatScheme}&ios_scheme${wechatScheme}`
window.location.href = tencent
return
}
结果展示如图,当点击左图的“安全打开“,会弹窗询问是否要打开其他应用,点击“允许“就跳转到网易新闻了。
如果是iOS的App,并且不支持scheme,那我们选择universal links(中间页)来实现跳转。
if (isIOS) {
const downloadPage = '//m.163.com/newsapp/applinks.html?path=${path}'
window.location.href = downloadPage
return
}
允许universal links
不允许universal links
如果此App允许universal links,那么唤端相当顺滑,我们来看动图展示:如果是不支持,那我们只能通过中间页,努力的引导用户通过浏览器打开。从下图中红色的“卑微“小箭头可以看出我们的努力,当用户选择浏览器打开之后,会直接跳转到新闻客户端,还是这熟悉的配方,熟悉的场景了。具体效果可见gif展示。最后判断是否是安卓,是的话弹起下载弹窗,下图所示。因为安卓的大部分App应该在scheme方案中就成功实现唤端,所以这里可以看作是一个兜底方案,在唤起失败的场景下提示安卓用户可以直接下载安装包。
if (isAndroid) {
const androidDownloadUrl = '//static.ws.126.net/163/apk/newsapp/newsreader_sps_article.apk'
showToast(androidDownloadUrl, channel, scheme, spss)
}
害,感觉挺长一个篇幅来讲这个事情,如果以结果论的话,总结一下无非就是以下几个路子:3、跳转中间页,蒙层或小箭头引导用户点击右上角按钮,使用浏览器打开;
此外,为第三方App唤端,微信提供了白名单,也开放了特定的标签,也为丰富了我们的选择。坦白说,并没有一个万无一失十全十美的方法,让我们的Web页面在所有场景中唤端一步到位,或者体验一致,而我们在代码层面上能做的只是在确保最常用的场景,最大化的兼容其他场景,来实现我们的唤端大业。
点个赞,证明你还爱我