网页打开app
先聲明一下關于ios中9.0打開方式的文章來自博客:IOS9通用鏈接(universal link)
前言
對于一個完備的互聯網產品而言需要有app端與web端兩個不同前端,對于產品而言很多都希望能夠將wap頁上的用戶引向native app上這就要求前端工程師們為網頁提供各種入口去打開app,今天我們就聊一聊app的打開方式(有錯誤的地方還請高手指正)。
常規打開
對于app打開而言最常規的打開就是通過url scheme的方式去打開你的app,如下的
myapp:// myapp://open myapp://type=1&id=2sdeo223lwe這些拋出都是以url的方式進行拋出,app捕捉到這些拋出去做相應的處理,本文對app的處理不做詳細描述,app開發請自行谷歌百度。對于前端而言拋出的方式也有很多,而最理想的方式是通過iframe的src對其進行鏈拋出,來!說的在多都沒有代碼來的清晰,請看下面。
首先我們需要有一個iframe:
//實際上就是新建一個iframe的生成器 var createIframe=(function(){var iframe;return function(){if(iframe){return iframe;}else{iframe = document.createElement('iframe');iframe.style.display = 'none';document.body.appendChild(iframe);return iframe; }} })()之后我們還需要一個url scheme:
//生成一個url scheme,假設我們約定的scheme是myApp://type=1&id=iewo212j32這種形式的var baseScheme = "myApp://" var createScheme=function(options){var urlScheme=baseScheme;for(var item in options){urlScheme=urlScheme+item + '=' + encodeURIComponent(options[item]) + "&";}urlScheme = urlScheme.substring(0, urlScheme.length - 1);return encodeURIComponent(urlScheme); }這種scheme形式的其實不是最好的,根據我們踩過的坑,覺得約定為與http協議相近可能更好一些,具體的協議需要前端人員自己去和app端人員約定。
ok萬事具備,iframe有了,urlScheme也有了,該去打開app了
var openApp=function(){var localUrl=createScheme();var openIframe=createIframe();if(isIos()){//判斷是否是ios,具體的判斷函數自行百度window.location.href = localUrl;var loadDateTime = Date.now();setTimeout(function () {var timeOutDateTime = Date.now();if (timeOutDateTime - loadDateTime < 1000) {window.location.href = "你的下載頁面";}}, 25);}else if(isAndroid()){//判斷是否是android,具體的判斷函數自行百度if (isChrome()) {//chrome瀏覽器用iframe打不開得直接去打開,算一個坑window.location.href = localUrl;} else {//拋出你的schemeopenIframe.src = localUrl;}setTimeout(function () {window.location.href = "你的下載頁面";}, 500);}else{//主要是給winphone的用戶準備的,實際都沒測過,現在winphone不好找啊openIframe.src = localUrl;setTimeout(function () {window.location.href = "你的下載頁面";}, 500);} }以上就是你要打開scheme的主要代碼了,好吧,實際上不只是打開app,還要實現未打開的時候跳到下載頁去。其中安卓實際上無論有沒有打開都會跳到下載頁去,而ios........好吧!按照網上的說法是瀏覽器失焦后會掛起腳本,呵呵,這是多老的ios版本的表現了,實際上現在的ios已經沒有這么做,有些版本會跟安卓的表現一樣,而有些則是直接跳轉根本不會去打開,還有打開的時候那個惡心的系統彈窗是什么鬼。好吧,實際上至此你會發現,ios9.0以上的有些打不開直接跳,有些打得開還會有允許彈窗,而微信則是無論如何都打不開,實際上微信會在他的瀏覽器里攔截掉所有未經其允許的scheme包括app store,那么接下來我們要解決這些問題。
通用鏈接
針對ios9及以上的打不開問題,實際上ios9提供了更好的解決方案————通用鏈接。
什么是Universal Links(通用鏈接)?
這是iOS9推出的一項功能,如果你的應用支持Universal Links(通用鏈接),那么就能夠方便的通過傳統的HTTP鏈接來啟動APP(如果iOS設備上已經安裝了你的app,不需要額外做任何判斷等),或者打開網頁(iOS設備上沒有安裝你的app)。或許可以更簡單點來說明,在iOS9之前,對于從各種從瀏覽器,Safari、UIWebView或者 WKWebView中喚醒APP的需求,我們通常只能使用scheme。
以上來自網上關于通用鏈接的介紹,對于前端簡單點講就是你訪問一個http的url,如果這個url帶有你提交給開發平臺的配置文件中匹配規則的內容,ios系統會去嘗試打開你的app,如果打不開,系統就會在瀏覽器中轉向你要訪問的鏈接。很好的一個屬性,因為通過這個屬性在ios9上我們能夠繞過微信的攔截從而打開app。
以下是ios開發人員要做的百度搜索結果第一條ios中實現通用鏈接:
而我們要做的真的很簡單,實際上我們只需要拋出鏈接就好了(實際上博主只是來騙經驗的)。在此之前請準備好與主站不同的域名,比如主站www.xxxx.com,你們可以準備好open.xxxx.com的域名作為重定向用。好吧!實際上通用鏈接有一個很坑的屬性,必須是異域打開,而且如果你提交的是你主站的鏈接,你打開你的主站你會發現網站上方會掛著一個難看的灰條轉向appstore中你們的app,沒錯,就是ios系統干的這個事,具體的其他注意事項可以參考這篇文章IOS9通用鏈接(universal link)。
那么接下來我們的代碼得做好更改
//增加通用鏈接的生成, var baseScheme = "myApp://",baseLink="http://m.xxxx.com?"; var createScheme=function(options,isLink){var urlScheme=isLink?baseLink:baseScheme;for(var item in options){urlScheme=urlScheme+item + '=' + encodeURIComponent(options[item]) + "&";}urlScheme = urlScheme.substring(0, urlScheme.length - 1);return isLink?urlScheme:encodeURIComponent(urlScheme); }然后對拋出做
var openApp=function(){//生成你的scheme你也可以選擇外部傳入var localUrl=createScheme({type:1,id:"sdsdewe2122"});var openIframe=createIframe();if(isIos()){//判斷是否是ios,具體的判斷函數自行百度if(isGreaterThan9()){//判斷是否為ios9以上的版本,跟其他判斷一樣navigator.userAgent判斷,ios會有帶版本號localUrl=createScheme({type:1,id:"sdsdewe2122"},true);//代碼還可以優化一下location.href = localUrl;//實際上不少產品會選擇一開始將鏈接寫入到用戶需要點擊的a標簽里return;}window.location.href = localUrl;var loadDateTime = Date.now();setTimeout(function () {var timeOutDateTime = Date.now();if (timeOutDateTime - loadDateTime < 1000) {window.location.href = "你的下載頁面";}}, 25);}else if(isAndroid()){//判斷是否是android,具體的判斷函數自行百度if (isChrome()) {//chrome瀏覽器用iframe打不開得直接去打開,算一個坑window.location.href = localUrl;} else {//拋出你的schemeopenIframe.src = localUrl;}setTimeout(function () {window.location.href = "你的下載頁面";}, 500);}else{//主要是給winphone的用戶準備的,實際都沒測過,現在winphone不好找啊openIframe.src = localUrl;setTimeout(function () {window.location.href = "你的下載頁面";}, 500);} }實際上就只需要更改這么點,最重要的是app端接入通用鏈接,注意拋出的鏈接不要跟主站同域即可,之后就是不斷的調試,自己去踩坑吧,記得綁定域名,這個對域名具有一定的依賴性。
微信中打開
至此只有微信是打不開的,實際上騰訊系的產品都是打不開的,包括qq瀏覽器。
對于微信中有兩種方式:
一種簡單的方式就是彈窗告訴用戶讓他去瀏覽器中打開——在技術之外的辦法
還有一種方式就是應用寶
是的如果是微信就去打開你的app對應的應用寶,應用寶會去檢測你的app是否存在有則去打開,但只是去打開。實際上騰訊的應用寶對于開發者在功能上做的比想象中的要強大,你在應用寶的微下載中配置申請你的applink與app store的鏈接,之后你只要在你的鏈接參數中帶上android_schema="myApp://"就在應用寶中打開app中的特定功能,如果忽略應用寶的頁面跟自己scheme打開沒有太大區別,具體的操作可以查看應用寶的說明。簡而言之,騰訊的產品中都去借助應用寶這個平臺去執行你需要的操作。在此就不貼代碼了,只要判斷瀏覽器如果是微信或者是qq就去跳你的應用寶鏈接就行。
總結
實際上單純打開app非常簡單,目前無論安卓還是ios都能夠很好的支持scheme,當然騰訊系產品除外,實際上百度瀏覽器也會攔截scheme(我覺得真是奇了葩!!!微信這種尚能理解,一個瀏覽器居然擅自去攔截scheme)目前對百度瀏覽器還沒有什么很好的辦法,可以嘗試是否能夠通過百度應用市場去解決。如果是希望打開app同時又要打開下載頁,那么ios9及以上就得用通用鏈接去解決,重點就是這個通用鏈接。
IOS9通用鏈接(universal link)
Jun 27, 2016IOS9以上版本新增了通用鏈接的功能。最近在項目中正好有用到,并在開發過程中遇到了很多坑。因此對其進行總結,以供大家參考,如有疏漏,求留言指證~~
應用場景
在WAP頁面中點擊某個按鈕。
- 用戶裝了APP,直接打開APP對應頁面;
- 沒有裝APP,跳轉到WAP下載頁;
URL Scheme實現方案
| var iframe = document.createElement('iframe'); iframe.style.display = 'none'; document.body.appendChild(iframe); if(userAgent.match(/(iPhone|iPod|iPad);?/i)){ //拋出schemes,打開app對應頁面 window.location.href = "apps custom url schemes"; //由于部分ios中打開app后,WAP頁面會被掛起,定時器不會被執行。因此可以做下優化: //WAP頁重新被聚焦后,如果超過1s,認為APP被打開了,重新聚焦時就不必再跳轉到APP下載頁 var loadDateTime = Date.now(); window.setTimeout(function () { var timeOutDateTime = Date.now(); if (timeOutDateTime - loadDateTime < 1000) { window.location.href = "app下載頁面"; } }, 25); }else{ //拋出schemes,打開app對應頁面 iframe.src = "apps custom url schemes" //跳轉下載頁 setTimeout(function () { window.location.href = "app下載頁面"; }, 500); } |
以上代碼原理是:
- 如果安裝了APP,拋出的URL Scheme可以被app解析,則打開該APP,并由APP跳轉到對應的頁面;
- 如果未安裝APP,沒有應用程序可以解析該協議,則在500ms以內執行定時器里的函數,打開WAP端的下載頁面。
apps custom url schemes是什么
apps custom url schemes 是WAP端和APP端約定好的一個協議URL,如:web2app://。和正常的URL一樣,除了protocol部分外,也可以有host、path及參數,如:web2app://openapp?type=1&id=12。具體要看各端約定,不過個人建議最好還是按照URL的組成規范來定義scheme,不然會引入由于URL不規范而導致的各種編碼問題。
首先在,APP里會配置好預定好的URL Scheme協議,
| <intent-filter > <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <!-- scheme的Uri的協議必須跟此值相同--> <data android:scheme="web2app"/> </intent-filter> |
每當WAP頁打開協議URL,系統便會打開該APP,然后根據URL協議后面的部分,執行后續邏輯(比如打開WAP頁對應的APP頁面)。
URL Scheme存在的問題
IOS9.0以上彈確認框的問題。
在IOS9.0以上版本中,WAP端打開協議URL,如果已安裝APP,會彈出如下圖所示的確認框。
大部分情況下,用戶點擊“打開”APP之前,頁面直接刷新跳轉到WAP下載頁,導致打開APP失敗。這就是IOS9.0以上不能用scheme實現需求的主要原因。如果手機上未安裝APP,WAP端打開協議URL,會彈出無效URL的彈窗,也會影響用戶體驗。跳轉下載頁問題。
由于跳轉到下載頁由前端定時器觸發,在所有的andriod機以及部分IOS機器上,打開APP后,WAP頁還是會被定時跳轉到下載頁。
通用鏈接實現方案
在IOS9.0以上開始支持通用鏈接,接下來詳細解析一下用通用鏈接實現該功能的方案。
apple-app-site-association文件
apple-app-site-association是IOS中一個JSON格式的“通用鏈接”配置文件,在其paths鍵中設置通用鏈接的具體規則。
| { "applinks": { "apps": [], "details": [ { "appID": "...", "paths": ["/open/*"] } ] } } |
IOS端,在Xcode的capabilities里添加域名(b.com,為通用鏈接的域名)。這樣在第一次啟動APP時,APP會從?https://b.com/apple-app-site-association?下載這個配置文件并交由IOS系統管理。該配置文件必須通過SSL的方式請求,所以,b.com必須支持SSL訪問。
實現原理
用通用鏈接實現的原理如下圖所示。在服務器a.com上部署WAP頁以及APP下載頁,在b.com上署“后端重定向服務”以及“ios通用鏈接的配置文件”。
當WAP頁打開如下通用鏈接時:http://b.com/open/…,?如果已經安裝了APP,且該鏈接和APP在apple-app-site-association中配置的規則一致,則打開該APP,并由APP進行后續處理(打開應用內的某個頁面);如果ios上沒有安裝APP,則系統不會對該鏈接進行特殊處理,直接在瀏覽器中打開,后端的重定向服務會將該鏈接重定向到下載頁“http://a.com/mobile/app”,?代碼如下:
| if(navigator.userAgent.match(/OS 9_\d[_\d]* like Mac OS X/i)){ location.href = "universal link"; } |
幾個坑
WAP頁面的域(a.com)和拋出的通用鏈接的域(b.com)必須不一樣。如果同域,拋出的通用鏈接在很多情況下會被系統忽略,就算已安裝APP,也打不開并且直接重定向到下載頁。(至少在IOS9.*的版本中遇到了這個問題)。
通用鏈接在微信webview中的BUG。
微信webview中打開WAP頁,該WAP頁通過設置loaction.href拋出通用鏈接打開APP。之后從APP重新返回到該webview頁面,并用微信進行分享。
- 期待結果:分享出在webview中展示的WAP頁。
- 實際結果:發現最終分享出去的是APP下載頁。
- 原因分析:雖然在裝了APP的情況下,不會在webview中打開該通用鏈接刷新到下載頁,但是location.href這個全局變量已被更改,微信的默認分享的鏈接是location.href所指鏈接。該BUG的具體原因及解決方案將在以后的文章中進行詳細分析。
總結
- 上一篇: 洛谷 P1719 最大加权矩形 (前缀和
- 下一篇: 华硕f540u内存条在哪里_华硕笔记本电