package com.pandocloud.freeiot.jsbridge; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONObject; import org.xwalk.core.XWalkResourceClient; import org.xwalk.core.XWalkUIClient; import org.xwalk.core.XWalkView; import org.xwalk.core.internal.XWalkJavascriptResultInternal; import org.xwalk.core.internal.XWalkUIClientInternal; import org.xwalk.core.internal.XWalkViewInternal; import org.xwalk.core.internal.XWalkWebChromeClient; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.net.http.SslError; import android.os.Looper; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.webkit.JsResult; import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import com.pandocloud.freeiot.utils.LogUtils; @SuppressLint("SetJavaScriptEnabled") public class BridgeHelper { private final String TAG = "BridgeWebView"; String toLoadJs = null; Map<String, CallBackFunction> mResponseCallbacks = new HashMap<String, CallBackFunction>(); Map<String, BridgeHandler> mMessageHandlers = new HashMap<String, BridgeHandler>(); BridgeHandler defaultHander = new DefaultHandler(); List<Message> startupMessage = null; long uniqueId = 0; private onLoadingListener mLoadingListener; private XWalkView xWalkView; // public BridgeWebView(Context context, AttributeSet attrs) { // super(context, attrs); // init(context); // } // // public BridgeWebView(Context context, AttributeSet attrs, int defStyle) { // super(context, attrs, defStyle); // init(context); // } public BridgeHelper(Context context, XWalkView xWalkView) { this.xWalkView = xWalkView; init(context); } public void setLoadingListener(onLoadingListener loadingListener) { this.mLoadingListener = loadingListener; } /** * * @param toLoadedJsUrl * 要注入的js http地址 * @param handler * 默认的handler,负责处理js端没有指定handlerName的消息,若js端有指定handlerName, * 则由native端注册的指定处理 */ public void initContext(String toLoadedJsUrl, BridgeHandler handler) { if (toLoadedJsUrl != null) { this.toLoadJs = toLoadedJsUrl; } if (handler != null) { this.defaultHander = handler; } } private void init(Context context) { xWalkView.setVerticalScrollBarEnabled(false); xWalkView.setHorizontalScrollBarEnabled(false); xWalkView.setXWalkWebChromeClient(new BridgeWebViewClient(xWalkView)); xWalkView.setResourceClient(new BridgeResourceViewClient(xWalkView)); xWalkView.setUIClient(new BridgeUIClient(xWalkView)); } private void handlerReturnData(String url) { String data = BridgeUtil.getDataFromReturnUrl(url); List<Message> list = null; try { list = Message.toArrayList(data); } catch (Exception e) { e.printStackTrace(); } if (list == null || list.size() == 0) { Log.i(TAG, "message is empty or null..."); } for (int i = 0; i < list.size(); i++) { Message m = list.get(i); String responseId = m.getResponseId(); // 是否是response if (!TextUtils.isEmpty(responseId)) { CallBackFunction fuction = mResponseCallbacks.get(responseId); JSONObject responseData = m.getResponseData(); fuction.onCallBack(responseData); mResponseCallbacks.remove(responseId); } else { CallBackFunction responseFunction = null; // 是否是callbackId final String callbackId = m.getCallbackId(); if (!TextUtils.isEmpty(callbackId)) { responseFunction = new CallBackFunction() { @Override public void onCallBack(JSONObject data) { LogUtils.i(TAG, "responseFunction " + data.toString()); Message responseMsg = new Message(); responseMsg.setResponseId(callbackId); responseMsg.setResponseData(data); queueMessage(responseMsg); } }; } else { responseFunction = new CallBackFunction() { @Override public void onCallBack(JSONObject data) { // do nothing } }; } BridgeHandler handler; if (!TextUtils.isEmpty(m.getHandlerName())) { handler = mMessageHandlers.get(m.getHandlerName()); } else { handler = defaultHander; } if (handler != null) { handler.handler(m.getData(), responseFunction); } else { LogUtils.e("no handler found for "+ m.getHandlerName()); } } } } class BridgeWebViewClient extends XWalkWebChromeClient { public BridgeWebViewClient(XWalkViewInternal view) { super(view); } } class BridgeResourceViewClient extends XWalkResourceClient { public BridgeResourceViewClient(XWalkView view) { super(view); } @Override public void onLoadStarted(XWalkView view, String url) { super.onLoadStarted(view, url); LogUtils.e("onPageStarted=>" + url); if (mLoadingListener != null) { mLoadingListener.onPageStart(); } } @Override public void onLoadFinished(XWalkView view, String url) { super.onLoadFinished(view, url); xWalkView.requestFocus(); } @Override public void onProgressChanged(XWalkView view, int progressInPercent) { if (progressInPercent >= 100) { if (mLoadingListener != null) { mLoadingListener.onPageFinished(); } if (startupMessage != null) { for (Message m : startupMessage) { dispatchMessage(m); } startupMessage = null; } } super.onProgressChanged(view, progressInPercent); } @Override public void onReceivedLoadError(XWalkView view, int errorCode, String description, String failingUrl) { Log.e("failedUrl", "failedUrl; " + failingUrl); Log.e("error", "errorCode: " + errorCode); xWalkView.load("file:///android_asset/failed/404.html", null); } } class BridgeUIClient extends XWalkUIClient { public BridgeUIClient(XWalkView view) { super(view); } @Override public boolean onJavascriptModalDialog(XWalkViewInternal view, JavascriptMessageTypeInternal typeInternal, String url, String message, String defaultValue, XWalkJavascriptResultInternal result) { LogUtils.e("url:" + url+"\n message:" + message); try { String msg = URLDecoder.decode(message, "utf-8"); if (msg.startsWith(BridgeUtil.PANDO_RETURN_DATA)) { // 如果是返回数据 handlerReturnData(message); result.cancel(); return true; } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return super.onJavascriptModalDialog(view, typeInternal, url, message, defaultValue, result); } } private void queueMessage(Message m) { if (startupMessage != null) { LogUtils.e(TAG, "queueMessage# startupMessage is not null..."); startupMessage.add(m); } else { dispatchMessage(m); } } private void dispatchMessage(Message m) { String messageJson = m.toBase64Json(); String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson).trim(); LogUtils.i(TAG, "dispatchMessage " + javascriptCommand); if (Thread.currentThread() == Looper.getMainLooper().getThread()) { LogUtils.e("dispatchMessage#loadUrl"); javascriptCommand = javascriptCommand.replaceAll("\n",""); xWalkView.load(javascriptCommand, null); } } /** * 注册handler,方便web调用 * * @param handlerName * @param handler */ public void registerHandler(String handlerName, BridgeHandler handler) { if (handler != null) { mMessageHandlers.put(handlerName, handler); } } public interface onLoadingListener { public void onPageStart(); public void onPageFinished(); } }