hybird 與h5 app是不同的,之前對這二者理解有所誤解,在實際開發中也並未真正採用hybird,而是使用h5+app外殼實現移動端應用。雖然開發出來的應用實現了無需升級app實現主功能更新,可是交互體驗上較原生相差甚多。
Hybrid App(混合模式移動應用)是指介於web-app、native-app這二者之間的app,兼具「Native App良好用戶交互體驗的優點」和「Web App跨平臺開發的優點」(摘自百度百科)
通常hybird app會將須要動態更新頁面及功能內置到app中,也就是將web頁面預置到本地,android端經過加載本地html頁面實現快速加載,因爲不須要通過網絡,速度上會有極大的提高。而須要升級是,則需在服務器上創建對應的資源包,並將服務器資源包與本地html版本作對比,若不一致則從服務器加載資源壓縮包,並下載到本地,從而實現不須要從新安裝app快速升級迭代的目的。此功能適用於須要頻繁更新,又對性能要求較高的場景,例如新聞頭條頁等。若用h5實現,則體驗上會相差很多。javascript
1.一般android與js混合調用的方式是android端定義webView,並設置以下代碼html
WebSettings settings = mWebView.getSettings(); settings.setJavaScriptEnabled(true); //設置本應用加載網頁 mWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url) return true; } }); mWebView.loadUrl("***.html");
此處傳入url並開啓訪問網絡權限便可實現打開頁面.AndroidManifest.xmljava
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
下面正式開始JS調用android方式
須要創建一個橋,以下android
import android.content.Context; import android.webkit.JavascriptInterface; import android.widget.Toast; public class JsInterface { private Context mContext; public JsInterface(Context context){ mContext = context; } //必須加註解,爲了安全性考慮,4.2後強制 @JavascriptInterface public void showToast(String params){ Toast.makeText(mContext,"Hello"+params,Toast.LENGTH_LONG).show(); } } //MainActivity中 JsInterface jsInterface = new JsInterface(MainActivity.this); myWebView.addJavascriptInterface(jsInterface,"bridge"); //js中,使用以下代碼 document.getElementById('#btn').addEventListener("click",function(){ if(window.bridge){ window.bridge.showToast('from js methods'); } })
此時js能夠成功 調用到android中原生方法,可是回調會很麻煩,4.4中有evaluatejavascript能夠實現,可是未兼容到4.4如下。至此,由於本文中的重點,hybird的實現方案及js與android交互方案。web
原理與android中原生schema協議相似,經過攔截URl形式實現。能夠經過自定義協議名稱,而後webView中攔截這個schema,並解析其中參數與回調函數,js調用android方法,並實現回調。
首先定義協議,即須要攔截的scheme ,我在這裏定義 myschema://utils,這個協議名能夠是任意的,只要攔截統一便可。
封裝的js方法以下安全
function invoke(action, data, callback) { // 拼裝 schema 協議,action對應須要實現的方法名 var schema = 'myshema://utils/' + action // 拼接參數 data對應參數 schema += '?a=a' var key for (key in data) { if (data.hasOwnProperty(key)) { schema += '&' + key +"="+ data[key]; } } // 處理 callback var callbackName = '' if (typeof callback === 'string') { callbackName = callback } else { callbackName = action + Date.now() window[callbackName] = callback } schema += '&callback='+callbackName; //最終拼接出來應該是zhezhong這種形式 myshema://utils/actioin?a=a&key=value&callback=callbackName // 觸發 var iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = schema // 重要!此處會發送鏈接,會被webviwe捕獲到 var body = document.body body.appendChild(iframe) setTimeout(function () { body.removeChild(iframe) iframe = null }) }
index中服務器
document.getElementById('btn1').addEventListener('click', function () { // invokeScan() invoke('showToast',{name:'js'},function(res){ console.log("回調成功",res)' }) //location.href="http://www.baidu.com"; })
android中,將js文件與index文件放置與assets文件夾下,webView加載此index,並設置攔截,代碼以下網絡
myWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //重要,此處實現攔截,可解析參數,根據action名稱調用不一樣方法,此處未演示 if(url.contains("myshema://utils/")){ Toast.makeText(MainActivity.this,"調用成功",Toast.LENGTH_LONG).show(); String callback = ""; Map<String,String> params = UriUtil.URLRequest(url); if(params.containsKey("callback")){ view.loadUrl("javascript:"+params.get("callback")+"()"); } }else{ view.loadUrl(url); } return true; } }); myWebView.loadUrl("file:///android_asset/index.html");
至此,實現了經過自定義schema實現js攔截調用android原生方法的方案,此方案好處是能夠隱藏調用細節,將調用細節封裝到內部,更安全,並且兼容性更好.
如有問題,歡迎提問並與我聯繫,轉載請註明做者!app