h5喚起app方法

一、引言

有這么一個需求,點擊h5頁面上的一個按鈕,需要判斷本機(jī)有沒有安裝某app,若已經(jīng)安裝過,則直接調(diào)起此app,若沒有安裝,則跳轉(zhuǎn)該app的下載頁。要求安卓手機(jī)跳轉(zhuǎn)此app的下載包地址。ios跳轉(zhuǎn)此app的APP Store。

二、喚起方法

URL Schemes

[scheme:][//authority][path][?query][#fragment] 比如:app://weixin?test=1
  
   行為(應(yīng)用的某個功能)    
            |
scheme://[path][?query]
   |               |
應(yīng)用標(biāo)識       功能需要的參數(shù)

URL Schemes:好比給手機(jī)APP分配一個特殊格式的 URL,用來訪問這個APP或者這個APP中的某個功能(來實現(xiàn)通信)。APP得有一個標(biāo)識,好讓我們可以定位到它,它就是 URL 的 Scheme 部分。

*注意:應(yīng)用是否支持URL Schemes要看App開發(fā)者有沒有寫那部分的代碼了

Intent

安卓的原生谷歌瀏覽器從chrome25版本之后就不能通過URL Schemes喚醒安卓應(yīng)用。要使用谷歌官方提供的intent:預(yù)發(fā), 如果喚醒失敗,則會跳轉(zhuǎn)到谷歌的應(yīng)用市場。語法與URL Schemes及其相似,相當(dāng)于谷歌定制版的URL Schemes,也沒用過,就不多說。

IOS Universal Link

  • 簡介

    Universal Link是在iOS9引入的新功能,通過傳統(tǒng)的HTTP鏈接就可以喚醒a(bǔ)pp,如果用戶沒有安裝APP,則會跳轉(zhuǎn)到該鏈接對應(yīng)的頁面,而且在喚醒a(bǔ)pp的時候沒有彈框提示哦。可以說是解決了URL Schemes的大部分問題。

  • 原理及流程

    1. App開發(fā)人員去配置中心配置Associated Domain配置一個支持https的域名,比如app-support.test.com - 然后 app-support.test.com/apple-app-site-association或者app-support.test.com/apple-app-site-association/.well-known/apple-app-site-association要返回app的teamId,bundleId,paths信息.

      router.get('/apple-app-site-association, (req, res) => {
        const data = {
          applinks: {
            apps: [],
            details: [
              {
                appID: 'teamId.bundleId',
                paths: ['*']
              }
            ]
          }
        };
        res.set('Content-Type', 'text/html');
        res.send(JSON.stringify(data));
      });
      
      
      
    2. 然后APP安裝后首次打開,如果Associated Domain配置了的話,就會去請求app-support.test.com/apple-app-site-association。系統(tǒng)會根據(jù)返回的teamId,bundleId,paths知道當(dāng)打開app-support.test.com下的哪些路徑的時候喚醒對應(yīng)的app,比如paths=*的話,就是打開app-support.test.com下的任意路徑都會喚醒a(bǔ)pp

    3. app那邊會收到對應(yīng)的路徑,然后要根據(jù)path寫邏輯跳轉(zhuǎn)到對應(yīng)的功能

  • 如何驗證配置成功

    在備忘錄中輸入配置好的鏈接,直接點開這個鏈接(https://app-support.test.com),配置好的話會直接跳到app, 或者長按,彈出菜單中會提示在xxx中打開 - 在safari中。

三、常見喚醒媒介

  • iframe
ifr = document.createElement("iframe");
ifr.setAttribute("src", "wrjk://com.eko123"); /***打開app的協(xié)議,有an同事提供***/
ifr.style.display = "none";
document.body.appendChild(ifr);

iframe方案的喚起原理是: 程序切換到后臺時,計時器會被推遲(計時器不準(zhǔn)的又一種情況)。如果app被喚醒那么網(wǎng)頁必然就進(jìn)入了后臺,如果用戶從app切回來,那么時間一般會超過2s;若app沒有被喚起,那么網(wǎng)頁不會進(jìn)入后臺,setTimeout基本準(zhǔn)時觸發(fā),那么時間不會超過2s。

在未安裝 app 的情況下,不會去跳轉(zhuǎn)錯誤頁面。但在各個系統(tǒng)及應(yīng)用中兼容性比較多。例如:ios9+ 禁止掉了iframe方式。

  • a 標(biāo)簽

    a = document.createElement("a");
    a.setAttribute("href", "wrjk://com.eko123"); /***打開app的協(xié)議,有an同事提供***/
    a.style.display = "none";
    document.body.appendChild(a);
    

    a標(biāo)簽如果目標(biāo)scheme錯誤,即應(yīng)用不存在也不會報錯

  • window.location跳轉(zhuǎn)

    window.location.href = "wrjk://com.eko123";
    

    兼容性:URL Scheme 在 ios 9+ 上諸如 safari、UC、QQ瀏覽器中, iframe 均無法成功喚起 APP,只能通過 window.location 才能成功喚端。(本人沒測試過,摘自別人的帖子)

三種喚醒媒介對比

某篇博文中對三種喚起方式進(jìn)行了測試

。X表示喚起失敗,√表示喚起成功
。紅色標(biāo)記表示進(jìn)入頁面直接喚起,綠色表示人工事件操作后喚起
。ios測試機(jī):iphone 6p;android測試機(jī):小米1s
  • iframe喚起app測試結(jié)果

    14657587-3a6cae2885fc2d63.jpg

  • a標(biāo)簽喚起app測試結(jié)果

    14657587-e4d90cde88ffa81a.jpg

  • iframe和window.location.href喚起對比

    14657587-5dd8cd13b99d7511.jpg

  • iframe、window.location.href和a標(biāo)簽喚起三者對比

    14657587-5abb787d252c9169.jpg

四、總結(jié)

  1. 對于ios來說,location.href跳轉(zhuǎn)更合適,因為這種方式可以在Safari中成功喚起app。Safari作為iphone默認(rèn)瀏覽器其重要性就不用多說了。
  1. 對于Android來說,在進(jìn)入頁面直接喚起的情況下,iframe和location.href是一樣的,但是如果是事件驅(qū)動的喚起,iframe喚起的表現(xiàn)比location.href要更好一點。
  1. 通過測試可以發(fā)現(xiàn),進(jìn)入頁面直接喚起和事件驅(qū)動的喚起,對于很多瀏覽器,兩者的表現(xiàn)是不同的,簡單來說,直接喚起的失敗更多。
  1. 以上測試可能隨時間已經(jīng)有出入和變化,僅供參考。

五、使用中常見問題及解決方案

  1. 問題:可能會被app禁掉,比如微信,qq等

    解決:通常會檢測打開的app環(huán)境,如果是微信,qq等環(huán)境,提示用戶瀏覽器內(nèi)打開。

  2. 問題:ios9+ 禁止掉了iframe方式。

    解決:通常會檢測ios的版本,ios9+不使用iframe方式,或直接用window.location.href.

  3. 問題:h5無法感知是否喚醒成功.

    解決:一段時間之后自動跳轉(zhuǎn)下載頁,或者是依賴setTimeout在瀏覽器進(jìn)入后臺后進(jìn)程切換導(dǎo)致的時間延遲判斷。

  4. 問題:大部分瀏覽器需要用戶手動觸發(fā)鏈接,js自動觸發(fā)無效。

    解決:瀏覽器機(jī)制,可以設(shè)置彈框不在顯示。


實際應(yīng)用

之前已經(jīng)介紹了要實現(xiàn)的需求,讓我們一步一步來吧。我應(yīng)用的是URL Schemes喚起方法,其實最完美的方案是IOS Universal Link,因為這個方法需要app那邊配置很多東西,配置好后給前端提供一個地址調(diào)用。首先要獲取訪問設(shè)備的信息,代碼如下:

let globalData = {
  isMobile: false,//是否為移動端
  openIn: '',//頁面打開的app
  openInType: '',//移動端設(shè)備的類型 ios an
  isHW: false,//是否為華為瀏覽器
}
var browser = {
  versions: function () {
    var u = navigator.userAgent, app = navigator.appVersion;
    return {         //移動終端瀏覽器版本信息
      trident: u.indexOf('Trident') > -1, //IE內(nèi)核
      presto: u.indexOf('Presto') > -1, //opera內(nèi)核
      webKit: u.indexOf('AppleWebKit') > -1, //蘋果、谷歌內(nèi)核
      gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐內(nèi)核
      mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否為移動終端
      ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios終端
      android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android終端或uc瀏覽器
      iPhone: u.indexOf('iPhone') > -1, //是否為iPhone或者QQHD瀏覽器
      iPad: u.indexOf('iPad') > -1, //是否iPad
      webApp: u.indexOf('safari') == -1, //是否web應(yīng)該程序,沒有頭部與底部
      //DF:u.indexOf('DF'),//是否是mmc app端
    };
  }(),
  language: (navigator.browserLanguage || navigator.language).toLowerCase(),
}
if (browser.versions.mobile) {//判斷是否是移動設(shè)備打開。browser代碼在下面
  globalData.isMobile = true;
  var ua = navigator.userAgent.toLowerCase();//獲取判斷用的對象
  console.log(ua + '=============ua對象');
  if (ua.match(/MicroMessenger/i) == "micromessenger") {
    //在微信中打開
    globalData.openIn = 'weixin';
  }
  if (ua.match(/WeiBo/i) == "weibo") {
    //在新浪微博客戶端打開
    globalData.openIn = 'weibo';
  }
  if (ua.match(/ qq\//i) == " qq/") {
    //在QQ空間打開
    globalData.openIn = 'qq';
  }
  if (ua.match(/huawei/i) == 'huawei') {
    globalData.isHW = true;
  }
  if (browser.versions.ios) {
    //是否在IOS瀏覽器打開
    globalData.openInType = 'ios';
  }
  if (browser.versions.android) {
    //是否在安卓瀏覽器打開
    globalData.openInType = 'android';
  }
} else {
  //否則就是PC瀏覽器打開
  globalData.isMobile = false;
}

我定義了一個全局對象globalData,用來存儲設(shè)備信息,有個屬性isHW,是因為華為瀏覽器和其他安卓設(shè)備又有些不同,故區(qū)分出來單獨處理。

此上是設(shè)備判斷的邏輯,能夠得到是pc端打開還是移動端,移動端打開app是什么app(例如:微信,微博,qq等),移動端設(shè)備的類型是 ios 還是 an,以及是否是華為手機(jī)。

下面就來寫調(diào)起的程序了。

//喚起app或跳轉(zhuǎn)下載頁
function applyApp(){
  if (globalData.isMobile && globalData.openInType == "android") {
    //判斷是否是會屏蔽下載鏈接的app打開
    if (
      globalData.openIn == "weixin" ||
      globalData.openIn == "weibo" ||
      globalData.openIn == "qq"
    ) {
      //Toast("請將鏈接復(fù)制到瀏覽器中打開");
      $('.mask').show();
      return;
    } else {
      if (globalData.isHW) {
        window.location.href = "wrjk://com.eko123.manmachine/startapp";
      } else {
        ifr = document.createElement("iframe");
        ifr.setAttribute("src", "wrjk://com.ekao123.manmachine/startapp"); /***打開app的協(xié)議,有an同事提供***/
        ifr.style.display = "none";
        document.body.appendChild(ifr);
      }
      timer = setTimeout(function () {
        location.;
      }, 5000);
    }
  }
  if (globalData.isMobile && globalData.openInType == "ios") {
    if (
      globalData.openIn == "weixin" ||
      globalData.openIn == "weibo" ||
      globalData.openIn == "qq"
    ) {
      //Toast("請將鏈接復(fù)制到瀏覽器中打開");
      $('.mask').show()
      return;
    } else {
      var loadDateTime = new Date();
      window.location = "com.ht.yiqikao://";//schema鏈接或者universal link
      window.setTimeout(function() { //如果沒有安裝app,便會執(zhí)行setTimeout跳轉(zhuǎn)下載頁
        var timeOutDateTime = new Date();
        if (timeOutDateTime - loadDateTime < 2000) {
          window.location = "https://itunes.apple.com/cn/app/id1422958471?l=zh&ls=1&mt=8"; //ios下載地址  
        } else {
          window.close();
        }
      }, 2000);
    }
  }
}

至此,喚起app的需求就完成了,僅供大家參考,若有更好的方法,歡迎留言交流。

本文部分內(nèi)容參考自:http://m.itdecent.cn/p/500f4be528e3

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容