最近遇到一个需求,须要在从APP分享出去的H5页面中,带有一个当即打开的按钮,若是本地安装了app,那么就直接唤起本地的app,若是没有安装,则跳转到下载。这是一个很正常的推广和导流量的策略。前端小白历来没有作过这个需求,只能开始哼唧哼唧地开启本身的度娘和谷歌之旅。javascript
通过一段时间的探索之旅发现里面的学问不少,要作一个兼容性很好的方案,就须要考虑各类状况,在不一样的状况适配不一样的方案,比方说用户是在手机浏览器打开仍是微信中打开,或者是在pc中打开,universal腾讯应用宝直接打开 APP link是否被关闭等,这就使代码实现变得复杂,且容易出错,且还有安卓平台机型众多、浏览器众多等致使的兼容问题。因为时间有限,此次主要先介绍一个比较广泛的使用URL Scheme进行App跳转的方法。html
通常来讲,咱们使用的智能设备上有许多咱们的我的信息。好比:联系方式、银行卡/信用卡信息、支付宝/Paypal/各大商城的帐户密码、照片甚至行程与位置信息等。前端
若是说,你设备上的每个应用,不论是官方的仍是你从任何商城安装的应用均可以随意地获取这些信息,那么你轻则收到骚扰信息和邮件、重则后果不堪设想。如何让这些信息不被其它应用随意使用,或者说,如何让这些信息仅在设备全部者本人知情并容许的状况下被使用,是全部智能设备与操做系统所要在意的核心安全问题。针对这个问题,苹果使用了名为「沙盒」的机制:应用只能访问它声明可能访问的资源。一切提交到 App Store 的应用都必须遵照这个机制。java
在安全方面沙盒是个很好的解决办法,可是有些矫枉过正。敏感的我的信息咱们不肯意透露,却不表明全部的信息咱们都不想与其它应用共享。所以,咱们急须要一个辅助工具来帮助咱们实现应用通讯, URL Schemes 就是这个工具。ios
[scheme]://[host]/[path]?[query]
咱们拿 https://www.baidu.com 来举例,scheme 天然就是 https 了,后面拼接的是传递的参数。URL Schemes 没有特别严格的规范,因此后面参数的具体定义是app开发者去自定义。web
就像给服务器资源分配一个 URL,以便咱们去访问它同样,咱们一样也能够给手机APP分配一个特殊格式的 URL,用来访问这个APP或者这个APP中的某个功能(来实现通讯)。APP得有一个标识,好让咱们能够定位到它,它就是 URL 的 Scheme 部分。浏览器
可是,二者还有几个重要的区别:安全
前面普及了一下URL Schemes的相关知识,做为个前端开发者,就不去深究其中的原理,都交给app开发者吧。接下来开始咱们的正题。首先固然是要客户端提供App的Url Schemes。服务器
在浏览器中打开 scheme 就像打开一个不一样的http地址同样。能够在一个 a 标签中打开。微信
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>打开App</title> </head> <body> <a href="luwei://" id="open">打开应用</a> </body> </html>
点击上面的H5页面中的连接将会尝试唤醒对应app,在一些浏览器中,可能会弹出一个提示框,询问用户是否容许打开应用。
若是打开的 scheme 在本地没有对应的 app,则点击不会反应。
固然还可使用 JavaScript 代码打开,只须要添加相应的事件触发和处理便可。
在JavaScript代码中打开链接有如下几种方式:
// 打开url的方式 var urlOpen = { // 在ios支持很差 'iframe' : function(url) { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = url; document.body.appendChild(iframe); }, 'location' : function(url) { window.location.href = url; }, 'href' : function(url) { var a = document.createElement('a'); a.style.display = 'none'; a.href = url; document.body.appendChild(a); a.click(); }, 'script' : function(url) { var script = document.createElement('script'); script.setAttribute('type', 'test/javascript'); script.innerHTML = '(function(){' + 'var a = document.createElement("a");' + 'a.style.display = "none";' + 'a.href = "' + url.replace(/"/g, '\\"') + '";' + 'document.body.appendChild(a);' + 'a.click();' + '})()'; document.body.appendChild(script); }, 'open' : function(url) { window.open(url); } };
以上方法是只是解决了在已安装App设备唤醒App的功能,并不能判断是否已安装App,没有安装即跳转至下载连接。
在浏览器其实是没有能力判断手机里是否安装了某个App的,因此只可以采起一种投机取巧的方式。
在JavaScript中判断页面是否进入后台来判断打开成功。Html5提供了下列事件和属性能够利用:
上面这些事件或者属性并非全部浏览器都支持。下面是一个给出为id为openBtn 的按钮添加打开scheme或者下载事件的例子,但对于Android 4.4版本如下则不支持
var downloader, scheme = 'luwei://', // 须要打开的app scheme 地址 iosDownload='http://xxx.com'; // 若是打开scheme失效的app下载地址 andDownload = 'http://xxx.com'; var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //g var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 // 给 id 为 openBtn 的按钮添加点击事件处理函数 document.getElementById('openBtn').onclick = function () { window.location.href = scheme; // 尝试打开 scheme // 设置3秒的定时下载任务,3秒以后下载app downloader = setTimeout(function(){ if(isAndroid) { window.location.href = andDownload; } if(isIOS) { window.location.href = iosDownload; } }, 3000); }; document.addEventListener('visibilitychange webkitvisibilitychange', function () { // 若是页面隐藏,推测打开scheme成功,清除下载任务 if (document.hidden || document.webkitHidden) { clearTimeout(downloader); } }); window.addEventListener('pagehide', function() { clearTimeout(downloader); });