Repository: happydog-intj/JsBridge Branch: master Commit: 78291ba35bb2 Files: 41 Total size: 91.0 KB Directory structure: gitextract_ae0068gj/ ├── .github/ │ └── workflows/ │ └── android.yml ├── .gitignore ├── README.md ├── build.gradle ├── example/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── assets/ │ │ ├── demo.html │ │ └── persistent_callback_demo.html │ ├── java/ │ │ └── com/ │ │ └── github/ │ │ └── lzyzsd/ │ │ └── jsbridge/ │ │ └── example/ │ │ ├── CustomWebView.java │ │ ├── MainActivity.java │ │ └── MainJavascriptInterface.java │ └── res/ │ ├── layout/ │ │ └── activity_main.xml │ └── values/ │ ├── strings.xml │ └── styles.xml ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── library/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── WebViewJavascriptBridge.js │ │ └── java/ │ │ └── com/ │ │ └── github/ │ │ └── lzyzsd/ │ │ └── jsbridge/ │ │ ├── BridgeHandler.java │ │ ├── BridgeHelper.java │ │ ├── BridgeUtil.java │ │ ├── BridgeWebView.java │ │ ├── BridgeWebViewClient.java │ │ ├── DefaultHandler.java │ │ ├── IWebView.java │ │ ├── JSRequest.java │ │ ├── JSResponse.java │ │ ├── Message.java │ │ ├── OnBridgeCallback.java │ │ └── WebViewJavascriptBridge.java │ └── test/ │ ├── assets/ │ │ └── test_persistent_callback.html │ └── java/ │ └── com/ │ └── github/ │ └── lzyzsd/ │ └── jsbridge/ │ └── PersistentCallbackTest.java └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/android.yml ================================================ 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 ================================================ FILE: .gitignore ================================================ #built application files *.apk *.ap_ # files for the dex VM *.dex # Java class files *.class # generated files bin/ gen/ # Local configuration file (sdk path, etc) local.properties # Windows thumbnail db Thumbs.db # OSX files .DS_Store # Eclipse project files .classpath .project # Android Studio .idea #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. .gradle build/ # Signing files .signing/ # User-specific configurations .idea/libraries/ .idea/workspace.xml .idea/tasks.xml .idea/.name .idea/compiler.xml .idea/copyright/profiles_settings.xml .idea/encodings.xml .idea/misc.xml .idea/modules.xml .idea/scopes/scope_settings.xml .idea/vcs.xml *.iml ================================================ FILE: README.md ================================================ # JsBridge ----- Inspired and modified from [this](https://github.com/jacin1/JsBridge) and WeChat jsBridge file, with some bug fixes and feature enhancements. This project makes a bridge between Java and JavaScript. It provides a safe and convenient way to call Java code from JavaScript and call JavaScript code from Java. ## How JsBridge Works ![JsBridge](./JsBridgeWork.png) ## Demo ![JsBridge Demo](https://raw.githubusercontent.com/lzyzsd/JsBridge/master/JsBridge.gif) ## Usage ## JitPack.io I strongly recommend [JitPack.io](https://jitpack.io) ```groovy repositories { // ... maven { url "https://jitpack.io" } } dependencies { compile 'com.github.lzyzsd:jsbridge:1.0.4' } ``` ## Use it in Java Add `com.github.lzyzsd.jsbridge.BridgeWebView` to your layout, it is inherited from WebView. ### Register a Java handler function so that JavaScript can call ```java webView.registerHandler("submitFromWeb", new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { Log.i(TAG, "handler = submitFromWeb, data from web = " + data); function.onCallBack("submitFromWeb exe, response data from Java"); } }); ``` JavaScript can call this Java handler method "submitFromWeb" through: ```javascript WebViewJavascriptBridge.callHandler( 'submitFromWeb' , {'param': str1} , function(responseData) { document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData } ); ``` You can set a default handler in Java, so that JavaScript can send messages to Java without an assigned handlerName ```java webView.setDefaultHandler(new DefaultHandler()); ``` ```javascript window.WebViewJavascriptBridge.doSend( data , function(responseData) { document.getElementById("show").innerHTML = "responseData from java, data = " + responseData } ); ``` ### Register a JavaScript handler function so that Java can call ```javascript WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) { document.getElementById("show").innerHTML = ("data from Java: = " + data); var responseData = "Javascript Says Right back aka!"; responseCallback(responseData); }); ``` Java can call this JavaScript handler function "functionInJs" through: ```java webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() { @Override public void onCallBack(String data) { } }); ``` You can also define a default handler using the init method, so that Java can send messages to JavaScript without an assigned handlerName For example: ```javascript window.WebViewJavascriptBridge.init(function(message, responseCallback) { console.log('JS got a message', message); var data = { 'Javascript Responds': 'Wee!' }; console.log('JS responding with', data); responseCallback(data); }); ``` ```java webView.send("hello"); ``` 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 ``` * MainActivity.java Change BridgeWebView class to CustomWebView: ```java CustomWebView webView = (CustomWebView) findViewById(R.id.webView); ``` ## Notice This library will inject a WebViewJavascriptBridge Object to the window object. You can listen to the `WebViewJavascriptBridgeReady` event to ensure `window.WebViewJavascriptBridge` exists, as the below code shows: ```javascript if (window.WebViewJavascriptBridge) { //do your work here } else { document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { //do your work here }, false ); } ``` Or put all JsBridge function call into `window.WVJBCallbacks` array if `window.WebViewJavascriptBridge` is undefined, this task 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's the same as [WebViewJavascriptBridge](https://github.com/marcuswestin/WebViewJavascriptBridge), which makes it easier for you to define the same behavior across different platforms between Android and iOS, while writing concise code. ## License This project is licensed under the terms of the MIT license. ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() google() } dependencies { 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 } } allprojects { repositories { jcenter() maven { url "https://maven.google.com" } google() } tasks.withType(Javadoc) { // 这一段是为了消除gbk的错�? options{ encoding "UTF-8" charSet 'UTF-8' links "http://docs.oracle.com/javase/7/docs/api" } } } ================================================ FILE: example/.gitignore ================================================ /build ================================================ FILE: example/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 28 // buildToolsVersion "25.0.3" defaultConfig { applicationId "com.github.lzyzsd.jsbridge.example" minSdkVersion 17 targetSdkVersion 28 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':library') implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'com.google.code.gson:gson:2.8.5' } ================================================ FILE: example/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/bruce/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: example/src/main/AndroidManifest.xml ================================================ ================================================ FILE: example/src/main/assets/demo.html ================================================ js调用java

