最近遇到一個需求,須要在從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); });