From c092aabe0d0f66dc895a250ced84f3ce61792b9c Mon Sep 17 00:00:00 2001 From: "Guo,Feng(RIM)" Date: Wed, 11 Jul 2018 20:16:30 +0800 Subject: [PATCH 01/13] comment build error --- library/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/build.gradle b/library/build.gradle index 0dc5ef9..e620b62 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -29,7 +29,7 @@ dependencies { def siteUrl = 'https://github.com/lzyzsd/JsBridge' def gitUrl = 'https://github.com/lzyzsd/JsBridge.git' -apply plugin: 'com.github.dcendents.android-maven' +// apply plugin: 'com.github.dcendents.android-maven' group = "com.github.lzyzsd.jsbridge" task sourcesJar(type: Jar) { from android.sourceSets.main.java.srcDirs From 0a39a7103f8a68b9a6f651cad108daad9e75f7fd Mon Sep 17 00:00:00 2001 From: "Guo,Feng(RIM)" Date: Wed, 11 Jul 2018 20:31:32 +0800 Subject: [PATCH 02/13] =?UTF-8?q?json=20=E8=BD=AC=E4=B9=89=E7=94=A8?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=8E=9F=E7=94=9F=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E6=89=8B=E5=8A=A8=E6=9B=BF=E6=8D=A2=E8=BD=AC=E4=B9=89=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E4=B8=8D=E5=AE=8C=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/github/lzyzsd/jsbridge/BridgeUtil.java | 2 +- .../java/com/github/lzyzsd/jsbridge/BridgeWebView.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeUtil.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeUtil.java index ae9e55c..ce8f22e 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeUtil.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeUtil.java @@ -17,7 +17,7 @@ public class BridgeUtil { final static String SPLIT_MARK = "/"; final static String CALLBACK_ID_FORMAT = "JAVA_CB_%s"; - final static String JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');"; + final static String JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative(%s);"; final static String JS_FETCH_QUEUE_FROM_JAVA = "javascript:WebViewJavascriptBridge._fetchQueue();"; public final static String JAVASCRIPT_STR = "javascript:"; diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java index b24db85..34cece8 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java @@ -9,6 +9,8 @@ import android.util.AttributeSet; import android.webkit.WebView; +import org.json.JSONObject; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -141,9 +143,8 @@ private void queueMessage(Message m) { void dispatchMessage(Message m) { String messageJson = m.toJson(); //escape special characters for json string 为json字符串转义特殊字符 - messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); - messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); - messageJson = messageJson.replaceAll("(?<=[^\\\\])(\')", "\\\\\'"); + // 系统原生 API 做 Json转义,没必要自己正则替换,而且替换不一定完整 + messageJson = JSONObject.quote(messageJson); String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); // 必须要找主线程才会将数据传递出去 --- 划重点 if (Thread.currentThread() == Looper.getMainLooper().getThread()) { From f6893a41f18c50c1e53de7b8823faf05eee85458 Mon Sep 17 00:00:00 2001 From: wangguangzhao Date: Thu, 13 Jun 2019 17:11:00 +0800 Subject: [PATCH 03/13] =?UTF-8?q?fixbug=20WebView=20loadurl=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=9C=A819=E4=BB=A5=E4=B8=8A=E8=B6=85=E8=BF=872097152?= =?UTF-8?q?=E4=B8=AA=E5=AD=97=E7=AC=A6=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/github/lzyzsd/jsbridge/BridgeWebView.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java index 5728681..6c93680 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java @@ -7,10 +7,9 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.AttributeSet; -import android.webkit.SslErrorHandler; import android.webkit.WebView; -import java.net.URLEncoder; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -21,6 +20,7 @@ public class BridgeWebView extends WebView implements WebViewJavascriptBridge{ private final String TAG = "BridgeWebView"; + private final int URL_MAX_CHARACTER_NUM=2097152; public static final String toLoadJs = "WebViewJavascriptBridge.js"; Map responseCallbacks = new HashMap(); Map messageHandlers = new HashMap(); @@ -152,7 +152,11 @@ void dispatchMessage(Message m) { String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); // 必须要找主线程才会将数据传递出去 --- 划重点 if (Thread.currentThread() == Looper.getMainLooper().getThread()) { - this.loadUrl(javascriptCommand); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT&&javascriptCommand.length()>=URL_MAX_CHARACTER_NUM) { + this.evaluateJavascript(javascriptCommand,null); + }else { + this.loadUrl(javascriptCommand); + } } } From 35ea1039e75ad7ae4b936ebf1369bfe2eab84609 Mon Sep 17 00:00:00 2001 From: ZhengAn Date: Sun, 7 Jul 2019 17:10:15 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E6=B7=BB=E5=8A=A0BridgeHelper=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB,=E6=8F=90=E4=BE=9B=E4=B8=8D=E7=BB=A7?= =?UTF-8?q?=E6=89=BFBridgeWebView=E4=B9=9F=E8=83=BD=E9=9B=86=E6=88=90JSBri?= =?UTF-8?q?dge=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../github/lzyzsd/jsbridge/BridgeHelper.java | 286 ++++++++++++++++++ .../com/github/lzyzsd/jsbridge/IWebView.java | 16 + 2 files changed, 302 insertions(+) create mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java create mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/IWebView.java diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java new file mode 100644 index 0000000..18b18fc --- /dev/null +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java @@ -0,0 +1,286 @@ +package com.github.lzyzsd.jsbridge; + +import android.os.Looper; +import android.os.SystemClock; +import android.text.TextUtils; +import android.util.Log; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * JsBridge辅助类,帮助集成JsBridge功能. + * + * @author ZhengAn + * @date 2019-06-30 + */ +public class BridgeHelper implements WebViewJavascriptBridge { + + private static final String TAG = "BridgeHelper"; + + private static final String BRIDGE_JS = "WebViewJavascriptBridge.js"; + private Map responseCallbacks = new HashMap<>(); + private Map messageHandlers = new HashMap<>(); + private BridgeHandler defaultHandler = new DefaultHandler(); + + private List startupMessage = new ArrayList<>(); + + private List getStartupMessage() { + return startupMessage; + } + + private void setStartupMessage(List startupMessage) { + this.startupMessage = startupMessage; + } + + private long uniqueId = 0; + + private IWebView webView; + + public BridgeHelper(IWebView webView) { + this.webView = webView; + } + + /** + * @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; + } + + /** + * 获取到CallBackFunction data执行调用并且从数据集移除 + * + * @param url + */ + private 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); + } + } + + @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 != null 添加到消息集合否则分发消息 + * + * @param m Message + */ + private void queueMessage(Message m) { + if (startupMessage != null) { + startupMessage.add(m); + } else { + dispatchMessage(m); + } + } + + /** + * 分发message 必须在主线程才分发成功 + * + * @param m Message + */ + private void dispatchMessage(Message m) { + String messageJson = m.toJson(); + //escape special characters for json string 为json字符串转义特殊字符 + messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); + messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); + messageJson = messageJson.replaceAll("(?<=[^\\\\])(\')", "\\\\\'"); + messageJson = messageJson.replaceAll("%7B", URLEncoder.encode("%7B")); + messageJson = messageJson.replaceAll("%7D", URLEncoder.encode("%7D")); + messageJson = messageJson.replaceAll("%22", URLEncoder.encode("%22")); + String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); + // 必须要找主线程才会将数据传递出去 --- 划重点 + if (Thread.currentThread() == Looper.getMainLooper().getThread()) { + this.loadUrl(javascriptCommand); + } + } + + /** + * 刷新消息队列 + */ + private 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 list = null; + try { + list = Message.toArrayList(data); + } catch (Exception e) { + Log.w(TAG, e); + return; + } + if (list == null || list.isEmpty()) { + 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); + } + } + } + } + }); + } + } + + private void loadUrl(String jsUrl, CallBackFunction returnCallback) { + this.loadUrl(jsUrl); + // 添加至 Map + responseCallbacks.put(BridgeUtil.parseFunctionName(jsUrl), returnCallback); + } + + private void loadUrl(String jsUrl) { + webView.loadUrl(jsUrl); + } + + /** + * register handler,so that javascript can call it + * 注册处理程序,以便javascript调用它 + * + * @param handlerName handlerName + * @param handler BridgeHandler + */ + public void registerHandler(String handlerName, BridgeHandler handler) { + if (handler != null) { + // 添加至 Map + messageHandlers.put(handlerName, handler); + } + } + + /** + * unregister handler + * + * @param handlerName + */ + public void unregisterHandler(String handlerName) { + if (handlerName != null) { + messageHandlers.remove(handlerName); + } + } + + /** + * call javascript registered handler + * 调用javascript处理程序注册 + * + * @param handlerName handlerName + * @param data data + * @param callBack CallBackFunction + */ + public void callHandler(String handlerName, String data, CallBackFunction callBack) { + doSend(handlerName, data, callBack); + } + + public void onPageFinished() { + webViewLoadLocalJs(); + + if (getStartupMessage() != null) { + for (Message m : getStartupMessage()) { + dispatchMessage(m); + } + setStartupMessage(null); + } + } + + private void webViewLoadLocalJs() { + String jsContent = BridgeUtil.assetFile2Str(webView.getContext(), BridgeHelper.BRIDGE_JS); + loadUrl("javascript:" + jsContent); + } + + public boolean shouldOverrideUrlLoading(String url) { + try { + url = URLDecoder.decode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + Log.w(TAG, e); + } + + if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { // 如果是返回数据 + handlerReturnData(url); + return true; + } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { // + flushMessageQueue(); + return true; + } + return false; + } +} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/IWebView.java b/library/src/main/java/com/github/lzyzsd/jsbridge/IWebView.java new file mode 100644 index 0000000..8de9867 --- /dev/null +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/IWebView.java @@ -0,0 +1,16 @@ +package com.github.lzyzsd.jsbridge; + +import android.content.Context; + +/** + * WebView功能接口. + * + * @author ZhengAn + * @date 2019-07-01 + */ +public interface IWebView { + + Context getContext(); + + void loadUrl(String url); +} From 576336aa053c4bd52d2fca71a6cf8b5929d3c501 Mon Sep 17 00:00:00 2001 From: ZhengAn Date: Sun, 7 Jul 2019 17:43:15 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E6=B7=BB=E5=8A=A0CustomWebView-=E4=BD=BF?= =?UTF-8?q?=E7=94=A8BridgeHelper=E9=9B=86=E6=88=90JSBridge=E7=9A=84?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsbridge/example/CustomWebView.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 example/src/main/java/com/github/lzyzsd/jsbridge/example/CustomWebView.java diff --git a/example/src/main/java/com/github/lzyzsd/jsbridge/example/CustomWebView.java b/example/src/main/java/com/github/lzyzsd/jsbridge/example/CustomWebView.java new file mode 100644 index 0000000..1b5935c --- /dev/null +++ b/example/src/main/java/com/github/lzyzsd/jsbridge/example/CustomWebView.java @@ -0,0 +1,115 @@ +package com.github.lzyzsd.jsbridge.example; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import com.github.lzyzsd.jsbridge.BridgeHandler; +import com.github.lzyzsd.jsbridge.BridgeHelper; +import com.github.lzyzsd.jsbridge.CallBackFunction; +import com.github.lzyzsd.jsbridge.IWebView; +import com.github.lzyzsd.jsbridge.WebViewJavascriptBridge; + +/** + * 采用BridgeHelper集成JsBridge功能示例.定制WebView,可只添加实际需要的JsBridge接口. + * + * @author ZhengAn + * @date 2019-07-07 + */ +@SuppressLint("SetJavaScriptEnabled") +public class CustomWebView extends WebView implements WebViewJavascriptBridge, IWebView { + + private BridgeHelper bridgeHelper; + + public CustomWebView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public CustomWebView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public CustomWebView(Context context) { + super(context); + init(); + } + + 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); + } + + bridgeHelper = new BridgeHelper(this); + this.setWebViewClient(new WebViewClient() { + @Override + public void onPageFinished(WebView webView, String s) { + bridgeHelper.onPageFinished(); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView webView, String s) { + return bridgeHelper.shouldOverrideUrlLoading(s); + } + }); + } + + /** + * @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) { + bridgeHelper.setDefaultHandler(handler); + } + + @Override + public void send(String data) { + send(data, null); + } + + @Override + public void send(String data, CallBackFunction responseCallback) { + bridgeHelper.send(data, responseCallback); + } + + + /** + * register handler,so that javascript can call it + * 注册处理程序,以便javascript调用它 + * + * @param handlerName handlerName + * @param handler BridgeHandler + */ + public void registerHandler(String handlerName, BridgeHandler handler) { + bridgeHelper.registerHandler(handlerName, handler); + } + + /** + * unregister handler + * + * @param handlerName + */ + public void unregisterHandler(String handlerName) { + bridgeHelper.unregisterHandler(handlerName); + } + + /** + * call javascript registered handler + * 调用javascript处理程序注册 + * + * @param handlerName handlerName + * @param data data + * @param callBack CallBackFunction + */ + public void callHandler(String handlerName, String data, CallBackFunction callBack) { + bridgeHelper.callHandler(handlerName, data, callBack); + } + +} From 914840315588b9bcf84cf3bc58a94782a48a8c85 Mon Sep 17 00:00:00 2001 From: wxj Date: Wed, 10 Jul 2019 19:01:25 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E6=9C=80=E5=B0=8Fapi=E4=B8=BA17=EF=BC=88?= =?UTF-8?q?google=E4=BF=AE=E5=A4=8D=E4=BA=86js=E7=9A=84=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E6=80=A7=E6=BC=8F=E6=B4=9E=EF=BC=89=EF=BC=8C=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E9=BB=98=E8=AE=A4android=E9=BB=98=E8=AE=A4js=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JsBridge.zip | Bin 0 -> 257763 bytes build.gradle | 4 +- example/build.gradle | 14 +- example/src/main/assets/demo.html | 79 ++-- .../lzyzsd/jsbridge/example/MainActivity.java | 29 +- .../example/MainJavascrotInterface.java | 36 ++ gradle.properties | 2 + gradle/wrapper/gradle-wrapper.properties | 2 +- library/build.gradle | 31 +- .../main/assets/WebViewJavascriptBridge.js | 80 ++-- .../github/lzyzsd/jsbridge/BridgeHandler.java | 7 - .../github/lzyzsd/jsbridge/BridgeUtil.java | 61 +-- .../github/lzyzsd/jsbridge/BridgeWebView.java | 408 +++++++++--------- .../lzyzsd/jsbridge/BridgeWebViewClient.java | 261 ++++++++--- .../lzyzsd/jsbridge/CallBackFunction.java | 7 - .../lzyzsd/jsbridge/DefaultHandler.java | 14 - .../com/github/lzyzsd/jsbridge/JSRequest.java | 15 + .../github/lzyzsd/jsbridge/JSResponse.java | 13 + .../com/github/lzyzsd/jsbridge/Message.java | 118 ----- .../lzyzsd/jsbridge/OnBridgeCallback.java | 7 + .../jsbridge/WebViewJavascriptBridge.java | 11 +- 21 files changed, 583 insertions(+), 616 deletions(-) create mode 100644 JsBridge.zip create mode 100644 example/src/main/java/com/github/lzyzsd/jsbridge/example/MainJavascrotInterface.java delete mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHandler.java delete mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/CallBackFunction.java delete mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/DefaultHandler.java create mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/JSRequest.java create mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/JSResponse.java delete mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/Message.java create mode 100644 library/src/main/java/com/github/lzyzsd/jsbridge/OnBridgeCallback.java diff --git a/JsBridge.zip b/JsBridge.zip new file mode 100644 index 0000000000000000000000000000000000000000..d2c837bc4139855c3578f56e6f37ff1650a19ac7 GIT binary patch literal 257763 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 _fetchQueue - public static String parseFunctionName(String jsUrl){ - return jsUrl.replace("javascript:WebViewJavascriptBridge.", "").replaceAll("\\(.*\\);", ""); - } - - // 获取到传递信息的body值 - // url = yy://return/_fetchQueue/[{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] - public static String getDataFromReturnUrl(String url) { - if(url.startsWith(YY_FETCH_QUEUE)) { - // return = [{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] - return url.replace(YY_FETCH_QUEUE, EMPTY_STR); - } - - // temp = _fetchQueue/[{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] - String temp = url.replace(YY_RETURN_DATA, EMPTY_STR); - String[] functionAndData = temp.split(SPLIT_MARK); - - if(functionAndData.length >= 2) { - StringBuilder sb = new StringBuilder(); - for (int i = 1; i < functionAndData.length; i++) { - sb.append(functionAndData[i]); - } - // return = [{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] - return sb.toString(); - } - return null; - } - - // 获取到传递信息的方法 - // url = yy://return/_fetchQueue/[{"responseId":"JAVA_CB_1_360","responseData":"Javascript Says Right back aka!"}] - public static String getFunctionFromReturnUrl(String url) { - // temp = _fetchQueue/[{"responseId":"JAVA_CB_1_360","responseData":"Javascript Says Right back aka!"}] - String temp = url.replace(YY_RETURN_DATA, EMPTY_STR); - String[] functionAndData = temp.split(SPLIT_MARK); - if(functionAndData.length >= 1){ - // functionAndData[0] = _fetchQueue - return functionAndData[0]; - } - return null; - } + public static final String JAVA_SCRIPT = "WebViewJavascriptBridge.js"; + public final static String UNDERLINE_STR = "_"; + public final static String CALLBACK_ID_FORMAT = "JAVA_CB_%s"; + public final static String JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');"; + public final static String JAVASCRIPT_STR = "javascript:%s"; - - /** * js 文件将注入为第一个script引用 * @param view WebView @@ -117,6 +69,7 @@ public static String assetFile2Str(Context c, String urlStr){ try { in.close(); } catch (IOException e) { + e.printStackTrace(); } } } diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java index 5728681..37f69a1 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java @@ -5,150 +5,190 @@ import android.os.Build; import android.os.Looper; import android.os.SystemClock; +import androidx.collection.ArrayMap; import android.text.TextUtils; import android.util.AttributeSet; -import android.webkit.SslErrorHandler; +import android.util.Log; +import android.webkit.JavascriptInterface; +import android.webkit.WebSettings; import android.webkit.WebView; -import java.net.URLEncoder; +import android.webkit.WebViewClient; + +import com.github.lzyzsd.library.BuildConfig; +import com.google.gson.Gson; +import java.net.URLEncoder; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @SuppressLint("SetJavaScriptEnabled") -public class BridgeWebView extends WebView implements WebViewJavascriptBridge{ - - private final String TAG = "BridgeWebView"; +public class BridgeWebView extends WebView implements WebViewJavascriptBridge, BridgeWebViewClient.OnLoadJSListener { - public static final String toLoadJs = "WebViewJavascriptBridge.js"; - Map responseCallbacks = new HashMap(); - Map messageHandlers = new HashMap(); - BridgeHandler defaultHandler = new DefaultHandler(); + private Map mCallbacks = new ArrayMap<>(); - private List startupMessage = new ArrayList(); + private List mMessages = new ArrayList<>(); - public List getStartupMessage() { - return startupMessage; - } + private BridgeWebViewClient mClient; - public void setStartupMessage(List startupMessage) { - this.startupMessage = startupMessage; - } + private long mUniqueId = 0; - private long uniqueId = 0; + private boolean mJSLoaded = false; - public BridgeWebView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } + private Gson mGson; - public BridgeWebView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } + public BridgeWebView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } - public BridgeWebView(Context context) { - super(context); - init(); - } + public BridgeWebView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + 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; - } + public BridgeWebView(Context context) { + super(context); + init(); + } private void init() { - this.setVerticalScrollBarEnabled(false); - this.setHorizontalScrollBarEnabled(false); - this.getSettings().setJavaScriptEnabled(true); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + clearCache(true); + getSettings().setUseWideViewPort(true); +// webView.getSettings().setLoadWithOverviewMode(true); + getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); + getSettings().setJavaScriptEnabled(true); +// mContent.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + getSettings().setJavaScriptCanOpenWindowsAutomatically(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG) { WebView.setWebContentsDebuggingEnabled(true); } - this.setWebViewClient(generateBridgeWebViewClient()); - } + mClient = new BridgeWebViewClient(this); + super.setWebViewClient(mClient); + } + + public void setGson(Gson gson) { + mGson = gson; + } + + public boolean isJSLoaded() { + return mJSLoaded; + } + + public Map getCallbacks() { + return mCallbacks; + } + + @Override + public void setWebViewClient(WebViewClient client) { + mClient.setWebViewClient(client); + } - protected BridgeWebViewClient generateBridgeWebViewClient() { - return new BridgeWebViewClient(this); + @Override + public void onLoadStart() { + mJSLoaded = false; + } + + @Override + public void onLoadFinished() { + mJSLoaded = true; + if (mMessages != null) { + for (Object message : mMessages) { + dispatchMessage(message); + } + mMessages = null; + } + } + + @Override + public void sendToWeb(Object data) { + sendToWeb(data, (OnBridgeCallback) null); + } + + @Override + public void sendToWeb(Object data, OnBridgeCallback responseCallback) { + doSend(null, data, responseCallback); } /** - * 获取到CallBackFunction data执行调用并且从数据集移除 - * @param url + * call javascript registered handler + * 调用javascript处理程序注册 + * + * @param handlerName handlerName + * @param data data + * @param callBack OnBridgeCallback */ - 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); - } + public void callHandler(String handlerName, String data, OnBridgeCallback callBack) { + doSend(handlerName, data, callBack); + } + + + @Override + public void sendToWeb(String function, Object... values) { + // 必须要找主线程才会将数据传递出去 --- 划重点 + if (Thread.currentThread() == Looper.getMainLooper().getThread()) { + String jsCommand = String.format(function, values); + jsCommand = String.format(BridgeUtil.JAVASCRIPT_STR, jsCommand); + loadUrl(jsCommand); + } + } /** * 保存message到消息队列 - * @param handlerName handlerName - * @param data data - * @param responseCallback CallBackFunction + * + * @param handlerName handlerName + * @param data data + * @param responseCallback OnBridgeCallback */ - 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); - } + private void doSend(String handlerName, Object data, OnBridgeCallback responseCallback) { + if (!(data instanceof String) && mGson == null){ + return; + } + JSRequest request = new JSRequest(); + if (data != null) { + request.data = data instanceof String ? (String) data : mGson.toJson(data); + } + if (responseCallback != null) { + String callbackId = String.format(BridgeUtil.CALLBACK_ID_FORMAT, (++mUniqueId) + (BridgeUtil.UNDERLINE_STR + SystemClock.currentThreadTimeMillis())); + mCallbacks.put(callbackId, responseCallback); + request.callbackId = callbackId; + } + if (!TextUtils.isEmpty(handlerName)) { + request.handlerName = handlerName; + } + queueMessage(request); + } /** * list != null 添加到消息集合否则分发消息 - * @param m Message + * + * @param message Message */ - private void queueMessage(Message m) { - if (startupMessage != null) { - startupMessage.add(m); - } else { - dispatchMessage(m); - } - } + private void queueMessage(Object message) { + if (mMessages != null) { + mMessages.add(message); + } else { + dispatchMessage(message); + } + } /** * 分发message 必须在主线程才分发成功 - * @param m Message + * + * @param message Message */ - void dispatchMessage(Message m) { - String messageJson = m.toJson(); + private void dispatchMessage(Object message) { + if (mGson == null){ + return; + } + String messageJson = mGson.toJson(message); //escape special characters for json string 为json字符串转义特殊字符 messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); - messageJson = messageJson.replaceAll("(?<=[^\\\\])(\')", "\\\\\'"); - messageJson = messageJson.replaceAll("%7B", URLEncoder.encode("%7B")); - messageJson = messageJson.replaceAll("%7D", URLEncoder.encode("%7D")); - messageJson = messageJson.replaceAll("%22", URLEncoder.encode("%22")); + messageJson = messageJson.replaceAll("(?<=[^\\\\])(\')", "\\\\\'"); + messageJson = messageJson.replaceAll("%7B", URLEncoder.encode("%7B")); + messageJson = messageJson.replaceAll("%7D", URLEncoder.encode("%7D")); + messageJson = messageJson.replaceAll("%22", URLEncoder.encode("%22")); String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); // 必须要找主线程才会将数据传递出去 --- 划重点 if (Thread.currentThread() == Looper.getMainLooper().getThread()) { @@ -156,114 +196,60 @@ void dispatchMessage(Message m) { } } - /** - * 刷新消息队列 - */ - 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 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); - } - } - } - } - }); - } - } - - - public void loadUrl(String jsUrl, CallBackFunction returnCallback) { - this.loadUrl(jsUrl); - // 添加至 Map - responseCallbacks.put(BridgeUtil.parseFunctionName(jsUrl), returnCallback); - } - - /** - * register handler,so that javascript can call it - * 注册处理程序,以便javascript调用它 - * @param handlerName handlerName - * @param handler BridgeHandler - */ - public void registerHandler(String handlerName, BridgeHandler handler) { - if (handler != null) { - // 添加至 Map - messageHandlers.put(handlerName, handler); - } - } - - /** - * unregister handler - * - * @param handlerName - */ - public void unregisterHandler(String handlerName) { - if (handlerName != null) { - messageHandlers.remove(handlerName); - } - } - - /** - * call javascript registered handler - * 调用javascript处理程序注册 - * @param handlerName handlerName - * @param data data - * @param callBack CallBackFunction - */ - public void callHandler(String handlerName, String data, CallBackFunction callBack) { - doSend(handlerName, data, callBack); - } + public void sendResponse(Object data, String callbackId) { + if (!(data instanceof String) && mGson == null){ + return; + } + if (!TextUtils.isEmpty(callbackId)) { + final JSResponse response = new JSResponse(); + response.responseId = callbackId; + response.responseData = data instanceof String ? (String) data : mGson.toJson(data); + if (Thread.currentThread() == Looper.getMainLooper().getThread()){ + dispatchMessage(response); + }else { + post(new Runnable() { + @Override + public void run() { + dispatchMessage(response); + } + }); + } + + } + } + + @Override + public void destroy() { + super.destroy(); + mCallbacks.clear(); + } + + public static abstract class BaseJavascriptInterface { + + private Map mCallbacks; + + public BaseJavascriptInterface(Map callbacks) { + mCallbacks = callbacks; + } + + @JavascriptInterface + public String send(String data, String callbackId) { + Log.d("chromium", data + ", callbackId: " + callbackId + " " + Thread.currentThread().getName()); + return send(data); + } + + @JavascriptInterface + public void response(String data, String responseId) { + Log.d("chromium", data + ", responseId: " + responseId + " " + Thread.currentThread().getName()); + if (!TextUtils.isEmpty(responseId)) { + OnBridgeCallback function = mCallbacks.remove(responseId); + if (function != null) { + function.onCallBack(data); + } + } + } + + public abstract String send(String data); + } } diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebViewClient.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebViewClient.java index 460f9cd..cff0ab4 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebViewClient.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebViewClient.java @@ -1,109 +1,258 @@ package com.github.lzyzsd.jsbridge; import android.graphics.Bitmap; - import android.net.http.SslError; import android.os.Build; +import androidx.annotation.Nullable; +import android.view.KeyEvent; +import android.webkit.ClientCertRequest; +import android.webkit.HttpAuthHandler; +import android.webkit.RenderProcessGoneDetail; +import android.webkit.SafeBrowsingResponse; import android.webkit.SslErrorHandler; +import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; - /** * 如果要自定义WebViewClient必须要集成此类 * Created by bruce on 10/28/15. */ -public class BridgeWebViewClient extends WebViewClient { - private BridgeWebView webView; +class BridgeWebViewClient extends WebViewClient { + + private OnLoadJSListener mListener; + + private WebViewClient mClient; - public BridgeWebViewClient(BridgeWebView webView) { - this.webView = webView; + public BridgeWebViewClient(OnLoadJSListener listener) { + mListener = listener; + } + + public void setWebViewClient(WebViewClient client) { + mClient = client; } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - try { - url = URLDecoder.decode(url, "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + view.loadUrl(url); + if (mClient != null) { + return mClient.shouldOverrideUrlLoading(view, url); } + return super.shouldOverrideUrlLoading(view, url); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + view.loadUrl(request.getUrl().getAuthority()); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mClient != null) { + return mClient.shouldOverrideUrlLoading(view, request); + } + return super.shouldOverrideUrlLoading(view, request); + } - if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { // 如果是返回数据 - webView.handlerReturnData(url); - return true; - } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { // - webView.flushMessageQueue(); - return true; + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + if (mClient != null) { + mClient.onPageStarted(view, url, favicon); } else { - return this.onCustomShouldOverrideUrlLoading(url)?true:super.shouldOverrideUrlLoading(view, url); + super.onPageStarted(view, url, favicon); } + } - // 增加shouldOverrideUrlLoading在api》=24时 @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + public void onPageFinished(WebView view, String url) { + if (mClient != null) { + mClient.onPageFinished(view, url); + } else { + super.onPageFinished(view, url); + } + mListener.onLoadStart(); + BridgeUtil.webViewLoadLocalJs(view, BridgeUtil.JAVA_SCRIPT); + mListener.onLoadFinished(); + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - String url = request.getUrl().toString(); - try { - url = URLDecoder.decode(url, "UTF-8"); - } catch (UnsupportedEncodingException ex) { - ex.printStackTrace(); - } - if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { // 如果是返回数据 - webView.handlerReturnData(url); - return true; - } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { // - webView.flushMessageQueue(); - return true; - } else { - return this.onCustomShouldOverrideUrlLoading(url)?true:super.shouldOverrideUrlLoading(view, request); - } - }else { - return super.shouldOverrideUrlLoading(view, request); + @Override + public void onLoadResource(WebView view, String url) { + if (mClient != null) { + mClient.onLoadResource(view, url); + } else { + super.onLoadResource(view, url); } } @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - super.onPageStarted(view, url, favicon); + public void onPageCommitVisible(WebView view, String url) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mClient != null) { + mClient.onPageCommitVisible(view, url); + } else { + super.onPageCommitVisible(view, url); + } } + @Nullable @Override - public void onPageFinished(WebView view, String url) { - super.onPageFinished(view, url); + public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + if (mClient != null) { + return mClient.shouldInterceptRequest(view, url); + } + return super.shouldInterceptRequest(view, url); + } - if (BridgeWebView.toLoadJs != null) { - BridgeUtil.webViewLoadLocalJs(view, BridgeWebView.toLoadJs); + @Nullable + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mClient != null) { + return mClient.shouldInterceptRequest(view, request); } + return super.shouldInterceptRequest(view, request); + } - // - if (webView.getStartupMessage() != null) { - for (Message m : webView.getStartupMessage()) { - webView.dispatchMessage(m); - } - webView.setStartupMessage(null); + @Override + public void onTooManyRedirects(WebView view, android.os.Message cancelMsg, android.os.Message continueMsg) { + if (mClient != null) { + mClient.onTooManyRedirects(view, cancelMsg, continueMsg); + } else { + super.onTooManyRedirects(view, cancelMsg, continueMsg); } + } - // - onCustomPageFinishd(view,url); + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + if (mClient != null) { + mClient.onReceivedError(view, errorCode, description, failingUrl); + } else { + super.onReceivedError(view, errorCode, description, failingUrl); + } + } + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mClient != null) { + mClient.onReceivedError(view, request, error); + } else { + super.onReceivedError(view, request, error); + } } + @Override + public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mClient != null) { + mClient.onReceivedHttpError(view, request, errorResponse); + } else { + super.onReceivedHttpError(view, request, errorResponse); + } - protected boolean onCustomShouldOverrideUrlLoading(String url) { - return false; } + @Override + public void onFormResubmission(WebView view, android.os.Message dontResend, android.os.Message resend) { + if (mClient != null) { + mClient.onFormResubmission(view, dontResend, resend); + } else { + super.onFormResubmission(view, dontResend, resend); + } - protected void onCustomPageFinishd(WebView view, String url){ + } + @Override + public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { + if (mClient != null) { + mClient.doUpdateVisitedHistory(view, url, isReload); + } else { + super.doUpdateVisitedHistory(view, url, isReload); + } + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + if (mClient != null) { + mClient.onReceivedSslError(view, handler, error); + } else { + super.onReceivedSslError(view, handler, error); + } + } + + @Override + public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mClient != null) { + mClient.onReceivedClientCertRequest(view, request); + } else { + super.onReceivedClientCertRequest(view, request); + } + } + + @Override + public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { + if (mClient != null) { + mClient.onReceivedHttpAuthRequest(view, handler, host, realm); + } else { + super.onReceivedHttpAuthRequest(view, handler, host, realm); + } + } + + @Override + public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) { + if (mClient != null) { + return mClient.shouldOverrideKeyEvent(view, event); + } + return super.shouldOverrideKeyEvent(view, event); + } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + if (mClient != null) { + mClient.onUnhandledKeyEvent(view, event); + } else { + super.onUnhandledKeyEvent(view, event); + } + } + + @Override + public void onScaleChanged(WebView view, float oldScale, float newScale) { + if (mClient != null) { + mClient.onScaleChanged(view, oldScale, newScale); + } else { + super.onScaleChanged(view, oldScale, newScale); + } + } + + @Override + public void onReceivedLoginRequest(WebView view, String realm, @Nullable String account, String args) { + if (mClient != null) { + mClient.onReceivedLoginRequest(view, realm, account, args); + } else { + super.onReceivedLoginRequest(view, realm, account, args); + } + } + + @Override + public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && mClient != null){ + return mClient.onRenderProcessGone(view, detail); + } + return super.onRenderProcessGone(view, detail); + } + + @Override + public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponse callback) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && mClient != null){ + mClient.onSafeBrowsingHit(view, request, threatType, callback); + }else { + super.onSafeBrowsingHit(view, request, threatType, callback); + } } + public interface OnLoadJSListener { + + void onLoadStart(); + void onLoadFinished(); + } } \ No newline at end of file diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/CallBackFunction.java b/library/src/main/java/com/github/lzyzsd/jsbridge/CallBackFunction.java deleted file mode 100644 index f41df5b..0000000 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/CallBackFunction.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.lzyzsd.jsbridge; - -public interface CallBackFunction { - - public void onCallBack(String data); - -} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/DefaultHandler.java b/library/src/main/java/com/github/lzyzsd/jsbridge/DefaultHandler.java deleted file mode 100644 index 22e5890..0000000 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/DefaultHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.lzyzsd.jsbridge; - -public class DefaultHandler implements BridgeHandler{ - - String TAG = "DefaultHandler"; - - @Override - public void handler(String data, CallBackFunction function) { - if(function != null){ - function.onCallBack("DefaultHandler response data"); - } - } - -} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/JSRequest.java b/library/src/main/java/com/github/lzyzsd/jsbridge/JSRequest.java new file mode 100644 index 0000000..b4c479d --- /dev/null +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/JSRequest.java @@ -0,0 +1,15 @@ +package com.github.lzyzsd.jsbridge; + +/** + * Created on 2019/7/10. + * Author: bigwang + * Description: + */ +class JSRequest { + + public String callbackId; + + public String data; + + public String handlerName; +} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/JSResponse.java b/library/src/main/java/com/github/lzyzsd/jsbridge/JSResponse.java new file mode 100644 index 0000000..bf5e2f1 --- /dev/null +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/JSResponse.java @@ -0,0 +1,13 @@ +package com.github.lzyzsd.jsbridge; + +/** + * Created on 2019/7/10. + * Author: bigwang + * Description: + */ +class JSResponse { + + public String responseId; + + public String responseData; +} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/Message.java b/library/src/main/java/com/github/lzyzsd/jsbridge/Message.java deleted file mode 100644 index 00d25db..0000000 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/Message.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.github.lzyzsd.jsbridge; - -import android.text.TextUtils; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; -import org.json.JSONTokener; - -/** - * data of bridge - * @author haoqing - * - */ -public class Message { - - private String callbackId; //callbackId - private String responseId; //responseId - private String responseData; //responseData - private String data; //data of message - private String handlerName; //name of handler - - private final static String CALLBACK_ID_STR = "callbackId"; - private final static String RESPONSE_ID_STR = "responseId"; - private final static String RESPONSE_DATA_STR = "responseData"; - private final static String DATA_STR = "data"; - private final static String HANDLER_NAME_STR = "handlerName"; - - public String getResponseId() { - return responseId; - } - public void setResponseId(String responseId) { - this.responseId = responseId; - } - public String getResponseData() { - return responseData; - } - public void setResponseData(String responseData) { - this.responseData = responseData; - } - public String getCallbackId() { - return callbackId; - } - public void setCallbackId(String callbackId) { - this.callbackId = callbackId; - } - public String getData() { - return data; - } - public void setData(String data) { - this.data = data; - } - public String getHandlerName() { - return handlerName; - } - public void setHandlerName(String handlerName) { - this.handlerName = handlerName; - } - - public String toJson() { - JSONObject jsonObject= new JSONObject(); - try { - jsonObject.put(CALLBACK_ID_STR, getCallbackId()); - jsonObject.put(DATA_STR, getData()); - jsonObject.put(HANDLER_NAME_STR, getHandlerName()); - String data = getResponseData(); - if (TextUtils.isEmpty(data)) { - jsonObject.put(RESPONSE_DATA_STR, data); - } else { - jsonObject.put(RESPONSE_DATA_STR, new JSONTokener(data).nextValue()); - } - jsonObject.put(RESPONSE_DATA_STR, getResponseData()); - jsonObject.put(RESPONSE_ID_STR, getResponseId()); - return jsonObject.toString(); - } catch (JSONException e) { - e.printStackTrace(); - } - return null; - } - - public static Message toObject(String jsonStr) { - Message m = new Message(); - try { - JSONObject jsonObject = new JSONObject(jsonStr); - m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR):null); - m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR):null); - m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR):null); - m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR):null); - m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR):null); - return m; - } catch (JSONException e) { - e.printStackTrace(); - } - return m; - } - - public static List toArrayList(String jsonStr){ - List list = new ArrayList(); - try { - JSONArray jsonArray = new JSONArray(jsonStr); - for(int i = 0; i < jsonArray.length(); i++){ - Message m = new Message(); - JSONObject jsonObject = jsonArray.getJSONObject(i); - m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR):null); - m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR):null); - m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR):null); - m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR):null); - m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR):null); - list.add(m); - } - } catch (JSONException e) { - e.printStackTrace(); - } - return list; - } -} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/OnBridgeCallback.java b/library/src/main/java/com/github/lzyzsd/jsbridge/OnBridgeCallback.java new file mode 100644 index 0000000..43b6d0e --- /dev/null +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/OnBridgeCallback.java @@ -0,0 +1,7 @@ +package com.github.lzyzsd.jsbridge; + +public interface OnBridgeCallback { + + void onCallBack(String data); + +} diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/WebViewJavascriptBridge.java b/library/src/main/java/com/github/lzyzsd/jsbridge/WebViewJavascriptBridge.java index 594b81f..69c4d3d 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/WebViewJavascriptBridge.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/WebViewJavascriptBridge.java @@ -1,11 +1,12 @@ package com.github.lzyzsd.jsbridge; -public interface WebViewJavascriptBridge { - - public void send(String data); - public void send(String data, CallBackFunction responseCallback); - +interface WebViewJavascriptBridge { + void sendToWeb(Object data); + + void sendToWeb(Object data, OnBridgeCallback responseCallback); + + void sendToWeb(String function, Object... values); } From 829cc14aef6f3bf31e848aeef886a8e3cc12932d Mon Sep 17 00:00:00 2001 From: guofeng <917043886@qq.com> Date: Tue, 25 Feb 2020 19:56:06 +0800 Subject: [PATCH 07/13] Create android.yml --- .github/workflows/android.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/android.yml diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..2884129 --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,17 @@ +name: Android CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Gradle + run: ./gradlew build From ee193beeccb0bed2627e135266e47fb6d28be877 Mon Sep 17 00:00:00 2001 From: hezaichang Date: Wed, 20 May 2020 22:03:51 +0800 Subject: [PATCH 08/13] feature: Using task queue store js caller --- library/src/main/assets/WebViewJavascriptBridge.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/src/main/assets/WebViewJavascriptBridge.js b/library/src/main/assets/WebViewJavascriptBridge.js index adcf0ff..4966832 100644 --- a/library/src/main/assets/WebViewJavascriptBridge.js +++ b/library/src/main/assets/WebViewJavascriptBridge.js @@ -115,7 +115,7 @@ receiveMessageQueue.push(messageJSON); } _dispatchMessageFromNative(messageJSON); - + } var WebViewJavascriptBridge = window.WebViewJavascriptBridge = { @@ -128,7 +128,12 @@ var doc = document; var readyEvent = doc.createEvent('Events'); + var jobs = window.WVJBCallbacks || []; readyEvent.initEvent('WebViewJavascriptBridgeReady'); readyEvent.bridge = WebViewJavascriptBridge; + window.WVJBCallbacks = [] + jobs.forEach(function (job) { + job(WebViewJavascriptBridge) + }) doc.dispatchEvent(readyEvent); })(); From 920eb3abb5db4f85f828e5af7334ddd62348d85f Mon Sep 17 00:00:00 2001 From: hezaichang Date: Wed, 20 May 2020 22:31:47 +0800 Subject: [PATCH 09/13] chore: update doc --- README.md | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8d57fa8..fd88f80 100644 --- a/README.md +++ b/README.md @@ -129,8 +129,7 @@ will print 'JS got a message hello' and 'JS responding with' in webview console. ## Notice This lib will inject a WebViewJavascriptBridge Object to window object. -So in your js, before use WebViewJavascriptBridge, you must detect if WebViewJavascriptBridge exist. -If WebViewJavascriptBridge does not exit, you can listen to WebViewJavascriptBridgeReady event, as the blow code shows: +You can listen to `WebViewJavascriptBridgeReady` event to ensure `window.WebViewJavascriptBridge` is exist, as the blow code shows: ```javascript @@ -148,6 +147,38 @@ If WebViewJavascriptBridge does not exit, you can listen to WebViewJavascriptBri ``` +Or put all JsBridge function call into `window.WVJBCallbacks` array if `window.WebViewJavascriptBridge` is undefined, this taks queue will be flushed when `WebViewJavascriptBridgeReady` event triggered. + +Copy and paste setupWebViewJavascriptBridge into your JS: + +```javascript +function setupWebViewJavascriptBridge(callback) { + if (window.WebViewJavascriptBridge) { + return callback(WebViewJavascriptBridge); + } + if (window.WVJBCallbacks) { + return window.WVJBCallbacks.push(callback); + } + window.WVJBCallbacks = [callback]; +} +``` + +Call `setupWebViewJavascriptBridge` and then use the bridge to register handlers or call Java handlers: + +```javascript +setupWebViewJavascriptBridge(function(bridge) { + bridge.registerHandler('JS Echo', function(data, responseCallback) { + console.log("JS Echo called with:", data); + responseCallback(data); + }); + bridge.callHandler('ObjC Echo', {'key':'value'}, function(responseData) { + console.log("JS received response:", responseData); + }); +}); +``` + +It same with https://github.com/marcuswestin/WebViewJavascriptBridge, that would be easier for you to define same behavior in different platform between Android and iOS. Meanwhile, writing concise code. + ## License This project is licensed under the terms of the MIT license. From da4e90835b93d1d63a4c742a9027a70ca0021503 Mon Sep 17 00:00:00 2001 From: lcn Date: Fri, 5 Feb 2021 11:44:04 +0800 Subject: [PATCH 10/13] =?UTF-8?q?BridgeHelper.shouldOverrideUrlLoading(Str?= =?UTF-8?q?ing=20url)=20=E6=96=B9=E6=B3=95=EF=BC=8C=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E4=BC=A0=E4=BA=BA=E7=9A=84=20url=20=E4=B8=AD=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E6=9C=AA=E7=BC=96=E7=A0=81=E7=9A=84=E7=AC=A6=E5=8F=B7=E2=80=9C?= =?UTF-8?q?%=E2=80=9D=E5=92=8C=E2=80=9C+=E2=80=9D=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=20URLDecoder.decode=20=E6=8A=9B=E5=87=BA=20I?= =?UTF-8?q?llegalArgumentException=EF=BC=8C=E5=9C=A8=20decode=20=E5=89=8D?= =?UTF-8?q?=E5=B0=86=E8=AF=A5=E7=89=B9=E6=AE=8A=E7=AC=A6=E5=8F=B7=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E7=BC=96=E7=A0=81=E5=A4=84=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java index 18b18fc..d4e4bfe 100644 --- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java +++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeHelper.java @@ -269,7 +269,9 @@ private void webViewLoadLocalJs() { public boolean shouldOverrideUrlLoading(String url) { try { - url = URLDecoder.decode(url, "UTF-8"); + // decode 之前,处理 % 和 + + String replacedUrl = url.replaceAll("%(?![0-9a-fA-F]{2})", "%25").replaceAll("\\+", "%2B"); + url = URLDecoder.decode(replacedUrl, "UTF-8"); } catch (UnsupportedEncodingException e) { Log.w(TAG, e); } From 984d8db8b1700fcddd3cd60ceccc1d75c416506c Mon Sep 17 00:00:00 2001 From: gaop Date: Wed, 17 Mar 2021 09:21:58 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E7=AE=80=E5=8C=96JS=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如果方法不需要参数,只有回调函数,简化JS中的调用 --- library/src/main/assets/WebViewJavascriptBridge.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/src/main/assets/WebViewJavascriptBridge.js b/library/src/main/assets/WebViewJavascriptBridge.js index adcf0ff..ccbfea8 100644 --- a/library/src/main/assets/WebViewJavascriptBridge.js +++ b/library/src/main/assets/WebViewJavascriptBridge.js @@ -36,7 +36,11 @@ } // 调用线程 function callHandler(handlerName, data, responseCallback) { - + // 如果方法不需要参数,只有回调函数,简化JS中的调用 + if (arguments.length == 2 && typeof data == 'function') { + responseCallback = data; + data = null; + } _doSend(handlerName, data, responseCallback); } From d0928a872f3d111254102a53ba604452ea2ea370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?hi=E5=A4=A7=E5=A4=B4=E9=AC=BChi?= Date: Wed, 24 Mar 2021 16:28:23 +0800 Subject: [PATCH 12/13] upgrade gradle --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 5bbdb7f..ba3db91 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:4.1.3' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index deecc9f..85cbcc2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Mar 31 22:44:06 CST 2018 +#Wed Mar 24 16:24:00 CST 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip From 253b2a55269c2834931e6580fc1c91f957ec3b22 Mon Sep 17 00:00:00 2001 From: Dengju Deng Date: Fri, 30 Apr 2021 17:41:38 +0800 Subject: [PATCH 13/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd88f80..d58fde3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#JsBridge +# JsBridge -----