編輯:關於Android編程
在移動互聯網,鏈接是比較重要的傳播媒質,但很多時候我們又希望用戶能夠回到APP中,這就要求APP可以通過浏覽器或在微信中被方便地喚起。
這是一個既直觀又很好的用戶體驗,但在實現過程中會遇到各種問題:
如何解決未安裝APP時的做好引導頁 如何在微信中喚醒APP 在iOS9中如何處理universal link被用戶誤關的情況 如何解決Android各種機型、各種第三方浏覽器導致的兼容問題等 在APP未安裝情況下,引導用戶下載後打開APP後,如何進入之前喚起時指定的頁面或內容,即如何實現場景還原 在微信中喚醒APP時,如何進入指定的頁面或內容下面是我一些個人的經驗分享。
這塊內容其實比較簡單,在網上都有很多資料可供查閱,就不再贅述。
首先需要說明,不管iOS還是Android,浏覽器都不可能預知本地是否安裝了某個APP的。或者更嚴謹地說,我們不能通過浏覽器來預知本地是否安裝。因為就算浏覽器可以讀取本地應用的安裝列表,但是目前也沒任何一家浏覽器提供查詢的API,所以這條路是走不通的。
本質上浏覽器是通過URL scheme打開APP,一個APP可以設置一個或多個打開自己的URL scheme。比如,Twitter就注冊自己能被「twitter://」打開。
其實,如果是做APP間相互跳轉是比較簡單的。iOS就可以使用 UIApplication 的 canOpenUrl 方法來檢測URL scheme 是否能打開對應的APP。比如,如果「twitter://」檢測能被打開,也就說明本地安裝了 Twitter 。再用 UIApplication 的 openURL 方法,就能打開Twitter了。Android 中的做法類似。
因為iOS9和之前的iOS系統有區別,所以這裡我們也要區別對待。
iOS中默認通過Safari打開URL scheme,方法一般如下兩種:
直跳方式:點擊鏈接、修改 window.location 等。 iframe 方式:在 body 上添加 iframe,設置src屬性為跳轉的URL scheme。第一種情況:
window.location.href = http://blog.csdn.net/dreamstarting/article/details/schemeUrl;
但在第一種情況,如果APP喚醒失敗,或者APP未安裝的話,很多時候都會跳到錯誤頁,這很影響用戶體驗,而我們的要求可能是跳轉到其他頁面或者下載APP。
後一種方法不會引起頁面可見的變化(例如頁面內容變成一個新頁面),不會導致浏覽器歷史記錄的變化,
過程是這樣:點擊 a 標簽時,首先會嘗試打開URL scheme,如果成功,就喚起APP;如果失敗,則跳轉到 href 屬性,即下載頁。
但這個方案在很多安卓機型上有問題,為保證可用,改用第一種方案:
$('a').click(function() { location.href = '自定義 URL scheme'; t = Date.now(); setTimeout(function(){ if (Date.now() - t < 1200) { location.href = 'Android 下載地址'; } }, 1000); return false; }
理想過程是這樣:浏覽器嘗試打開 URL scheme,在1秒計時後,檢查當前時間,如果實際時間已過 1200 毫秒,說明喚起APP 成功(喚起 APP 會讓浏覽器的定時器變慢);如果沒超過 1200 毫秒,很可能是沒有安裝應用,就跳到下載地址。
或者換種方式:
var ifr = document.createElement('iframe'); ifr.src = 'com.baidu.tieba://'; ifr.style.display = 'none'; document.body.appendChild(ifr); var openTime = +new Date(); window.setTimeout(function(){ document.body.removeChild(ifr); if( (+new Date()) - openTime > 2500 ){ window.location = 'http://exam.com/xxxx.apk'; } },2000)
但原理都是一樣,利用setTimeout。但這其實不穩定,因為Android是基於Linux的分時多任務的,setTimeout的基准偏差可能會沒那麼大。
但如果設置比較小的運行間隔(<30ms),在浏覽器或者webview中,應用切換到後台,setInterval會被很明顯的延遲執行,比如設置一個運行間隔20ms,總計運行100次的定時器,如果頁面一直處於前台,則100次跑完,總耗時與 100x20=2000ms不會有太大差異,但頁面在後台運行時,此時間會明顯超過2000ms。可以利用這一點來實現是否成功打開APP檢測及回調。
function openApp(openUrl, appUrl, action, callback) {
//檢查app是否打開
function checkOpen(cb){
var _clickTime = +(new Date());
function check(elsTime) {
if ( elsTime > 3000 || document.hidden || document.webkitHidden) {
cb(1);
} else {
cb(0);
}
}
//啟動間隔20ms運行的定時器,並檢測累計消耗時間是否超過3000ms,超過則結束
var _count = 0, intHandle;
intHandle = setInterval(function(){
_count++;
var elsTime = +(new Date()) - _clickTime;
if (_count>=100 || elsTime > 3000 ) {
clearInterval(intHandle);
check(elsTime);
}
}, 20);
}
//在iframe 中打開APP
var ifr = document.createElement('iframe');
ifr.src = openUrl;
ifr.style.display = 'none';
if (callback) {
checkOpen(function(opened){
callback && callback(opened);
});
}
document.body.appendChild(ifr);
setTimeout(function() {
document.body.removeChild(ifr);
}, 2000);
}
另外,可以通過
document.hidden 或
document.[webkit|moz|ms]Hidden 來判斷頁面是否被置入後台(即應用被喚起),或
visibilitychange事件,但對於Android 4.4版本一下則不支持。
iOS9
在 iOS 9 上,iframe 方案變得不可用。
按不能使用之前Android的代碼,因為在打開自定義 URL scheme 時,會彈出對話框,詢問是否用 xx 應用來打開。往往用戶還沒來得及點擊打開,定時器又觸發了,導致跳到 App Store。
可以在嘗試打開URL scheme 後,再加一個頁面跳轉,這樣對話框會被覆蓋,再刷新頁面,就能無需確認喚起APP:
$('a').click(function() {
location.href = '自定義 URL scheme';
location.href = '下載頁';
location.reload();
}
這裡,下載頁延時 2 秒跳轉到 App Store。
APP已安裝這是沒問題的,但如果APP未安裝,跳 App Store 的請求會失敗。
這時可以使用兩個定時器:
$('a').click(function() {
location.href = '自定義 URL scheme';
setTimeout(function() {
location.href = '下載頁';
}, 250);
setTimeout(function() {
location.reload();
}, 1000);
}
不過在iOS9中其實是支持universal link的,就是一個http域名形式,在微信中都可以喚起APP。如果未安裝的話,可以直接引導用戶去APP store下載。
沒有完美的解決方案
主要是在安卓上,總歸會有各種兼容問題,知乎的解決辦法是,提供兩個按鈕,一個下載,一個打開APP,讓用戶自己選。
微信中打開
因為微信將喚起本地APP的接口給禁了,所以微信中是不能直接喚起APP的,一般做法是提示用戶在浏覽器中打開,之後的流程還是我們上面講的內容。
但是,在iOS9中,這個限制是可以突破的,也就是說可以直接喚起APP。方法就是使用我們上文提到的universal link。
在Android和iOS8及其以下系統中,我們可以利用騰訊的親兒子:應用寶。簡單講,就是把你的喚起地址配置成你APP的應用寶地址,微信中跳轉到這個地址後,如果用戶已經安裝了APP,則可直接喚起,如果沒有安裝,則可直接點擊下載,如下圖示:
vce1xMG0vdOjqLHIt73LtbXjvLi31s/to6zItLK70KHQxLXju/fByyZyZHF1bzttbGlua3MuY2MmcmRxdW87o6mjrLW81sLM+LW9zeKyv+SvwMDG99bQo6zI58/CzbzL+cq+o7o8L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9wPg0KPHA+PGNvZGU+PGNvZGU+PGNvZGU+PGNvZGU+PGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20160801/20160801093839975.jpg" title="\" />
這時候再在微信中就打不開APP了,因為universal link已被關閉,這是iOS9的機制,沒法改變,這時候用戶再在微信中打開,就得需要一個中間頁來引導用戶在外部浏覽器中打開APP,如下圖所示:
另外,在微信中喚醒APP默認只能到達首頁,即不能到達指定頁面或內容,如果想要做,則需要額外的處理。
拿來主義
從以上內容可以總結出:要做一個兼容性很好的方案,就需要考慮各種情況,在不同的情況適配不同的方案,比方說用戶是在手機浏覽器打開還是微信中打開,或者是在pc中打開,universal link是否被關閉等,這就使代碼實現變得復雜,且容易出錯,且還有安卓平台機型眾多、浏覽器眾多等導致的兼容問題。
如果覺得實現難度或者成本太高,你可以考慮使用魔窗的mLink。只要你加了魔窗的sdk,就可以通過類似“https://s.mlinks.cc/AA01”的鏈接,在任何環境下打開你的APP(如果在pc機上打開,浏覽器中將會出現http://blog.csdn.net/dreamstarting/article/details/APP下載地址的二維碼),上面提到的問題都不復存在,並且魔窗已經兼容超過600台以上安卓機型的第三方主流浏覽器。而且關鍵的是,不管是在手機浏覽器中,還是在微信中打開,你可以指定喚起APP後直達APP中的某個頁面或內容(某個促銷商品等),就算用戶沒安裝APP,點擊下載安裝之後,再打開,還是跳轉到指定的頁面,這就是場景還原,或者叫做Deffered Deep Linking。
本例使用了6個庫代碼和1個主工程代碼。 一、6個庫代碼如下圖所示: 其中 ①.MenuDrawer、ViewPagerIndi
簡介 Android Universal Image Loader簡稱UIL, 其github鏈接https://github.com/nostra13/Android-
Android平台提供了一些傳感器讓你能監測設備的移動。它們中的兩個傳感器總是基於硬件的(加速度和陀螺儀),另外的這類這些傳感器中的3個即能使用基於硬件的也能使用基於軟件
前言給自己的APP增加相機是一個不錯的功能,在我們打開相機時,如果能動態給我們的臉上貼上標簽,或者是貼上一個卡通的眼睛,最後點擊拍照,一張合成的圖片就產生了,這是不是一個