作者:hwj3747
转载请注明
Crosswalk介绍
目前APP的开发模式大多基于H5+原生壳的开发模式,这时候使用到的WebView的性能就至关重要。我们知道,Android平台上,系统的碎片化比较严重,同Android版本的WebView的H5解析能力也有较大差异,导致相应的HTML5应用一致性难以保证。所以在做混合开发的时候,对Android系统的适配是一个比较麻烦的问题。
这个时候,如果能在我们的APP嵌入一个第三方,不使用系统自带浏览器的话,这些问题就都迎刃而解了。Crosswalk就是这样一个第三方浏览器,其具有较好的H5性、功能支持,较好的平台一致性,以及近似原生应用的系统整合体验。
Crosswalk项目具有以下优势:
最大限度降低Android碎片化的影响,得到一致的,可预测的行为。
使用最新的Web技术及API。在Android 4.0+版本上提供丰富的功能。
使用Chrome DevTools轻松调试。(很方便的功能,可以直接在谷歌浏览器上进行调试,只不过需要翻墙)
提升应用中HTML,CSS和JavaScript的性能。
WebViewJavascriptBridge介绍
WebViewJavascriptBridge 是盛名已久的 JSBridge 库,其主要作用是作为原生native与web JS沟通的“桥梁”,讲人话就是,能实现JS调用原生代码,以及原生调用JS的这么一个功能。目前该库已经累计获得1W+的start,并且已经有很多成熟的项目在使用这个库了,由此可见,该库是被广大开发者所认可的。
美中不足的是,目前官方只支持IOS版本的库。万幸它是开源的,许多人大神都基于它实现了支持Android版本的WebViewJavascriptBridge。比如说我使用到的是“大头鬼”开发的一个库:WebViewJavascriptBridge。
准备工作
首先,先从crosswalk官网下载aar包
我用到的是这个包:crosswalk-23.53.589.4.aar
然后从github上down下WebViewJavascriptBridge库,导入Android studio
然后在该项目的基础上导入crosswalk的aar包:
集成方法:
- 设置grade外部库为libs,拷贝aar文件到libs**
repositories { flatDir { dirs 'libs' }}
- 关联crosswalk库
compile(name: 'crosswalk-23.53.589.4', ext: 'aar')
然后同步一下代码就准备就绪了
使用Crosswalk和WebViewJavascriptBridge开发应用
打开项目,发现原本的项目用的还是系统自带的webview以及WebViewClient
public class BridgeWebView extends WebView implements WebViewJavascriptBridge
public class BridgeWebViewClient extends WebViewClient
我们要做的就是把这两个替换成相应的crosswalk的XWalkView和XWalkResourceClient
所以新建一个类,模仿BridgeWebView 的写法,把BridgeWebView 相关的注册和处理handle,消息分发,等操作搬到自定义的XWalkView上。
@SuppressLint("SetJavaScriptEnabled")public class MyXWalkView extends XWalkView implements WebViewJavascriptBridge { private final String TAG = "BridgeWebView"; public static final String toLoadJs = "WebViewJavascriptBridge.js"; Map<String, CallBackFunction> responseCallbacks = new HashMap<String, CallBackFunction>(); Map<String, BridgeHandler> messageHandlers = new HashMap<String, BridgeHandler>(); BridgeHandler defaultHandler = new DefaultHandler(); private List<Message> startupMessage = new ArrayList<Message>(); public List<Message> getStartupMessage() { return startupMessage; } public void setStartupMessage(List<Message> startupMessage) { this.startupMessage = startupMessage; } private long uniqueId = 0; public MyXWalkView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MyXWalkView(Context context) { super(context); init(); } /** * * @param handler * default handler,handle messages send by js without assigned handler name, * if js message has handler name, it will be handled by named handlers registered by native */ public void setDefaultHandler(BridgeHandler handler) { this.defaultHandler = handler; } private void init() { this.setVerticalScrollBarEnabled(false); this.setHorizontalScrollBarEnabled(false); this.getSettings().setJavaScriptEnabled(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { WebView.setWebContentsDebuggingEnabled(true); } this.setResourceClient(new MyXWalkResourceClient(this)); } /** * 获取到CallBackFunction data执行调用并且从数据集移除 * @param url */ void handlerReturnData(String url) { String functionName = BridgeUtil.getFunctionFromReturnUrl(url); CallBackFunction f = responseCallbacks.get(functionName); String data = BridgeUtil.getDataFromReturnUrl(url); if (f != null) { f.onCallBack(data); responseCallbacks.remove(functionName); return; } } @Override public void send(String data) { send(data, null); } @Override public void send(String data, CallBackFunction responseCallback) { doSend(null, data, responseCallback); } /** * 保存message到消息队列 * @param handlerName handlerName * @param data data * @param responseCallback CallBackFunction */ private void doSend(String handlerName, String data, CallBackFunction responseCallback) { Message m = new Message(); if (!TextUtils.isEmpty(data)) { m.setData(data); } if (responseCallback != null) { String callbackStr = String.format(BridgeUtil.CALLBACK_ID_FORMAT, ++uniqueId + (BridgeUtil.UNDERLINE_STR + SystemClock.currentThreadTimeMillis())); responseCallbacks.put(callbackStr, responseCallback); m.setCallbackId(callbackStr); } if (!TextUtils.isEmpty(handlerName)) { m.setHandlerName(handlerName); } queueMessage(m); } /** * list<message> != null 添加到消息集合否则分发消息 * @param m Message */ private void queueMessage(Message m) { if (startupMessage != null) { startupMessage.add(m); } else { dispatchMessage(m); } } /** * 分发message 必须在主线程才分发成功 * @param m Message */ void dispatchMessage(Message m) { String messageJson = m.toJson(); //escape special characters for json string 为json字符串转义特殊字符 messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); // 必须要找主线程才会将数据传递出去 --- 划重点 if (Thread.currentThread() == Looper.getMainLooper().getThread()) { this.loadUrl(javascriptCommand); } } /** * 刷新消息队列 */ void flushMessageQueue() { if (Thread.currentThread() == Looper.getMainLooper().getThread()) { loadUrl(BridgeUtil.JS_FETCH_QUEUE_FROM_JAVA, new CallBackFunction() { @Override public void onCallBack(String data) { // deserializeMessage 反序列化消息 List<Message> list = null; try { list = Message.toArrayList(data); } catch (Exception e) { e.printStackTrace(); return; } if (list == null || list.size() == 0) { return; } for (int i = 0; i < list.size(); i++) { Message m = list.get(i); String responseId = m.getResponseId(); // 是否是response CallBackFunction if (!TextUtils.isEmpty(responseId)) { CallBackFunction function = responseCallbacks.get(responseId); String responseData = m.getResponseData(); function.onCallBack(responseData); responseCallbacks.remove(responseId); } else { CallBackFunction responseFunction = null; // if had callbackId 如果有回调Id final String callbackId = m.getCallbackId(); if (!TextUtils.isEmpty(callbackId)) { responseFunction = new CallBackFunction() { @Override public void onCallBack(String data) { Message responseMsg = new Message(); responseMsg.setResponseId(callbackId); responseMsg.setResponseData(data); queueMessage(responseMsg); } }; } else { responseFunction = new CallBackFunction() { @Override public void onCallBack(String data) { // do nothing } }; } // BridgeHandler执行 BridgeHandler handler; if (!TextUtils.isEmpty(m.getHandlerName())) { handler = messageHandlers.get(m.getHandlerName()); } else { handler = defaultHandler; } if (handler != null){ handler.handler(m.getData(), responseFunction); }
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。