H5页面中唤起native app

如今各种app,分享出去的H5页面中,通常都会带着一个当即打开的按钮,若是本地安装了app,那么就直接唤起本地的app,若是没有安装,则跳转到下载。这是一个很正常的推广和导流量的策略,最近产品经理就提出了这样的一个需求,作一个像今日头条功能同样的带打开app的下载条。javascript

实现这个功能,咱们须要解决两个问题
一、js如何唤起本地app
二、js如何知道手机已经安装了对应的应用php

js如何唤起本地appcss

既然是经过网页调用app,这个固然涉及到与app的通讯。经过咨询ios和android的同事,ios与android都支持一种叫作schema协议的连接。这种协议的相似于咱们熟悉的http协议,咱们只要跟app协商好协议头,app经过拦截到这个协议头的请求就能够知道有网页要求调用。而对于js来讲,咱们这要像a标签的href同样来激活这个协议的连接就好了。html

好比:java

<a href="myapp://">调起app</a>


这种方式ios和android均可以共用android

二、如何知道手机已经安装的对应的应用对于这个功能的实现,首先想到的是查询应用是否存在,可是这种方法显而易见是行不通的,好比说你在UC浏览器,微信中,咱们没法主动的去查询咱们系统中是否安装了该应用。因此这个判断是没法实现。因此咱们就须要采用曲线救国的方式来实现。既然咱们能够唤起app,那咱们就能够忽略判断,直接唤起app,若是用户没有安装,咱们作一个容错处理。ios

结合这个思路,咱们基本能够获得咱们的实现方案
web

var iframe = document.createElement('iframe');
var body = document.body;
iframe.style.display = "none";
ar timer = null;

var openapp = document.getElementById('openapp');
openapp.addEventListener('click', function() {
body.appendChild(iframe);
iframe.src = "appschema://";
timer = setTimeout(function() {
wondow.location.href = "download.html"; //容错的下载页面
}, 500);
}, false)

写完代码,作了测试,发现这样的实现有不少问题
一、微信没法调起。微信对于连接的跳转限制很严重,不少下载外链都引导到浏览器打开
二、调起app返回浏览器的时候,会跳转到下载页面,既然用户已经下载了app,再让页面跳转到下载页很不友好
三、ios9+的safari没法经过iframe跳转到其余页面浏览器

有问题就须要解决微信

一、对于微信或者QQ空间,在网上查找资料,若是是在应用宝上线的应用,应用宝提供了微下载来实现微信和QQ打开app,先跳转到应用宝的的下载连接,而后下载宝连接会判断打开对应的app,具体参考(http://wiki.open.qq.com/index.php?title=mobile/%E5%BA%94%E7%94%A8%E5%AE%9D%E5%BE%AE%E4%B8%8B%E8%BD%BD)可是应用宝的微下载有个问题,ios微信和QQ中没法打开对应的应用,只是会经过你应用宝配置的appstore下载连接跳转到对应的下载页面,再从appstore里面打开应用。因此这个问题仍是不能彻底解决,只能完美解决android的机器

二、针对问题2,网上有人经过监控页面的pagehide和visibilitychange方法来实现禁止跳转,具体的实现思路是监控页面是否隐藏,利用延时若是页面已经打开app,此时页面会是隐藏状态,触发页面的隐藏事件,clear延时事件,禁止跳转,不过这个方案会出现问题,有一些浏览器在app打开,离开浏览器以后,js事件不在执行,也就是此时没法监控的页面的隐藏,在返回页面的时候,js继续执行,可是事件监控的仍是页面展现的状态,没法clear延时事件,因此该方式没法完美解决这个问题

后来找到了另外的解决方案,调起app须要唤起另外的进程,因此js的进程会挂起,致使先后有一个时间差,记录先后的事件差对比就能够判断是否调起了app了

iframe.src = "appschema://";
var timer = null,
t = Date.now();
timer = setTimeout(function() {
if (Date.now() - t > 1200) {
clearTimeout(timer);
return false;
}
}, 1000);

三、对于问题3,Apple为iOS 9发布了一个所谓的通用连接的深层连接特性,即Universal links。只要在app中受权好域名,在网页中只要打开对应域名连接,都会检测与域名绑定的app是否存在,若是存在,直接调起app,具体参考(http://stackoverflow.com/questions/31891777/ios-9-safari-iframe-src-with-custom-url-scheme-not-working),而且该方法不会被微信拦截,能够在微信中使用,这样也就解决了咱们在腾讯平台下ios没法经过微下载打开的问题

最后再来整理一下咱们的思路
一、ios经过Universal links,针对ios9一下和之前版本没有实现Universal links,在绑定好的域名下作一个中间页,直接跳转到中间页
二、android分平台,若是是微信或者QQ(能够经过用户代理检测),直接经过微下载,其余浏览器,直接用schema协议

具体代码实现以下

var url = {
        open: 'duchuang://',
        down: 'http://a.app.qq.com/o/simple.jsp?pkgname=com.nayun.framework'
    },
    iframe = document.createElement('iframe');
iframe.style.cssText = 'display:none;width=0;height=0';
var timer = null,
    //点击第三方下载
    isAndroid = !!navigator.userAgent.match(/android/ig),
    isIos = !!navigator.userAgent.match(/iphone|ipod/ig),
    isIpad = !!navigator.userAgent.match(/ipad/ig),
    isWeixin = (/MicroMessenger/ig).test(navigator.userAgent),
    isQQ = (/qq/ig).test(navigator.userAgent),
    openapp = document.getElementById('cal-app');
openapp.addEventListener('click', function() {
    if (isIos) {
        window.location.href = "https://appdetail.netwin.cn/download.html"
    }

    if (isAndroid) {
        if (isWeixin || isQQ) { //andorid微信和QQ走微下载
            window.location.href = 'http://a.app.qq.com/o/simple.jsp?pkgname=com.nayun.framework&android_schema=' +  url;
        } else {
            body.appendChild(iframe);
            iframe.src = url.open;
            var t = Date.now();
            timer = setTimeout(function() {
                if (Date.now() - t > 1200) {
                    clearTimeout(timer);
                    return false;
                }
                if (document.webkitHidden || document.hidden) {
                    return false;
                }
                window.location.href = 'http://a.app.qq.com/o/simple.jsp?pkgname=com.nayun.framework';
            }, 1000);
        }
    }
}, false)


document.addEventListener("webkitvisibilitychange", function() {
    var tag = document.hidden || document.webkitHidden;
    if (tag) {
        clearTimeout(timer);
    }
});


window.addEventListener('pagehide', function() {
    clearTimeout(timer);
})
相关文章
相关标签/搜索