Skip to content

H5唤起APP的小结[每天进步一点点系列] #32

@stuxt

Description

@stuxt

背景

最近在做DeepLink的需求,DeepLink不算是一个新话题了,但是却一直都没间断过讨论。开始接触之前了解并不是很多,但是接触下来发现也就那几种实现方式。

什么是DeepLink呢?其实就是H5页面提供一个按钮,例如:“打开APP”或者“下载APP”等。在H5页面中点击这个按钮,如果安装了目标APP直接通过链接唤起,否则跳转到下载页面去下载APP。这种通过H5唤起APP的链接的方式就是DeepLink。

看起来很简单的一个业务流程,但是实现起来还是有很多坑的,主要是因为设备、设备版本、浏览器等碎片差异严重,导致很多兼容需要处理。

最终实现的效果

用户点击H5页面的打开App或者下载按钮(这个按钮可能在一个下载入口页、各种分享页面的吸顶或吸底的banner),如果用户已经安装了App,则根据业务跳转到相应的Native页面;如果用户没有安装该应用,则跳到AppStore或者应用市场去下载App。

default
图1:各种实现方式

已安装APP时的实现方式

一、iOS中的实现

iOS中在IOS9.0前后是一个分界点,因为从iOS9.0之后苹果开放universal link的方式代替schema的方式来唤起APP。下面我们就分别从iOS9.0前后分别来说:

1、iOS9.0之前

iOS9.0之前苹果和安卓的实现方式都是通过schema的方式来实现的。但是跳转方式也有很多种(window.location.href方式、a链接方式、iframe方式等),经过测试和查阅资料发现,iOS9.0之后的跳转方式选择iframe的方式是最靠谱的方式。代码如下所示:

function openOrDownload() {
		var ifr = document.createElement('iframe');
    		ifr.src = 'test.1234://deeplink?token=1111111';
    		ifr.style.display = 'none';
    		document.body.appendChild(ifr);
}

2、iOS9.0+

iOS9.0+后的版本的苹果设备,开始支持universal link的实现方式,当然schema的方式也是被支持的,只不过在遇到未安装的时候会弹出一个丑陋的错误提示框,即使安装了也还是会弹窗询问用户是不是要打开APP,用户体验不好。

universal link的实现方式在网上有很多很详尽的说明和示例,此处不做详细说明。

当然,universal link的实现方式需要客户端和服务端的配合。

对于跳转方式iOS9.0+后选用a链接的方式最靠谱,iframe的方式已经无法使用了。a链接的示例代码如下所示:

        let t = document.createElement("a");
        iframeState = t;
        t.style.display = "none";
        t.href = url;
        document.body.appendChild(t);
        t.click();

二、Android中的实现

安卓中的实现方式比起苹果设备来看要更加复杂一点,因为有一些过长的浏览器总是奇葩的存在(如:UC)。
但是在安卓中目前schema是实现的主要方式,跳转方式通过测试,也是iframe的方式最靠谱。实现方式如上面iframe实现方式所示。

未安装的实现方式

因为在H5中是无法获取到设备中app的安装情况,无法判断是否安装,只能采用尝试打开的方式,如果已经安装则直接打开,如果未安装,通过时间差的方式来判断做出跳转到下载页面的操作。

其实,这个过程中还是存在一些坑的,比如跳转到app了,返回H5页面后还是会跳转到下载页面,因为浏览器差异兼容情况不一,始终没有完美的方案,只能通过如下方式尽量来兼容。

实现代码如下所示:

        var o = setTimeout(function() {
		    	document.body.removeChild(ifr);
		        document.hasFocus() && (window.location = 'http://www.baidu.com')
		    }, 1000);

	var hidden,
            visibilityChange;
	        if (typeof document.hidden !== "undefined") {
	            hidden = document.hidden;
	            visibilityChange = "visibilitychange";
	        } else if (typeof document.mozHidden !== "undefined") {
	            hidden = document.mozHidden;
	            visibilityChange = "mozvisibilitychange";
	        } else if (typeof document.msHidden !== "undefined") {
	            hidden = document.msHidden;
	            visibilityChange = "msvisibilitychange";
	        } else if (typeof document.webkitHidden !== "undefined") {
	            hidden = document.webkitHidden;
	            visibilityChange = "webkitvisibilitychange";
	        } else {
	            hidden = false;
	        }

	        document.addEventListener(visibilityChange,
	            function() {
	                 clearTimeout(o);
	            },
	        !1)

通过上面的实现方式可以兼容大部分,但是有些还是有问题,iOS下的safari就有问题,可以再加上如下代码,safari问题就可以解决了,代码如下:

        /**
         * 兼容safari 唤醒APP后仍跳转下载页面的问题
         */
        window.addEventListener("pageshow", function(evt){
            clearTimeout(o);
        }, false);

        window.addEventListener("pagehide", function(evt){
            clearTimeout(o);
        }, false);

微信、QQ等的实现方式

目前所有的直接再微信里面跳转APP的方式都已经行不通了,只有两种处理方式:1、提示在浏览器打开 2、通过应用宝来打开。

QQ、微博等,都是差不多的,具体没有一一测试,但是腾讯系的都可以通过应用宝的方式解决,其他的就提示浏览器打开吧。

基本H5唤起APP的大概的实现方式已经做了简单的介绍。

最后再吐槽一个莫名其妙的坑,就是ios中在safari中使用schema打开应用,应用没有安装的时候,会跳转App Store,如果第一次提示打开App Store时,选择“取消”,那么再点击的时候是无法跳转到App Store的,具体不知道苹果是怎么想的。

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions