之前在百度,负责了很长一段时间某App的拉新、拉活工作。主要就是在分享页拉起App。下面是18年上半年做的一篇总结。包含了我所遇到的各种的业务需求、场景。
背景
在H5页面或者app的webview中调起第三方app
核心
调起app是操作系统(iOS、Android)的机制,在h5页面,我们可以做的不多。
在调起之前,h5页面无法判断当前手机是否安装了对应的app,我们只能去尝试调起,并且用一些方法来处理没有调起的情况。
调起的原理就不介绍了,网上一搜一大堆。直接上核心代码。
if(iOS9) { window.location.href = ${universalLink}; } else { var ifr = document.createElement('iframe'); ifr.src = ${scheme}; ifr.style.display = 'none'; document.body.appendChild(ifr); window.setTimeout(function () { document.body.removeChild(ifr); }, 300); } 举个栗子: ${universalLink} = 'http://myapp.com' ${scheme} = 'myapp://index'
解释一下上面的代码,如果是iOS9及以上的iOS系统,直接跳转到调起app的universal link。如果是安卓或者iOS9一下的iOS系统,就新建一个iframe,把这个iframe的src弄成调起app的scheme,然后把这个iframe直接塞到页面的DOM树上,然后『听天由命』就行。
iOS的调起
iOS是使用universalLink(下面简称ulink)的方式来进行调起。具体系统内部的机制就不说了,网上一堆文章,随便搜一下就行。
universalLink其实就是一个正常的http请求的url。我们在h5页面使用 location.href=XX进行调起的时候,如果说调起成功了,那么其实这个url是不会被访问的,抓包也抓不到。换句话说,如果我们访问到这个url了,说明我们的调起失败了。
iOS如何实现【安装了调起,没有安装跳下载页或其他页面】
上面说了,iOS下调起失败后,会访问到一个url。要实现没有安转跳下载页,那么就直接把ulink对应的链接做成下载页就好了。根据需求,我们还可以将ulink对应的url做成任何页面。但是,如果我们不想要跳转到这个页面,而是跳转到其他页面呢?很简单,叫RD哥哥在通链那个url的服务端加一个302重定向服务就行。
举个栗子,假设我们和后端约定的字段为target,我们使用下面的ulink来调起App。
`http://myapp.com/index?target=${encodeURIComponent('http://m.baidu.com')}`
调起失败后,上面那个ulink会被浏览器访问到,由于服务端加了重定向服务,我们最终会访问到target对应的地址,即 http://m.baidu.com。这样,我们就实现了【调起失败时,跳转到其他页面】。其实,这个重定向服务还能做很多事情,继续往下看。
iOS如何实现【安装了调起,没有安装时,在当前页面继续进行其他操作】
两种方法:
一、需要后端重定向服务,我们只需要把上面重定向的链接换成一个scheme就行了。这种方法适用于页面必须要用户点击才能触发的交互,比如视频、音频的播放等。(另:微信下可以通过监听jsbridge ready的事件,自动播放视频、音频)
这个scheme需要满足以下的要求:
- 可以被当前浏览器识别
- 浏览器识别了这个scheme,但是不会进行任何其他操作。
如果这个scheme同时满足了上述两个条件,那么体验就是最好的。否则,可能就会出现浏览器弹框等问题。
举几个scheme的例子
... facetime:// (iOS11以下体验完美,之后的版本会直接拉起facetime--) ucbrowser:// ...
二、需要后端重定向服务,我们需要把重定向链接换成【当前链接后加一个特殊参数】的链接。这样在前端代码里就可以判断url里面的特殊参数,从而得知当前页面是拉起app失败时进入的。
iOS调起的注意事项
- 2018年初,iOS微信下全面封禁了universalLink,所以在微信下是调不起app的,暂时是没有什么办法。这种时候,一般可以提示用户,从浏览器打开。当然,也可以找微信开白名单,直接用微信的能力去拉起。
- 其实iOS下用scheme也是可以调起的,比如 window.location.href = scheme 但是这样有个问题,如果说没有安装对应的app,在safari下会弹窗:无法识别该链接,并且就算安装了该app,也会弹一个窗让你确认是否调起 。
- 要在页面使用ulink拉起app,不仅要客户端以及服务端支持,还需要满足以下几个条件:1、当前页面的url和ulink必须跨域。2、ulink要为https协议。3、必须要有用户的点击操作。
Android的调起
安卓的调起是用iframe的方式(其实现在的高版本安卓也可以直接window.location.href=scheme)。
安卓调起的最大的特点就是,安卓无法知道是否成功调起了app。安卓下的调起一般都会有自带的兜底策略,比如下载。代码也很简单
var ifr = document.createElement('iframe'); ifr.src = ${scheme}; ifr.style.display = 'none'; document.body.appendChild(ifr); window.setTimeout(function () { document.body.removeChild(ifr); // 这里写兜底策略的逻辑,比如下载。 // 当然,也可以不加任何的兜底策略,调不起就算了。 window.location.href = ${下载地址} }, 300);
如果想要实现【安装了app调起,没有安装app下载】的功能,那么肯定会调起和下载的逻辑同时执行,因为安卓无法知道是否成功调起app。
安卓的调起是很灵活的,你可以任意控制兜底策略的逻辑,想干嘛干嘛。只是说,兜底策略是几乎一定会执行的,不管你调起成功还是失败。
Android调起注意事项
各种浏览器的屏蔽
很多浏览器都对scheme做了屏蔽。所以安卓下调不起app是一件十分正常的事情。
微信下调起
微信太封闭了,自然屏蔽了非自家app的调起。只新建一个iframe的方式在微信下是不能调起的。微信针对webview调起app的策略也一直在修改。最新(2018年3月19日)的想要在微信的webview下调起app的方式是:
- 手机上必须安装应用宝
- 使用下面的方式,跳转到微信内的应用宝页面进行调起。
window.location.href ='http://a.app.qq.com/o/simple.jsp?pkgname=${pkgname}&android_scheme= encodeURIComponent(${scheme})'
${pkgname}表示app的包名,比如'com.myapp',${scheme}表示调起的scheme
Android下判断是否调起成功
其实有一种方法可以判断安卓下是否调起成功。执行调起逻辑后,设一定的延时判断当前页面是否可见,若不可见了,几乎就可以确定是调起成功了。但是只对小部分浏览器有效(比如安卓下的chrome)。对大多数浏览器而言,调起成功后,会有一个弹框,需要用户点击确定后,才能唤起app。由于这个弹框的存在,就无法通过页面是否可见的方法来判断调起成功与否了。而chrome下,调起成功直接唤起app,是不会弹窗的,所以chrome下可以用延时+页面是否可见的方式来判断调起成功与否。