h5啓動原生APP總結

許久沒有寫博客了,最近有個H5啓動APP原生頁面的需求,中間趕上一些坑,看了些網上的實現方案,特地來總結下javascript

1、須要判斷客戶端的平臺以及是否在微信瀏覽器中訪問前端

一、客戶端判斷java

在啓動APP時,Android和IOS系統處理的方式是不同的,Android這邊因爲開放,能夠在瀏覽器中經過<a>標籤以及meta標籤的方式,讓瀏覽器app獲取手機打開應用的權限進而啓動APP。android

而在IOS這邊,IOS9之後的系統,則能夠在APP開發過程當中加入配置和邏輯代碼編寫,系統在瀏覽器即將訪問到某個域名前就把這個域名對應的APP打開,這個有點閃,封閉仍是有封閉的好處。ios

因此首先要在客戶端判斷,是Android系統仍是IOS系統,判斷代碼以下後端

function isInIos(){
    var userAgentInfo = navigator.userAgent ,
        Agents = ["iPhone" , "iPad", "iPod"];
    for(var v = 0; v < Agents.length; v++) {
        if (userAgentInfo.indexOf(Agents[v]) > 0) {
          return true;
        }
    }
    return false;
}        

二、是否在微信內置瀏覽器中瀏覽器

不管是在哪一個平臺的客戶端Android/IOS,在微信的平臺上訪問都有一個問題,那就是沒法啓動客戶端,這是微信爲了安全性考慮的限制,android這邊屏蔽schema協議,除非公司是微信的夥伴加入了白名單才能安全

使用,IOS系統能夠去訪問app對應appstore的下載頁,可是微信常常屏蔽appstore的這個網址,進而訪問不到。比較方便的作法就是在微信瀏覽器中,不管是IOS仍是android都去應用寶的下載(IOS 這邊最後會到微信

appstore中)頁面打開。我這邊的需求是提示用戶點擊「...」用默認瀏覽器打開。app

判斷是不是在微信中,代碼以下:

function isInWx(){
    var agent = window.navigator.userAgent.toLowerCase();
    return agent.match(/MicroMessenger/i) == 'micromessenger';
}

 

 

2、原理

首先不管是andorid仍是IOS端,在瀏覽器中經過JS都是沒法判斷該手機是否裝有某APP的,即便這個瀏覽器有權限讀取手機應用列表,也沒有一個固定的對外API讓我們進行查詢。而H5啓動APP本質上是經過

URL scheme打開APP,一個APP能夠設置一個或多個打開本身的URL scheme,瀏覽器去訪問某一個APP的URL scheme,而後若系統安裝有這個APP,則會請求權限去打開這個APP。其實也算是瀏覽器app

打開另外一個app,iOS就可使用 UIApplication 的 canOpenUrl 方法來檢測URL scheme 是否能打開對應的APP,而android也是相似的方式。固然若是JS跳轉URL scheme沒有反應,也意味着這個手機沒有

裝這個app。

 

3、android平臺

首先編輯AndroidManifest.xml,主要是增長第二個<intent-filter>

<activity android:name=".activity.LoadingActivity"
      android:label="${APP_NAME}"
      android:screenOrientation="portrait"
      android:theme="@style/FirstActivityTheme">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      <intent-filter>
          <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="android.intent.category.BROWSABLE" />
      <data android:host="android"
                android:scheme="wushang" />
      </intent-filter>
</activity>

好比此處wushang就是scheme,這個最好是app的惟一標識符,要否則在H5喚醒時,會出現一個選擇框,選擇啓動哪個APP。而host表示啓動該頁面,其實這個更應該用com.android.sky這樣的包名來替代更好。

這樣的狀況完整的URL就是wushang://android?data=sky,後面是參數傳遞。在Activity中能夠用以下代碼獲取參數

public void onCreate(Bundle savedInstanceState) {             
     Uri uridata = this.getIntent().getData();             
     String mydata = uridata.getQueryParameter("data");            
}

以後在進行字符串截取仍是什麼鬼的都隨意啦。

 

接下來來談談前端代碼,這裏有兩種狀況

一、頁面在刷新進入時,請求權限喚起APP

這個比較簡單,就只用在頁面的頂部head中加入meta標籤便可

<meta http-equiv="refresh" content="0;url=wushang://android?data=sky">

