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同样,十分容易理解。