diff --git a/README.md b/README.md
index d2c14e1..c13b165 100644
--- a/README.md
+++ b/README.md
@@ -129,6 +129,44 @@ For example:
will print 'JS got a message hello' and 'JS responding with' in webview console.
+### Persistent Callbacks (New Feature)
+
+By default, callbacks are deleted after first use. However, you can now use persistent callbacks that can be reused multiple times:
+
+#### Java Side
+
+```java
+// Use persistent callback that won't be deleted after first use
+webView.callHandlerPersistent("functionInJs", data, new OnBridgeCallback() {
+ @Override
+ public void onCallBack(String data) {
+ // This callback can be called multiple times
+ Log.d(TAG, "Persistent callback called: " + data);
+ }
+});
+```
+
+#### JavaScript Side
+
+```javascript
+// Use persistent callback
+WebViewJavascriptBridge.callHandlerPersistent("javaHandler", data, function(response) {
+ // This callback can be reused multiple times
+ console.log("Persistent callback response: " + response);
+});
+
+// Register and manually manage persistent callbacks
+var callbackId = "my_persistent_callback";
+WebViewJavascriptBridge.registerPersistentCallback(callbackId, function(data) {
+ console.log("Persistent callback called: " + data);
+});
+
+// Remove persistent callback when no longer needed
+WebViewJavascriptBridge.removePersistentCallback(callbackId);
+```
+
+This feature is useful when you need to maintain a long-term communication channel between Java and JavaScript, such as for real-time updates or event notifications.
+
### Switch to CustomWebView
* activity_main.xml
```xml
diff --git a/example/src/main/assets/persistent_callback_demo.html b/example/src/main/assets/persistent_callback_demo.html
new file mode 100644
index 0000000..712b80f
--- /dev/null
+++ b/example/src/main/assets/persistent_callback_demo.html
@@ -0,0 +1,114 @@
+
+
+
+
+ Persistent Callback Demo
+
+
+
+
Persistent Callback Demo
+
This demo shows how to use persistent callbacks that can be reused multiple times.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainActivity.java b/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainActivity.java
index 8cc0946..4f540b3 100644
--- a/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainActivity.java
+++ b/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainActivity.java
@@ -77,7 +77,7 @@ public boolean onShowFileChooser(WebView webView, ValueCallback filePathC
}
});
- webView.addJavascriptInterface(new MainJavascriptInterface(webView.getCallbacks(), webView), "WebViewJavascriptBridge");
+ webView.addJavascriptInterface(new MainJavascriptInterface(webView.getCallbacks(), webView.getPersistentCallbacks(), webView), "WebViewJavascriptBridge");
webView.setGson(new Gson());
webView.loadUrl("file:///android_asset/demo.html");
User user = new User();
diff --git a/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainJavascriptInterface.java b/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainJavascriptInterface.java
index a32c2c3..88fc46a 100644
--- a/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainJavascriptInterface.java
+++ b/example/src/main/java/com/github/lzyzsd/jsbridge/example/MainJavascriptInterface.java
@@ -24,6 +24,11 @@ public MainJavascriptInterface(Map callbacks, WebViewJ
mWebView = webView;
}
+ public MainJavascriptInterface(Map callbacks, Map persistentCallbacks, WebViewJavascriptBridge webView) {
+ super(callbacks, persistentCallbacks);
+ mWebView = webView;
+ }
+
public MainJavascriptInterface(Map callbacks) {
super(callbacks);
}
diff --git a/library/build.gradle b/library/build.gradle
index 500ecf2..f595cc0 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -27,6 +27,14 @@ android {
dependencies {
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.code.gson:gson:2.8.5'
+
+ // Test dependencies
+ testImplementation 'junit:junit:4.13.2'
+ testImplementation 'org.mockito:mockito-core:3.12.4'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test:core:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation 'org.mockito:mockito-android:3.12.4'
}
diff --git a/library/src/main/assets/WebViewJavascriptBridge.js b/library/src/main/assets/WebViewJavascriptBridge.js
index 6f93f09..eac870e 100644
--- a/library/src/main/assets/WebViewJavascriptBridge.js
+++ b/library/src/main/assets/WebViewJavascriptBridge.js
@@ -11,6 +11,7 @@
var sendMessageQueue = [];
var responseCallbacks = {};
+ var persistentCallbacks = {};
var uniqueId = 1;
var lastCallTime = 0;
@@ -63,24 +64,48 @@
delete messageHandlers[handlerName];
}
+ // Register a persistent callback that won't be deleted after first use
+ function registerPersistentCallback(callbackId, callback) {
+ persistentCallbacks[callbackId] = callback;
+ responseCallbacks[callbackId] = callback;
+ }
+
+ // Remove a persistent callback
+ function removePersistentCallback(callbackId) {
+ delete persistentCallbacks[callbackId];
+ delete responseCallbacks[callbackId];
+ }
+
// 调用线程
- function callHandler(handlerName, data, responseCallback) {
+ function callHandler(handlerName, data, responseCallback, persistent) {
// 如果方法不需要参数,只有回调函数,简化JS中的调用
if (arguments.length == 2 && typeof data == 'function') {
responseCallback = data;
data = null;
}
- _doSend(handlerName, data, responseCallback);
+ _doSend(handlerName, data, responseCallback, persistent);
+ }
+
+ // Call handler with persistent callback that can be reused
+ function callHandlerPersistent(handlerName, data, responseCallback) {
+ if (arguments.length == 2 && typeof data == 'function') {
+ responseCallback = data;
+ data = null;
+ }
+ _doSend(handlerName, data, responseCallback, true);
}
//sendMessage add message, 触发native处理 sendMessage
- function _doSend(handlerName, message, responseCallback) {
+ function _doSend(handlerName, message, responseCallback, persistent) {
var callbackId;
if(typeof responseCallback === 'string'){
callbackId = responseCallback;
} else if (responseCallback) {
callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime();
responseCallbacks[callbackId] = responseCallback;
+ if (persistent) {
+ persistentCallbacks[callbackId] = responseCallback;
+ }
message.callbackId = callbackId;
}else{
callbackId = '';
@@ -98,7 +123,10 @@
return;
}
responseCallback(responseData);
- delete responseCallbacks[callbackId];
+ // Only delete if it's not a persistent callback
+ if (!persistentCallbacks[callbackId]) {
+ delete responseCallbacks[callbackId];
+ }
}
}
@@ -141,7 +169,10 @@
return;
}
responseCallback(message.responseData);
- delete responseCallbacks[message.responseId];
+ // Only delete if it's not a persistent callback
+ if (!persistentCallbacks[message.responseId]) {
+ delete responseCallbacks[message.responseId];
+ }
} else {
//直接发送
if (message.callbackId) {
@@ -179,7 +210,11 @@
WebViewJavascriptBridge.init = init;
WebViewJavascriptBridge.doSend = send;
WebViewJavascriptBridge.registerHandler = registerHandler;
+ WebViewJavascriptBridge.removeHandler = removeHandler;
WebViewJavascriptBridge.callHandler = callHandler;
+ WebViewJavascriptBridge.callHandlerPersistent = callHandlerPersistent;
+ WebViewJavascriptBridge.registerPersistentCallback = registerPersistentCallback;
+ WebViewJavascriptBridge.removePersistentCallback = removePersistentCallback;
WebViewJavascriptBridge._handleMessageFromNative = _handleMessageFromNative;
WebViewJavascriptBridge._fetchQueue = _fetchQueue;
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 cfbdfee..2073bfd 100644
--- a/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java
+++ b/library/src/main/java/com/github/lzyzsd/jsbridge/BridgeWebView.java
@@ -33,6 +33,7 @@ public class BridgeWebView extends WebView implements WebViewJavascriptBridge, B
private final int URL_MAX_CHARACTER_NUM=2097152;
private Map mCallbacks = new ArrayMap<>();
+ private Map mPersistentCallbacks = new ArrayMap<>();
private List