最近公司要求做一款h5游戏嵌入app,我用的游戏引擎是Cocos creator TS发布h5。所以首先要解决的就是交互问题,方便互相之间获取数据。我改写了网上的jsbridge demo用以适应自己的工程,也做了进一步解释。
参考的原工程:https://github.com/lzyzsd/JsBridge
在Android Studio上创建library实现jsbridge模块放入app中。
创建BridgeWebView类继承安卓的WebView在类中实现基本的初始化设置
getSettings().setJavaScriptEnabled(true);
getSettings().setDomStorageEnabled(true);
getSettings().getJavaScriptCanOpenWindowsAutomatically();
getSettings().setAllowUniversalAccessFromFileURLs(true);
在该类中实现调用js的方法 callJavaScriptFunc(String funcName, Object params, IBridgeCallback responseCall)
js在注册表中通过funcName找到对应方法执行,如果需要js返回结果数据,则添加responseCall,java派发这一方法
时在responseCall中添加对应的id以方便js执行完对应的方法后携带该id返回数据,java通过该id接收执行responseCall
中对应的回调拿到返回数据
/**
* 调用JavaScript的方法
* @param funcName JavaScript方法名
* @param params 参数 JSON/String
* @param responseCall
*/
public void callJavaScriptFunc(String funcName, Object params, IBridgeCallback responseCall){
// 没有方法名 return
if(TextUtils.isEmpty(funcName)) return;
// 参数不是String Gosn无实例对象 return
if(!(params instanceof String) && _jsonUtil == null) return;
JSRequest request = new JSRequest();
request._funcName = funcName;
request._funcParam = (params instanceof String)?(String)params:_jsonUtil.toJson(params);
if(responseCall != null){
String key = BridgeConfig.BRIDGE_CALL_KEY + (++_callbackId);
request._callFuncKey = key;
_responseCallMap.put(key, responseCall);
}
dispatchMessageToJS(request, BridgeDispatchType.DispatchCallFunc);
}
原工程中派发方法和派发返回数据都是走的同一方法,我将其分开了。返回结果给js也是通过查看js调用java方法时是否携带
回调函数的id如果有就代表需要返回数据,返回数据时将js传过来的id一并返回,js通过该id执行对应的回调拿到Java给的返回
数据。
/**
* 返回数据给JavaScript
* @param responseData 返回的数据
* @param callFuncKey JavaScript注册的回调函数的key
*/
public void responseToJavascript(Object responseData, String callFuncKey) {
if (TextUtils.isEmpty(callFuncKey)) return;
if (!(responseData instanceof String) && _jsonUtil == null) return;
final JSResponse response = new JSResponse();
response._callFuncKey = callFuncKey;
response._responseData = responseData instanceof String ? (String) responseData : _jsonUtil.toJson(responseData);
if (Thread.currentThread() == Looper.getMainLooper().getThread()){
dispatchMessageToJS(response, BridgeDispatchType.DispatchResponse);
}else {
post(new Runnable() {
@Override
public void run() {
dispatchMessageToJS(response, BridgeDispatchType.DispatchResponse);
}
});
}
}
在给js传输数据时需要在主线程中传输,在H5页面加载完成后注入jsWebBridge.js对象
@Override
public void onPageFinished(WebView view, String url) {
if (_webViewClient != null) {
_webViewClient.onPageFinished(view, url);
} else {
super.onPageFinished(view, url);
}
// 注入jsWebBridge.js对象
BridgeUtil.LoadLocalJS(view, BridgeConfig.JS_BRIDGE_SCRIPT);
}
java调用js方法需要在js端先注册对应的方法,因为jsWebBridge.js是在h5加载之后才注入,如果在此对象还不存在时注册
js方法不会成功,所以需要做回调执行,通过监听该对象生成后再执行注册
var doc = document;
var readyEvent = doc.createEvent('Events');
readyEvent.initEvent('jsWebBridgeReady');
readyEvent.bridge = jsWebBridge;
doc.dispatchEvent(readyEvent);
在注册前可以先监听jsWebBridgeReady事件,再执行以下方法
// register js func for java call
function registerFuncForJava(funcName, func){
registerFuncMap[funcName] = func;
}
js调用java方法时和java调用js一样的原理,如果需要返回数据则将回调函数添加一个id存储起来,java返回时查找id调用
这里调用java方法是通过java指定的android对象去调用
// js call java func
function callJavaFunc(funcName, params, callback){
var callbackId;
if (callback){
callbackId = BRIDGE_CALL_KEY + (++_callbackId);
responseCallMap[callbackId] = callback;
}
if (funcName){
try{
eval("window.android." + funcName + "('"+JSON.stringify(params)+"','"+callbackId+"')");
}catch(exception){
if (typeof console != 'undefined'){
console.log('jsWebBridge: callJavaFunc java func call fail >>' + funcName);
}
}
}
}
java调用js方法,js在注册表中查找对应的方法执行,并且调用java的方法返回数据
// java call js func
function callFuncFromJava(message){
var msgJson = JSON.parse(message);
var responseCall = null;
var jsFunc = null;
if (msgJson._funcName) {
jsFunc = registerFuncMap[msgJson._funcName];
}
if (msgJson._callFuncKey){
console.log("there is a callback id = " + msgJson._callFuncKey);
responseCall = function(responseData){
sendResponseToJava(msgJson._callFuncKey, responseData);
}
}
if (jsFunc){
try{
jsFunc(msgJson._funcParam, responseCall);
}catch(exception){
if (typeof console != 'undefined'){
console.log('jsWebBridge: callFuncFromJava javascript func call fail >>' + msgJson._funcName);
}
}
}
}
创建一个类用来实现js的方法注册以及java的方法调用,不做过多解释,代码有注释
/**
* 注册可以供native调用的方法
* (if:如果jsWebBridge对象已存在直接注册)
* (else:如果jsWebBridge对象不存在等待jsWebBridgeReady.js加载完给通知再执行注册)
* @param funcName 注册的方法名称
* @param func 注册的方法(example: function(params, responseCall) params:java传的参数 responseCall:回传数据时调用)
* 在回调中如果有对creator ui操作要用event事件派发,否则会操作失败
*/
registerFunc(funcName: string, func: Function){
if(window['jsWebBridge']){
window['jsWebBridge'].registerFuncForJava(funcName, func);
}else{
document.addEventListener(
"jsWebBridgeReady",
function() {
window['jsWebBridge'].registerFuncForJava(funcName, func);
},
false);
}
}
/*
example:
registerFunc("testCallFromJava", testCallFromJava)
testCallFromJava(params, responseCall:Function){
EventManager.getInstance().emit("register", params, responseCall)
}
*/
/**
* 调用Java方法
* @param funcName 方法名
* @param params 参数
* @param receiveCall 接收Java返回的数据函数(在回调中如果有对creator ui操作的行为要用event事件派发)
*/
callJavaFunc(funcName:string, params, receiveCall:Function){
if (window['jsWebBridge']){
window['jsWebBridge'].callJavaFunc(funcName, params, receiveCall)
}
}
Demo地址:https://pan.baidu.com/s/1vnJyxih_aqb7Ymvv2MwpYQ
提取码:2ojd