Hybrid App开发笔记
开发模式:
因为尚属初次尝试.结合业务需求.使用【多View混合型】即Native View和Web View独立展示,交替出现的模式.这种模式首要解决的就是点击H5页面进行native界面跳转及数据传递.
主要交互的实现:
一.使用a标签
在用户点击的这个超链接的时候截获该连接.进行分析并获取值,进行下一步的操作.
使用场景:
- 点击H5功能列表获取数据并进入native页面.
- 调用java方法(传参不好确定)
js实现:
在html代码中使用固定头开始的a标签:
[a href="mc://mcvc?class=KCGoodCategoryVC&showtype=push&dataString=MCstring&jsid=888888">打开商品分类</a><br]
[a href="mc://mcfunc?func=test">执行本地方法</a><br]
安卓实现:
定义接收bean和方法接口:
public class BaseBean implements Parcelable{ public String showtype; public String dataString; public String jsid; public BaseBean() { } public BaseBean(Parcel in) { showtype = in.readString(); dataString = in.readString(); jsid = in.readString(); } } //子类具体实现 public class KCGoodCategoryVC extends BaseBean { protected KCGoodCategoryVC(Parcel in) { super(in); } public KCGoodCategoryVC() { } } //定义方法接口 public interface IFunc { void test(); void test1(String var); } //定义方法具体实现 public class FuncImpl implements IFunc { private Context mContext; public FuncImpl(Context context) { mContext = context; } @Override public void test() { Toast.makeText(mContext, "利用a标签调用了安卓方法", Toast.LENGTH_SHORT).show(); } @Override public void test1(String var) { Toast.makeText(mContext, "利用a标签调用.var:"+var, Toast.LENGTH_SHORT).show(); } }WebView获取被点击的超链接URL进行分析处理:
public class KCWebViewClient extends WebViewJavascriptBridge.MyWebViewClient { public KCWebViewClient(WebViewJavascriptBridge bridge) { super(bridge); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { et.setText(url); if (url.startsWith(BASE_HEADER)) { String[] value = url.split("\\?"); String[] val; switch (value[0]) { case CLASS_HEADER://解析url获取bean 并传递给相应的activity val = value[1].split("&"); String className = val[0].split("=")[1]; try { Class clazz = Class.forName("com.fec.h5demo.bean." + className); BaseBean instance = (BaseBean) clazz.newInstance(); for (int i = 1; i < val.length; i++) { String[] field = val[i].split("="); Field field1 = clazz.getField(field[0]); field1.set(instance, field[1]); } startActivity(new Intent(MainActivity.this, StartActivity.class).putExtra(StartActivity.EXTRA_KEY, instance));//实际情况中, // 这里是要启动不同的activity或者是不同的操作这里以一个activity代替 } catch (Exception e) { e.printStackTrace(); } break; case FUNC_HEADER: try { FuncImpl func = new FuncImpl(MainActivity.this);//根据url从固定的实现类中调用方法,这种方法存在传参不好确定的问题.有的方法不需要参数,有的需要参数,在这里无法进行确定 Class clazz = func.getClass(); val = value[1].split("&"); Method method = clazz.getDeclaredMethod(val[0].split("=")[1]); method.invoke(func); } catch (Exception e) { e.printStackTrace(); } break; } } return super.shouldOverrideUrlLoading(view, url); } }
二.使用方法接口交互:
使用Js和安卓支持的方法接口方式调用对方的方法,存在缺点:原生不支持直接回调.如要实现需另外调用其他方法.
使用场景:
- Js可以直接打开原生的activity,弹出toast等.
- native也可以控制h5页面的跳转等.
Js实现:
调用native:
function showToast(){ var message = document.getElementById("message").value; var lengthLong = document.getElementById("length").checked; app.makeToast(message, lengthLong); return false; } /* 把showToast方法重定向给onsubmit == window.app.makeToast() */ window.onload = function(){ var form = document.getElementById("form"); form.onsubmit = showToast; }给native调用:
function toastAlert(){ var msg = document.getElementById('message').value; alert(msg); } function actionFromNativeWithParam(arg){ document.getElementById("log_msg").innerHTML += ("<br\>Native调用了js函数并传递参数:"+arg); }跳转activity并传入data:
function callNative(msg){ window.app.gotoActivity(msg); } <script> var arg1 = "{'type':'mcvc','class':'com.fec.StartActivity','showtype':'push','dataString':'Js传入'}";//使用隐式意图进行跳转 </script> <input type="button" value="调用java方法进行跳转,传值" onclick="callNative(arg1);"/><br>
安卓实现:
调用js:
String param = et.getText().toString().trim(); wv.loadUrl("javascript:actionFromNativeWithParam(" + "'" + param + "'" + ")");//传参调用js代码给Js调用:
//定义方法接口 public interface IJavaFunc { void makeToast(String msg, boolean lengthLong); void gotoActivity( String arg); } wv.addJavascriptInterface(new IJavaFunc() {//添加js能够调用的方法接口 @JavascriptInterface @Override public void makeToast(String msg, boolean lengthLong) {//被调用后接收Js传递的参数并执行方法体内代码. Toast.makeText(MainActivity.this, msg, lengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show(); } @JavascriptInterface @Override public void gotoActivity(String arg) {//使用json传输数据 JsonBean jsonBean = mGson.fromJson(arg, JsonBean.class); startActivity(new Intent(jsonBean.getClassX()).putExtra("json", jsonBean)); } }, "app");定义JsonBean接收数据,跳转activity时进行传输:
public class JsonBean implements Parcelable { /** * type : mcvc * class : TestViewController * showtype : push * dataString : js string */ private String type; @SerializedName("class") private String classX; private String showtype; private String dataString; protected JsonBean(Parcel in) { type = in.readString(); classX = in.readString(); showtype = in.readString(); dataString = in.readString(); }
三.使用WebViewJavascriptBridge框架:
An iOS/OSX bridge for sending messages between Obj-C and JavaScript in WKWebViews, UIWebViews & WebViews.(gitHub)
优点如下:
- 有安卓衍生版本(Cross-platform WebViewJavascriptBridge for HTML/Android/Chrome Extension, the javascript interface compatible with WebViewJavascriptBridge).框架的统一使用避免因调用方式不同而导致同样的业务逻辑,前端为ios和android各写一套的问题.
- 能比较方便的统一实现Js和native的传值\方法互调和回调.
- 使用者较多,项目一直在维护.安卓端框架体积小.
Js实现:
console.log("user_client.js called!");
var bridge;
document.addEventListener('WebViewJavascriptBridgeReady'
, function(event) {
bridge=event.bridge;
bridge.init(function(message, responseCallback) {//初始化默认给java调用的处理方法
document.getElementById("log_msg").innerHTML +=
("<br\>Javascript默认处理方法收到了: "+ message);
if (responseCallback) {
responseCallback("js默认处理") ;
}
}) ;
bridge.send('js无回调发送');
bridge.send('js回调发送', function(responseData) {//发送消息给java并取得回复
document.getElementById("log_msg").innerHTML +=
("<br\>Javascript收到了回答: "+ responseData);
});
bridge.registerHandler("showAlert", function(data,responseCallback) {
alert("alert:"+data);
responseCallback(data+1);
});//提供给java调用
bridge.callHandler("handler1","js发送给handler1",function(responseData){//调用java传送数据并取得回复
document.getElementById("log_msg").innerHTML +=
("<br\>js收到handler1的response:"+responseData);
});
}, false)
function fwcallNative(msg){//启动acivitiy
bridge.callHandler("gotoActivity",msg,function(responseData){
document.getElementById("log_msg").innerHTML +=
("<br\>js启动activity得到了response:"+responseData);
});
}
安卓实现:
- 集成框架.
定义给Js调用的handler:
bridge = new WebViewJavascriptBridge(this, wv, new UserServerHandler()); bridge.setCustomWebViewClient(new KCWebViewClient()); bridge.registerHandler("handler1", new WebViewJavascriptBridge.WVJBHandler() {//定义给Js调用的handler @Override public void handle(String data, WebViewJavascriptBridge.WVJBResponseCallback jsCallback) { if (null != jsCallback) { jsCallback.callback("handler1 收到了:" + data); } } }); bridge.registerHandler("gotoActivity", new WebViewJavascriptBridge.WVJBHandler() {//定义给Js调用的handler @Override public void handle(String data, WebViewJavascriptBridge.WVJBResponseCallback jsCallback) { if (!TextUtils.isEmpty(data)) { JsonBean jsonBean = mGson.fromJson(data, JsonBean.class); startActivity(new Intent(jsonBean.getClassX()).putExtra("json", jsonBean)); if (null != jsCallback) { jsCallback.callback("启动了activity:" + jsonBean.getClassX()); } } } });向Js发送数据并取得回复:
bridge.send("呵呵", new WebViewJavascriptBridge.WVJBResponseCallback() { @Override public void callback(String data) { Log.i("test", "java说:呵呵 js回复说:"+data); } });调用Js的方法并取得回复:
bridge.callHandler("showAlert", "99", new WebViewJavascriptBridge.WVJBResponseCallback() { @Override public void callback(String data) { Log.i("test", "调用js方法回调: "+data); } });//调用js方法
本文介绍了HybridApp开发中三种核心交互方式:使用a标签、方法接口和WebViewJavascriptBridge框架,详细展示了每种方法的具体实现步骤和技术细节。
492

被折叠的 条评论
为什么被折叠?



