h5喚醒APP小記

suan_suan發表於2019-03-26

h5喚醒APP功能

最近遇到一個需求,需要在從APP分享出去的H5頁面中,帶有一個立即開啟的按鈕,如果本地安裝了app,那麼就直接喚起本地的app,如果沒有安裝,則跳轉到下載。這是一個很正常的推廣和導流量的策略。前端小白從來沒有做過這個需求,只能開始哼唧哼唧地開啟自己的度娘和谷歌之旅。

經過一段時間的探索之旅發現裡面的學問很多,要做一個相容性很好的方案,就需要考慮各種情況,在不同的情況適配不同的方案,比方說使用者是在手機瀏覽器開啟還是微信中開啟,或者是在pc中開啟,universal騰訊應用寶直接開啟 APP link是否被關閉等,這就使程式碼實現變得複雜,且容易出錯,且還有安卓平臺機型眾多、瀏覽器眾多等導致的相容問題。由於時間有限,這次主要先介紹一個比較普遍的使用URL Scheme進行App跳轉的方法。

URL Scheme —— 喚端媒介

來源

一般來說,我們使用的智慧裝置上有許多我們的個人資訊。比如:聯絡方式、銀行卡/信用卡資訊、支付寶/Paypal/各大商城的賬戶密碼、照片甚至行程與位置資訊等。

如果說,你裝置上的每一個應用,不管是官方的還是你從任何商城安裝的應用都可以隨意地獲取這些資訊,那麼你輕則收到騷擾資訊和郵件、重則後果不堪設想。如何讓這些資訊不被其它應用隨意使用,或者說,如何讓這些資訊僅在裝置所有者本人知情並允許的情況下被使用,是所有智慧裝置與作業系統所要在乎的核心安全問題。針對這個問題,蘋果使用了名為「沙盒」的機制:應用只能訪問它宣告可能訪問的資源。一切提交到 App Store 的應用都必須遵守這個機制。

在安全方面沙盒是個很好的解決辦法,但是有些矯枉過正。敏感的個人資訊我們不願意透露,卻不代表所有的資訊我們都不想與其它應用共享。因此,我們急需要一個輔助工具來幫助我們實現應用通訊, URL Schemes 就是這個工具。

URL Schemes是什麼

[scheme]://[host]/[path]?[query]

我們拿 https://www.baidu.com 來舉例,scheme 自然就是 https 了,後面拼接的是傳遞的引數。URL Schemes 沒有特別嚴格的規範,所以後面引數的具體定義是app開發者去自定義。

就像給伺服器資源分配一個 URL,以便我們去訪問它一樣,我們同樣也可以給手機APP分配一個特殊格式的 URL,用來訪問這個APP或者這個APP中的某個功能(來實現通訊)。APP得有一個標識,好讓我們可以定位到它,它就是 URL 的 Scheme 部分。

但是,兩者還有幾個重要的區別:

  • 所有網頁都一定有網址,不管是首頁還是子頁。但未必所有的應用都有自己的 URL Schemes,更不是每個應用的每個功能都有相應的 URL Schemes。幾乎沒有所有功能都有對應 URL 的應用。一個 App 是否支援 URL Schemes 要看那個 App 的作者是否在自己的作品裡新增了 URL Schemes 相關的程式碼。
  • 一個網址只對應一個網頁,但並非每個 URL Schemes 都只對應一款應用。這點是因為蘋果沒有對 URL Schemes 有不允許重複的硬性要求,所以曾經出現過有 App 使用支付寶的 URL Schemes 攔截支付帳號和密碼的事件。
  • 一般網頁的 URL 比較好預測,而URL Scheme 因為沒有統一標準,所以非常難猜,通過猜來獲取 應用的 URL Schemes 是不現實的。

前面普及了一下URL Schemes的相關知識,作為個前端開發者,就不去深究其中的原理,都交給app開發者吧。接下來開始我們的正題。首先當然是要客戶端提供App的Url Schemes。

用瀏覽器去開啟scheme

在瀏覽器中開啟 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程式碼中開啟連線有以下幾種方式:

  • 新建一個隱藏的 iframe ,地址指向需要開啟的url
  • 使用 window.location 或者 window.location.href 重新整理當前頁面
  • 新建一個隱藏的 a 標籤,地址指向開啟的url,並觸發開啟連結事件
  • 動態建立一個script指令碼,在這個指令碼中新建一個a標籤並開啟
// 開啟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提供了下列事件和屬性可以利用:

  • pagehide : 頁面隱藏時觸發
  • visibilitychange : 頁面隱藏沒有在當前顯示時觸發(切換tab也會觸發該事件)
  • document.hidden : 當頁面隱藏時,該值為true,顯示時為false

上面這些事件或者屬性並不是所有瀏覽器都支援。下面是一個給出為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);
    });

沒有完美的方案

  • 微信中無法喚醒App,需要“用瀏覽器開啟”是因為微信對所有的分享連結接做了scheme遮蔽,也就是說分享連線中所有對於scheme的呼叫都被微信封掉了。有些app是能在微信開啟是因為微信有一個白名單(有關係就是不錯),對於在白名單中的分享連結是不會遮蔽掉scheme呼叫的。
  • 本文只是小小地拋個磚,介紹了一種比較常用簡單的方法去喚醒app,該方案相容性不是特別好吧。要做出一個比較完美的方案還需要細細去鑽研,還需要不停地去搬磚~不說了,搬磚去了~

相關文章