Android混合开发(一)——移动端与前端交互之JSBridge引入
一丶概述
最近转前端,在做一个混合项目,Android + 前端Vue技术,Vue没那么快上手,先分享一下Android部分的经验,后期会学习Flutter,和RN,边学边做边分享
二丶效果演示
三丶JSBridge引入
1.什么是JSBridge
JSBridge是移动UIView和Html交互通信的桥梁,就是实现java(ios为oc)和js的互相调用的桥梁。出于安全考虑,android自4.4后不建议使用@JavascriptInterface注解,所以Android4.4以后就没有了默认的Jsbridge的实现,替代了WebView的自带JavascriptInterface的接口,使得我们的开发更加灵活和安全。
说明:
(1).JSBridge作用是移动端和前端通信;
(2).Java oc js要分别实现;
(3).替代JavascriptInterface的接口,安全;
2.JSBridge集成
GitHub全局搜索JSBridge
star最多,Android端一般会选择上面一个,iOS端会选择下面一个
这样前端的同事就得注意了,两者初始化方法不一样,需要分别对接解决兼容问题
当然也有大牛解决这个问题
DSBridge
这里由于跟iOS没达成一致选择了上面的方式
四丶效果实现
效果作用,演示Android与前端方法互相调用
1.添加依赖
repositories { // ... maven { url "https://jitpack.io" }}dependencies { compile 'com.github.lzyzsd:jsbridge:1.0.4'}
2.布局页面
<?xml version="1.0" encoding="utf-8"?>
3.Android端桥注册及调用
public class MixedActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mixed_activity); Button btn = (Button) findViewById(R.id.btn); final EditText etText = (EditText) findViewById(R.id.et_text); final BridgeWebView bridgeWebView = (BridgeWebView) findViewById(R.id.JsBridgeWebView); bridgeWebView.setDefaultHandler(new DefaultHandler()); bridgeWebView.setWebChromeClient(new WebChromeClient()); bridgeWebView.loadUrl("file:///android_asset/a.html"); /** * js调用Android * * 参数一:getUserInfo就是注册供JS调用的方法名, * 参数二:data是JS传过来的参数, * 参数三:CallBackFunction 函数中需要把JS需要的response返回给JS */ bridgeWebView.registerHandler("submitFromWeb", new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { Log.e("TAG", "js返回:" + data); //显示js传递给Android的消息 Toast.makeText(MixedActivity.this, "js返回:" + data, Toast.LENGTH_LONG).show(); //Android返回给JS的消息 function.onCallBack("我是js调用Android返回数据:" + etText.getText().toString()); } }); /** * Android调用js * * 参数一:js中的方法名称 * 参数二:Android传递给js数据 * 参数三:回调接口,data为Android调用js方法的返回数据 */ btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { bridgeWebView.callHandler("functionInJs", "Android调用js的方法", new CallBackFunction() { @Override public void onCallBack(String data) { Log.e("TAG", "onCallBack:" + data); Toast.makeText(MixedActivity.this, data, Toast.LENGTH_LONG).show(); } }); } }); }}
注意点:1.桥名称相同;2.传递数据类型相同(android只能String,所以统一String)
4.前端JSBridge实现
这里要做重点注意,这边开发由于是iOS与前端先调试完,再调试Android,方法各种调不通,明明参考的同一篇博客,就是无效。原因呢:注册的方式不对,与iOS的方式只有细节上的不同。
丢给前端一个文件,分别做兼容,才解决问题
WebViewJavascriptBridge.js
//notation: js file can only use this kind of comments//since comments will cause error when use in webview.loadurl,//comments will be remove by java use regexp(function() { if (window.WebViewJavascriptBridge) { return; } var messagingIframe; var sendMessageQueue = []; var receiveMessageQueue = []; var messageHandlers = {}; var CUSTOM_PROTOCOL_SCHEME = 'yy'; var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/'; var responseCallbacks = {}; var uniqueId = 1; function _createQueueReadyIframe(doc) { messagingIframe = doc.createElement('iframe'); messagingIframe.style.display = 'none'; doc.documentElement.appendChild(messagingIframe); } //set default messageHandler function init(messageHandler) { if (WebViewJavascriptBridge._messageHandler) { throw new Error('WebViewJavascriptBridge.init called twice'); } WebViewJavascriptBridge._messageHandler = messageHandler; var receivedMessages = receiveMessageQueue; receiveMessageQueue = null; for (var i = 0; i < receivedMessages.length; i++) { _dispatchMessageFromNative(receivedMessages[i]); } } function send(data, responseCallback) { _doSend({ data: data }, responseCallback); } function registerHandler(handlerName, handler) { messageHandlers[handlerName] = handler; } function callHandler(handlerName, data, responseCallback) { _doSend({ handlerName: handlerName, data: data }, responseCallback); } //sendMessage add message, 触发native处理 sendMessage function _doSend(message, responseCallback) { if (responseCallback) { var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime(); responseCallbacks[callbackId] = responseCallback; message.callbackId = callbackId; } sendMessageQueue.push(message); messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; } // 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容 function _fetchQueue() { var messageQueueString = JSON.stringify(sendMessageQueue); sendMessageQueue = []; //android can't read directly the return data, so we can reload iframe src to communicate with java messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString); } //提供给native使用, function _dispatchMessageFromNative(messageJSON) { setTimeout(function() { var message = JSON.parse(messageJSON); var responseCallback; //java call finished, now need to call js callback function if (message.responseId) { responseCallback = responseCallbacks[message.responseId]; if (!responseCallback) { return; } responseCallback(message.responseData); delete responseCallbacks[message.responseId]; } else { //直接发送 if (message.callbackId) { var callbackResponseId = message.callbackId; responseCallback = function(responseData) { _doSend({ responseId: callbackResponseId, responseData: responseData }); }; } var handler = WebViewJavascriptBridge._messageHandler; if (message.handlerName) { handler = messageHandlers[message.handlerName]; } //查找指定handler try { handler(message.data, responseCallback); } catch (exception) { if (typeof console != 'undefined') { console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception); } } } }); } //提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以 function _handleMessageFromNative(messageJSON) { console.log(messageJSON); if (receiveMessageQueue && receiveMessageQueue.length > 0) { receiveMessageQueue.push(messageJSON); } else { _dispatchMessageFromNative(messageJSON); } } var WebViewJavascriptBridge = window.WebViewJavascriptBridge = { init: init, send: send, registerHandler: registerHandler, callHandler: callHandler, _fetchQueue: _fetchQueue, _handleMessageFromNative: _handleMessageFromNative }; var doc = document; _createQueueReadyIframe(doc); var readyEvent = doc.createEvent('Events'); readyEvent.initEvent('WebViewJavascriptBridgeReady'); readyEvent.bridge = WebViewJavascriptBridge; doc.dispatchEvent(readyEvent);})();
jsbridgewebview加载的html
js调用java
写在最后微信扫码提问
源码下载:
https://github.com/JinBoy23520/CoderToDeveloperByTCLer
如果文章对你有帮助,欢迎点赞关注
更多相关文章
- Android工程引用另外一个工程的正确/错误方法
- Android(安卓)和 Webview 如何相互 sayHello(一)
- 简述Android(安卓)解决65536/64K方法数限制方案
- 调用Android常用应用的接口
- Android(安卓)—— 自定义View的实现方法
- Android真机连接Eclipse时,打不开File Explorer下的data文件夹解
- Android(安卓)UI事件处理、focus处理
- Qt on Android: http下载与Json解析
- Android中的单例模式