這個標註當頁面刷新即去訪問這個連接,進而啓動APP。可是存在一個問題,若是是蘋果系統的Safari瀏覽器的話,訪問有這個meta的頭,會給出錯誤提示,因此這個頭部能夠在後端進行頁面渲染時經過客戶端的

總類在加上去。

二、經過點擊事件喚起APP

最簡單的辦法固然是直接使用a標籤,以下

<a href="wushang://android">open Android app</a>

可是在實際使用時,是須要對客戶端的平臺類型還有是否在微信內置瀏覽器中進行判斷的,因此這樣的作法確定是不行的。

接下來談談在開發過程當中,遇到的一個問題,記錄下。由於這邊移動端使用的工具庫庫是zepto,採用的點擊事件是tap,可是在用tap進行處理是常常要點不少下,才能喚起APP

<script type="text/javascript">
  $('#go').tap(function(){
      window.location.href = "wushang://android";
  });
</script>

具體緣由不知,多是tap事件採用的是輕點觸碰。而後摸索了下,才用click事件,或者直接在a標籤上標註處理函數就沒有這問題

<a id="go" >
    open Android app
</a>
<a href="javascript:startApp()">
   open
</a>
<script src="../res/lib/zepto.min.js"></script>
<script src="../res/lib/public.js"></script>
<script>
    $('#go').click(function () {
       if(publicFun.isIos()){
          alert('it is IOS')
       }else{
          window.location.href = "wushang://android";
       }
    });

    function startApp(){
       if(publicFun.isIos()){
          alert('it is IOS')
       }else{
          window.location.href = "wushang://android";
       }
    }
</script>

因此決定之後遇到這類問題,就用這兩種方式了。下面是實際的處理函數

 window.startApp = function(){     //啓動APP
     if(publicFun.isInWx()){     //微信中
        alert("請在瀏覽器中打開");
     }else{      //非微信中
        if(publicFun.isIos()){    //IOS系統,直接去itunes中,既能夠下載也能夠打開
            window.location.href = "https://itunes.apple.com/cn/app/[name]/id[id]";
        }else{      //android系統,經過定時器的方式,判斷是否安裝有APP
            var hasApp = true , t = 1000;
            setTimeout(function () {  //沒有安裝APP則跳轉至應用寶下載,延時時間設置爲2秒
              if(!hasApp) window.location.href = "http://a.app.qq.com/o/simple.jsp?pkgname=[name]";
            } , 2000);
            var t1 = Date.now();
            window.location.href = "wushang://android";
            setTimeout(function () {    //t的時間就是出發APP啓動的時間,若APP啓動了,再次返回頁面時t2這行代碼執行,hasApp即爲true。反之若APP沒有啓動即爲false
              var t2 = Date.now();
              hasApp = !(!t1 || t2 - t1 < t + 150);
            } , t);
        }
     }
  } 

其實有個很是簡單的辦法,就是直接跳轉應用寶。不管是在android仍是IOS,以及微信非微信。應用寶的下載頁面都有下載和打開兩個功能(若是是在IOS平臺,它是經過鏈接app store的方式)

 

4、IOS平臺

針對ios9及以上的打不開問題,實際上ios9提供了更好的解決方案————通用連接。

這是iOS9推出的一項功能,若是你的應用支持Universal Links(通用連接),那麼就可以方便的經過傳統的HTTP連接來啓動APP(若是iOS設備上已經安裝了你的app,不須要額外作任何判斷等),或者打開網頁(iOS設備上沒有安裝你的app)。或許能夠更簡單點來講明,在iOS9以前,對於從各類從瀏覽器,Safari、UIWebView或者 WKWebView中喚醒APP的需求,咱們一般只能使用scheme。

以上來自網上關於通用連接的介紹,對於前端簡單點講就是你訪問一個http的url,若是這個url帶有你提交給開發平臺的配置文件中匹配規則的內容,ios系統會去嘗試打開你的app,若是打不開,系統就會在瀏覽器中轉向你要訪問的連接。很好的一個屬性,由於經過這個屬性在ios9上咱們可以繞過微信的攔截從而打開app。

因此上面的點擊事件,僅僅是去訪問app store,由於若app已安裝,在瀏覽器訪問時,就已經去到APP中了。

這些都是IOS配置上的東西,就很少寫了。至於傳參,以及頁面定向,其實也就是至關於在UIWebView中獲取當前鏈接的URL,而後進行字符串拆分以及校驗,便可判斷去哪一個頁,以及獲取參數值。

相關文章
相關標籤/搜索