hybrid:混合使用Native和web技術開發,即前端和客戶端的混合開發。核心是快速迭代,無需審覈。
主流技術框架javascript
webview:是app的一個組件,用於加載內嵌的h5頁面,即一個小型的瀏覽器內核
file協議:加載本地資源文件(http(s)協議則是網絡請求,加載網絡資源)前端
具體實現:
前端的靜態頁面交給客戶端,以文件形式存儲在app中,客戶端在webview中使用file協議加載靜態資源文件。
使用NA:體驗要求極致,變化不頻繁(新聞資訊類app的首頁)
使用hybrid:體驗要求高,變化頻繁(新聞資訊類app的新聞詳情頁)
使用h5:體驗無要求,不經常使用(如活動、反饋、舉報頁面)java
開發運維成本高,適用於產品的穩定功能,體驗要求高,迭代頻繁(產品型);
h5適用於單次的活動頁面或不經常使用頁面(運營型);git
上傳靜態資源包到服務端,客戶端每次啓動檢查包文件版本是否更新,下載新的包文件並解壓修改爲新的版本號。
(服務端的版本和zip包維護,更新zip包以前,先對比版本號。)github
JSBridge是實現web端和native端雙向通信的一種機制,以javascript引擎或者webview容器爲媒介,經過約定協議進行通信。
而Schema協議是前端和客戶端通信的約定(形式就是常見的url)。
web
window['_invoke_scan_callback_'] = function(result){ alert(result) } var iframe = document.createElement('iframe'); iframe.style.display = none; iframe.src = 'weixin://dl/scan?k1=v1&k2=v2&callback=_invoke_scan_callback_'; var body = document.body || document.getElementsByTagsName('body')[0]; body.appendChild('iframe'); setTimeout(function(){ body.removeChild(iframe); iframe = null; }) window.invoke.share({title: 'xxx', content: 'xxx'}, function(result){ if(result.errno === 0){ alert('分享成功~~~~') } else { // 分享失敗 alert(result.message) } }) (function (window, undefined) { // 調用 schema 的封裝 function _invoke(action, data, callback) { // 拼裝 schema 協議 var schema = 'myapp://utils/' + action // 拼接參數 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' // 觸發 var iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = schema // 重要! var body = document.body body.appendChild(iframe) setTimeout(function () { body.removeChild(iframe) iframe = null }) } // 暴露到全局變量 window.invoke = { share: function (data, callback) { _invoke('share', data, callback) } // ... } })(window) // invoke.js內置到客戶端,客戶端每次啓動webview都默認執行。實現本地加載
1.攔截webView請求的URL Schemaajax
兼容性好,但不直觀、url長度有限制 開源實現:JsBridge 通信的基本形式:調用能力,傳遞參數,監聽回調
2.向webView注入JS api小程序
簡單直觀,Android 4.2+版本 開源實現:DsBridge
function showNativeDialog(showBtn, text){ if(showBtn === 'showBtn1'){ // 通常是建立iframe元素節點,經過設定src屬性發起請求 window.alert(`jsBridge://showNativeDialog?text=${text}攔截URLSchema`); }else { // 向webView注入JS api方法通信 window.NativeBridge.showNativeDialog(`${text} 向webView注入JS api`); } }
客戶端獲取內容,而後JS通信拿到內容,再渲染。微信小程序
1.web端點擊按鈕,彈出Native端彈出框,顯示web端input內容api
<div class="ipt"> <input type="text" id="editText" placeholder="請輸入內容"> </div> // 1.攔截URLSchema <button id="showBtn1">show Native Dialog(攔截URLSchema)</button> <hr> // 2.注入JS api <button id="showBtn2">show Native Dialog(向webView注入JS api)</button> function showNativeDialog(showBtn, text){ if(showBtn === 'showBtn1'){ // 通常是建立iframe元素節點,經過設定src屬性發起請求 window.alert(`jsBridge://showNativeDialog?text=${text}攔截URLSchema`); }else { // 調用原生端的彈窗方法 window.NativeBridge.showNativeDialog(`${text} 向webView注入JS api`); } } private WebView webView; private MainActivity self = this; webView.setWebChromeClient(new WebChromeClient(){ // 攔截webView請求的URL Schema實現jsBridge,重寫對象攔截彈窗(開源實現JsBridge) @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { if (!message.startsWith("jsBridge://")){ return super.onJsAlert(view, url, message, result); } // 符合自定義url Schema,執行native彈窗方法 String text = message.substring(message.indexOf("=") + 1); self.showNativeDialog(text); result.confirm(); return true; } }); // 顯示原生彈窗 private void showNativeDialog (String text) { new AlertDialog.Builder(this).setMessage(text).create().show(); } // 向webView注入JS api(開源實現DsBridge) webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge"); class NativeBridge { private Context ctx; NativeBridge(Context ctx){ this.ctx = ctx; } @JavascriptInterface public void showNativeDialog (String text) { new AlertDialog.Builder(ctx).setMessage(text).create().show(); } }
2.Native端點擊按鈕,彈出web端彈出框,顯示Native端input內容
showBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 拿到native輸入的內容,並調用顯示web彈窗的方法 String iptValue = editText.getText().toString(); self.showWebDialog(iptValue); } }); // 顯示web彈窗 private void showWebDialog (String text) { String jsCode = String.format("window.showWebDialog('%s')", text); webView.evaluateJavascript(jsCode, null); } window.showWebDialog = text => alert(text);
1.web端發送原生http請求
2.原生端實現換膚功能
// 1. native端定義JsApi類,實現nativeRequest方法。用來接收web發送過來的url字符串,獲取地址而後發送原生http請求。 public class JsApi{ @JavascriptInterface public void nativeRequest(Object params, CompletionHandler handler) { try { String url = ((JSONObject)params).getString("url"); String data = request(url); handler.complete(data); } catch (Exception e) { handler.complete(e.getMessage()); e.printStackTrace(); } } private String request(String urlSpec) throws Exception { HttpURLConnection connection = (HttpURLConnection) new URL(urlSpec).openConnection(); connection.setRequestMethod("GET"); InputStream inputStream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuffer result = new StringBuffer(); String line; while ( (line = reader.readLine()) != null){ result.append(line); } // 將result轉爲字符串(http請求返回的內容) return result.toString(); } } // web端發送url信息,並返回獲取的請求內容。 sendBtn.addEventListener("click", e => { dsBridge.call("nativeRequest", { url: urlText.value}, data => { response.textContent = data; }) }); 2.定義changeTheme方法,改變狀態欄、標題欄、導航欄、web頁面的背景顏色。而後使用原生的菜單欄,調用changeTheme方法。 private void changeTheme (int color){ // 狀態欄 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); getWindow().setStatusBarColor(color); // 標題欄 getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color)); // 導航欄 getWindow().setNavigationBarColor(color); // web網頁 dwebView.callHandler("changeTheme", new Object[]{color}); } //web端改變背景色 dsBridge.register("changeTheme", color => { // andriod 0xFFFF0000 ARGB // web RGB/RGBA document.body.style.backgroundColor = '#' + (color & 0x00FFFFFF).toString(16); })
demo上傳地址: github地址https://github.com/NidusP/hybrid-demo
簡單瞭解一些hybrid開發的知識,JSbridge做爲web端與native端的溝通橋樑,其中schema協議和http(s)與file協議同樣,規定了一種通信方式,這種基本形式(調用能力,傳遞參數,監聽回調)與ajax同樣,十分容易理解。