================================================ FILE: example/src/main/assets/persistent_callback_demo.html ================================================ Persistent Callback Demo

Persistent Callback Demo

This demo shows how to use persistent callbacks that can be reused multiple times.

================================================ FILE: example/src/main/java/com/github/lzyzsd/jsbridge/example/CustomWebView.java ================================================ 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.IWebView; import com.github.lzyzsd.jsbridge.OnBridgeCallback; import com.github.lzyzsd.jsbridge.WebViewJavascriptBridge; import com.google.gson.Gson; import java.util.Map; /** * 采用BridgeHelper集成JsBridge功能示例.定制WebView,可只添加实际需要的JsBridge接口. * * @author ZhengAn * @date 2019-07-07 */ @SuppressLint("SetJavaScriptEnabled") public class CustomWebView extends WebView implements WebViewJavascriptBridge, IWebView { private BridgeHelper bridgeHelper; private Gson mGson; 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); } /** * 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, OnBridgeCallback callBack) { bridgeHelper.callHandler(handlerName, data, callBack); } @Override public void sendToWeb(String data) { sendToWeb(data, (OnBridgeCallback) null); } @Override public void sendToWeb(String data, OnBridgeCallback responseCallback) { bridgeHelper.sendToWeb(data, responseCallback); } @Override public void sendToWeb(String function, Object... values) { bridgeHelper.sendToWeb(function, values); } @Override public void responseFromWeb(String data, String callbackId) { bridgeHelper.responseFromWeb(data,callbackId); } public void setGson(Gson gson){ this.mGson = gson; } public Map getCallbacks() { return bridgeHelper.getCallbacks(); } @Override public WebView getWebView() { return this; } } ================================================ FILE: example/src/main/java/com/github/lzyzsd/jsbridge/example/MainActivity.java ================================================ package com.github.lzyzsd.jsbridge.example; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.widget.Button; import com.github.lzyzsd.jsbridge.BridgeWebView; import com.github.lzyzsd.jsbridge.OnBridgeCallback; import com.google.gson.Gson; public class MainActivity extends Activity implements OnClickListener { private final String TAG = "MainActivity"; BridgeWebView webView; Button button; int RESULT_CODE = 0; ValueCallback mUploadMessage; ValueCallback mUploadMessageArray; static class Location { String address; } static class User { String name; Location location; String testStr; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = (BridgeWebView) findViewById(R.id.webView); button = (Button) findViewById(R.id.button); button.setOnClickListener(this); webView.setWebChromeClient(new WebChromeClient() { @SuppressWarnings("unused") public void openFileChooser(ValueCallback uploadMsg, String AcceptType, String capture) { this.openFileChooser(uploadMsg); } @SuppressWarnings("unused") public void openFileChooser(ValueCallback uploadMsg, String AcceptType) { this.openFileChooser(uploadMsg); } public void openFileChooser(ValueCallback uploadMsg) { mUploadMessage = uploadMsg; pickFile(); } @Override public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { mUploadMessageArray = filePathCallback; pickFile(); return true; } }); 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(); Location location = new Location(); location.address = "SDU"; user.location = location; user.name = "大头鬼"; webView.callHandler("functionInJs", new Gson().toJson(user), new OnBridgeCallback() { @Override public void onCallBack(String data) { Log.d(TAG, "onCallBack: " + data); } }); webView.sendToWeb("hello"); } public void pickFile() { Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT); chooserIntent.setType("image/*"); startActivityForResult(chooserIntent, RESULT_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == RESULT_CODE) { if (null == mUploadMessage && null == mUploadMessageArray){ return; } if(null!= mUploadMessage && null == mUploadMessageArray){ Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } if(null == mUploadMessage && null != mUploadMessageArray){ Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); if (result != null) { mUploadMessageArray.onReceiveValue(new Uri[]{result}); } mUploadMessageArray = null; } } } @Override public void onClick(View v) { if (button.equals(v)) { webView.callHandler("functionInJs", "data from Java", new OnBridgeCallback() { @Override public void onCallBack(String data) { // TODO Auto-generated method stub Log.i(TAG, "reponse data from js " + data); } }); } } } ================================================ FILE: example/src/main/java/com/github/lzyzsd/jsbridge/example/MainJavascriptInterface.java ================================================ package com.github.lzyzsd.jsbridge.example; import android.util.Log; import android.webkit.JavascriptInterface; import com.github.lzyzsd.jsbridge.BridgeWebView; import com.github.lzyzsd.jsbridge.OnBridgeCallback; import com.github.lzyzsd.jsbridge.WebViewJavascriptBridge; import java.util.Map; /** * Created on 2019/7/10. * Author: bigwang * Description: */ public class MainJavascriptInterface extends BridgeWebView.BaseJavascriptInterface { //WebJSbridge private WebViewJavascriptBridge mWebView; public MainJavascriptInterface(Map callbacks, WebViewJavascriptBridge webView) { super(callbacks); mWebView = webView; } public MainJavascriptInterface(Map callbacks, Map persistentCallbacks, WebViewJavascriptBridge webView) { super(callbacks, persistentCallbacks); mWebView = webView; } public MainJavascriptInterface(Map callbacks) { super(callbacks); } @Override public String send(String data) { return "it is default response"; } @JavascriptInterface public void submitFromWeb(String data, String callbackId) { Log.d("MainJavascriptInterface", data + ", callbackId: " + callbackId + " " + Thread.currentThread().getName()); mWebView.responseFromWeb("submitFromWeb response", callbackId); } } ================================================ FILE: example/src/main/res/layout/activity_main.xml ================================================