手记

H5页面拉起第三方App

背景

在H5页面或者app的webview中调起第三方app

本文是2018年的旧文

核心

调起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重定向服务就行。

举个栗子,我们使用下面的ulink来调起App。

http://myapp.com/index?target=encodeURIComponent('http://www.baidu.com');

调起失败后,上面那个ulink会被浏览器访问到,我们在服务端加了重定向服务,我们最终会访问到target对应的地址,即 http://www.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,也会弹一个窗让你确认是否调起 。
  • 虽说iOS的通链是一个url,但是也不是直接粘贴到safari等浏览器下访问就能直接调起app。因为iOS的通链调起必须要求有用户操作,比如点击等行为。可以将链接粘贴到iOS的备忘录上,点击这个链接就可以直接调起了。

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

安卓下判断是否调起成功

其实有一种方法可以判断安卓下是否调起成功。执行调起逻辑后,设一定的延时判断当前页面是否可见,若不可见了,几乎就可以确定是调起成功了。但是只对小部分浏览器有效(比如安卓下的chrome)。对大多数浏览器而言,调起成功后,会有一个弹框,需要用户点击确定后,才能唤起app。由于这个弹框的存在,就无法通过页面是否可见的方法来判断调起成功与否了。而chrome下,调起成功直接唤起app,是不会弹窗的,所以chrome下可以用延时+页面是否可见的方式来判断调起成功与否。

3人推荐
随时随地看视频
慕课网APP