iOS中使用schema協議調用APP和使用iframe打開APP的例子

在iOS中,須要調起一個app可使用schema協議,這是iOS原生支持的,而且由於iOS系統中都不能使用本身的瀏覽器內核,因此全部的瀏覽器都支持,這跟android生態不同,android是能夠本身搞內核的,可是iOS不行。php

在iOS中提供了兩種在瀏覽器中打開APP的方法:Smart App Banner和schema協議。html

Smart App Bannernode

即經過一個meta 標籤,在標籤上帶上app的信息,和打開後的行爲,例如:app-id之類的,代碼形如:android

<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">

具體能夠看下開發文檔:https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html
今天Smart APP Banner不是咱們的主角,咱們說的是schemaios

使用schema URL來打開iOS APPweb

schema相似自定義url協議,咱們能夠經過自定義的協議來打開本身的應用,形如:chrome

myapplink://

# 例如 facebook的

fb://

# itunes的

itms-apps://

# 還有短信也是相似的

sms://

若是要打開一個app,最簡單的方式是經過一個連接,如咱們在html中這樣寫:瀏覽器

<a href="myapplink://">打開個人app</a>

當用戶點擊連接的時候就能夠打開對應的app。app

綁定click事件dom

可是實際中咱們更多的狀況是綁定事件,好比作個彈層啥的,不能一味的用a標籤啊,因此能夠經過兩種方式來解決:location.href和iframe。

iframe的方式是開發中經常使用的,可是他也有一些問題:

1.咱們沒很好的方式來判斷是否打開了app
2.會引發history變化
3.由於引發history變化,因此一些webview會有問題,好比:我查查,打開一個頁面,若是有iframe,選擇在safari中打開,實際打開的是iframe的頁面
4.若是頁面暴漏給了android系統,那麼也會出現頁面打不開,之類的問題
5.若是沒有app,調起不成功,ios的safari會本身彈出一個對話框:打不開網址之類的提示

因此如今的問題是:如何知道iframe已經打開了某個app,即解決iframe打開app回調。

使用iframe在iOS系統中打開app

聰明的你可能想到了,iframe的onload事件啊,但是遺憾的說,無效!因此咱們找到了定時器(setTimeout),經過一個定時器,若是在一段時間內(好比500ms),當點擊了按鈕(記錄time1),頁面沒有切走(調起app以後,頁面進程會被中斷),進程中斷,那麼計時器也會中斷,這時候應該不會觸發timer,若是調起失敗,那麼timer會就觸發,咱們判斷下在必定時間內若是頁面沒有被切走,就認爲調起失敗。

另外經過timer觸發時候的timer2,作差,判斷是否太離譜了(切走了以後的時間應該比timer實際定時的500ms要長):

function openIos(url, callback) {

    if (!url) {

        return;

    }

    var node = document.createElement('iframe');

    node.style.display = 'none';

    var body = document.body;

    var timer;

    var clear = function(evt, isTimeout) {

       (typeof callback==='function') &&  callback(isTimeout);

        if (!node) {

            return;

        }

        node.onload = null;

        body.removeChild(node);

        node = null;  
     };

    var hide = function(e){

        clearTimeout(timer);

        clear(e, false);

    };

    node.onload = clear;

    node.src = url;

    body.appendChild(node);

    var now = +new Date();

    //若是事件失敗,則1秒設置爲空

    timer = setTimeout(function(){

        var newTime = +new Date();

          if(now-newTime>600){

            //由於切走了,在切回來須要消耗時間

            //因此timer即便執行了,可是二者的時間差應該跟500ms有較大的出入

            //可是實際並非這樣的!

            clear(null, false);

          }else{

            clear(null, true);

          }

    }, 500);

}

看上去方法很靠譜,可是現實老是那麼的殘酷!

不一樣的瀏覽器app(包括webview),都有本身在後臺的常駐時間,即:假如一個瀏覽器他在被切走以後,後臺常駐10s,那麼咱們設置定時器5s過時就是徒勞的,並且5s的定時器,用戶要空等5s!交互也不讓你這樣幹啊!

最後咱們想到了pageshow和pagehide事件,即若是瀏覽器被切走到了要打開的app,應該會觸發瀏覽器的pagehide事件,而從app從新返回到瀏覽器,就會觸發pageshow方法。

可是通過代碼測試發現,在uc、chrome中,不會觸發pagehide和pageshow的方法,而在safari中能夠的。

結論:

1.使用iframe調用schema URL
2.使用定時器判斷在一段時間內是否調起成功
3.使用pageshow和pagehide來輔助定時器作更詳細的判斷
4.定時器中若是有alert可能不會被彈出,這一點很吃驚!後面的dom居然5.執行了,可是alert沒彈出,可能跟alert的實現有關係吧
6.在實驗中我使用了兩個定時器,是由於切回瀏覽器以後,有時候timeout觸發要在pagehide和pageshow以前
7.計算timer實際執行時間差,也是不靠譜的

最後附上研究的代碼,算是比較靠譜的方法了,雖然仍是有必定的失敗(第三方瀏覽器pagehide和pageshow不觸發):

 <button id="btn">點我點我啊!alert,不會彈出</button> 

 <button id="btn2">點我點我啊!alert2,雖然有alert和info,info執行,可是alert不彈出</button> 

 <button id="btninfo">點我點我啊!info能夠</button>   
 $(function(){ 
   var $info = $('#info'); 
   function info(msg){

    var p = $(' '+msg+' ');

    $info.append(p);

  } 
   $('#btn').on('click', function(){

    openIos('baiduboxapp://', function(t){

      if(t){

        alert('timeout or no baidu APP');

      }else{

        alert('invoke success');

      }

    });

  });

  $('#btn2').on('click', function(){

    openIos('baiduboxapp://', function(t){

      if(t){

        info('timeout or no baidu APP2');

        alert('timeout or no baidu APP2');

      }else{

        info('invoke success2');

        alert('invoke success2');

      }

    });

  });

  $('#btninfo').on('click', function(){

    openIos('baiduboxapp://', function(t){

      if(t){

        info('timeout or no baidu APP');

      }else{

        info('invoke success');

      }

    });

  }); 
 }); 
 function openIos(url, callback) {

    if (!url) {

        return;

    }

    var node = document.createElement('iframe');

    node.style.display = 'none';

    var body = document.body;

    var timer;

    var clear = function(evt, isTimeout) {

       (typeof callback==='function') &&  callback(isTimeout);

        window.removeEventListener('pagehide', hide, true);

        window.removeEventListener('pageshow', hide, true);

        if (!node) {

            return;

        } 
         node.onload = null;

        body.removeChild(node);

        node = null; 
     };

    var hide = function(e){

        clearTimeout(timer);

        clear(e, false);

    };

    window.addEventListener('pagehide', hide, true);

    window.addEventListener('pageshow', hide, true);

    node.onload = clear;

    node.src = url;

    body.appendChild(node);

    var now = +new Date();

    //若是事件失敗,則1秒設置爲空

    timer = setTimeout(function(){

        timer = setTimeout(function(){

          var newTime = +new Date();

          if(now-newTime>1300){

            clear(null, false);

          }else{

            clear(null, true);

          } 
         }, 1200);

    }, 60);

}
相關文章
相關標籤/搜索