11.29更新項目中對微信內的處理方案及一些坑
12.3更新ios9后url scheme的坑及最終解決方案
最近遇到一個需求:如果用戶安裝了app,則跳app;如果用戶沒安裝app,則跳app下載鏈接,這個在平常見的還蠻多的。查了一些資料,總結一下。
一、解決方案:URL scheme 或 universal link
a)URL scheme是在app內配置的鏈接,比如:weixin://,superclass://。
URL scheme的格式是[scheme]://[host]/[path]?[query]。
b)universal link是ios9之后出的功能。它是通過傳統HTTP鏈接來啟動App。它其實就是一個https開頭的鏈接,還要滿足一些特定的規則才能被識別為universal link,才能直接喚起app。
二、具體實現
分2種情況討論:
1、ios8之前和android:使用scheme方案。
原理:不管是ios還是安卓,瀏覽器都不可能知道手機有沒有裝某個app,所以方法是首先通過URL scheme打開app,如果打不開,則跳轉下載鏈接。
var timeout, t = 1000, hasApp = true;
var openScript = setTimeout(function () {
if (!hasApp) {
// 跳轉下載鏈接
}
document.body.removeChild(ifr);
}, 2000)
var t1 = Date.now();
var ifr = document.createElement("iframe");
ifr.setAttribute('src', url);
ifr.setAttribute('style', 'display:none');
document.body.appendChild(ifr);
timeout = setTimeout(function () {
var t2 = Date.now();
if (t2 - t1 < t + 100) {
hasApp = false;
}
}, t);
之所以要用iframe打開,而不是直接跳鏈接,是因為如果APP喚醒失敗,或者APP未安裝的話,很多時候都會跳到錯誤頁,影響用戶體驗。而iframe方法不會引起頁面可見的變化(例如頁面內容變成一個新頁面),不會導致瀏覽器歷史記錄的變化。
2、ios9之后:可以使用scheme方案,也可以使用ios9的universal link方案
(1)先說scheme方案,ios9把iframe封了,所以用的是直接跳轉鏈接
location.href = url;
setTimeout(function() {
// 跳轉下載鏈接
}, 250);
setTimeout(function() {
location.reload();
}, 1000);
這個方案在用戶安裝了app的時候還沒什么問題,但是如果沒裝app,跳轉失敗會先彈出錯誤彈窗,再彈出是否在「app store」中打開鏈接,見下圖。
如果產品能接受這種彈窗,其實也行。。下面的是封裝了2個函數,實現h5跳app。
通用的URL scheme方案代碼:
<script>
function detectVersion() {
let isAndroid,isIOS,isIOS9,version,
u = navigator.userAgent,
ua = u.toLowerCase();
if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) { //android終端或者uc瀏覽器
//Android系統
isAndroid = true
}
if(ua.indexOf("like mac os x") > 0){
//ios
var regStr_saf = /os [\d._]*/gi ;
var verinfo = ua.match(regStr_saf) ;
version = (verinfo+"").replace(/[^0-9|_.]/ig,"").replace(/_/ig,".");
}
var version_str = version+"";
if(version_str != "undefined" && version_str.length >0){
version = parseInt(version)
if(version>=8){
// ios9以上
isIOS9 = true
}
else{
isIOS = true
}
}
return {isAndroid,isIOS,isIOS9}
}
// 判斷手機上是否安裝了app,如果安裝直接打開url,如果沒安裝,執行callback
function openApp(url,callback) {
let {isAndroid,isIOS,isIOS9} = detectVersion()
if(isAndroid || isIOS){
var timeout, t = 4000, hasApp = true;
var openScript = setTimeout(function () {
if (!hasApp) {
callback && callback()
}
document.body.removeChild(ifr);
}, 5000)
var t1 = Date.now();
var ifr = document.createElement("iframe");
ifr.setAttribute('src', url);
ifr.setAttribute('style', 'display:none');
document.body.appendChild(ifr);
timeout = setTimeout(function () {
var t2 = Date.now();
if (t2 - t1 < t + 100) {
hasApp = false;
}
}, t);
}
if(isIOS9){
location.href = url;
setTimeout(function() {
callback && callback()
}, 250);
setTimeout(function() {
location.reload();
}, 1000);
}
}
//跳h5
function goConfirmAddr(){
window.location.
}
window.onload = function(){
openApp("superclass://home",goConfirmAddr)
}
</script>
(2)universal link
這個配置起來比較麻煩,主要是app那邊配置。具體可以看看最下面的參考博客。
看了下百度知乎的方法,都是用universal link
h5的知乎有個【app打開】按鈕,這個按鈕就是跳轉universal link鏈接。
a)若此時安裝了app,就提示是否在app打開。可以直接跳到app
b)若未裝app或未喚起app,跳到下載頁。
注意看域名:oia.zhihu.com,這個就是知乎的universal link,之所以是oia開頭,是因為universal link必須跨域。
參考
https://www.cnblogs.com/shadajin/p/5724117.html
http://www.cocoachina.com/ios/20170904/20463.html
http://www.lxweimin.com/p/03e6b7828307
11.29更新
以上只是Demo階段的總結,在項目過程遇到了2個問題:
一、微信內的處理方案
由于公司的app達不到微信的一些要求,所以微信瀏覽器內用universal link直接調起app這個方案行不通。
微信內的方案是:點擊「打開app」時,彈窗一個遮罩層,提示讓用戶點開右上角選擇在瀏覽器內打開。之后就簡單了。
遇到的問題:ios微信瀏覽器內url不變化
解決方案戳ios微信瀏覽器內vue項目url不改變
二、一些安卓手機自帶瀏覽器不能喚起app
原因:經反復測試之后發現,在手機自帶瀏覽器內,某個網址第一次嘗試打開app時,會有個是否打開某app的選擇彈窗,瀏覽器會記住用戶的選擇。如用戶選擇「打開」,之后每次都不出現選擇彈窗,每次直接跳轉app;如果用戶選擇「取消」,之后該網站就再也不出現是否打開某app的選擇彈窗,所以就調不起app,除非用戶在設置內清除瀏覽器的數據。
暫時只在小米手機瀏覽器內發現這個問題,qq瀏覽器都好使,暫時沒找到好的解決辦法。
12.3更新
測試階段自己點出了一個bug,ios9后用url scheme會出現一個偶發bug。
bug具體描述:前面我們知道,當用戶沒裝app時,嘗試打開app時會出現一個錯誤彈窗【safari打不開該網頁,因為網址無效】。理論上說,點擊「好」確認彈窗后,應該彈出【是否在app store打開】彈窗。(是否在app store中打開是因為配置了''window.location.href = 'https://itunes.apple.com/cn/app/id**********' ")
但是!!!!!!!!!!!!!!!!!!!!
當快速點擊確認錯誤彈窗時,頁面并不會彈出【是否在app store打開】彈窗,此時地址欄閃一下itunes的地址,之后嘗試打開app,都是錯誤彈窗,再也調不起【是否在app store打開】彈窗。
然后看了下同樣是使用url scheme方案的淘寶,他們的方案是錯誤彈窗后,跳轉到自己內部的下載頁,然后一進入下載頁時就會彈出【是否在app store打開】彈窗,這樣就不會出現上面的問題。
最后和產品商量,解決方案是跳到內部下載頁,和淘寶一樣。
12.7更新
看頭條的這個功能時,發現了ios里一個好玩的東西Smart App Banners