creator-webview与Android交互


title: creator-webview与Android交互

categories: Cocos2dx
tags: [cocos2dx, creator, webview, 交互]
date: 2024-03-23 13:17:20
comments: false
mathjax: true
toc: true

creator-webview与Android交互


前篇


java 调用 js

  • 使用 WebView.evaluateJavascript 执行 js 代码

    java 复制代码
    String callStr = String.format("window['java2js'](`%s`, `%s`)", funcName, jsonMsg);
    WebViewIns.evaluateJavascript(callStr, null);

    如果要透传数据结构或 json, 最好用 base64 加密一下, 然后在 js 中再解密出来, 以保证这些数据不会破会 js 代码的结构

    一般跨语言的交互中, 我都会使用 base64 去加密数据使之变成正常的字符串


js 调用 java

  1. 使用 WebView.addJavascriptInterface(Object, String); 映射对象和方法到 js 中一个变量, 例如:

    java 复制代码
    public static class JsUtils {
        @JavascriptInterface
        public void call(String funcName, String jsonMsg) { // 具体多少个参数对上 js 即可
        	...
        }
    }
    
    WebViewIns.addJavascriptInterface(new JsUtils(), "gJavaObj");
  2. 直接使用 gJavaObj 对象即可

    js 复制代码
    gJavaObj.call(funcName, jsonMsg);

加载 js 代码

  • 使用 WebView.loadUrl

    js 复制代码
    String bdg = "js 代码";
    WebView.loadUrl("javascript:" + bdg);
  • js 代码书写有严格的要求, 例如:

    js 复制代码
    // 1. 一定要以这种 执行方法 的方式初始化
    // 2. 语句结尾要加 ;, 不然报错 Invalid left-hand side expression in postfix operation
    // 3. 注释必须清楚掉
    (function() {
        window.cm = {};
        window.java2js = function(f, m) {
            var oldCb = window.cm[f];
            if (oldCb) oldCb(window.atob(m));
            window.cm[f] = null;
        };
        window.WebViewJavascriptBridge = {
            init: function() { },
            registerHandler: function() { },
            callHandler: function(f, m, c) {
                window.cm[f] = c;
                gJavaObj.call(f, m);
            },
        };
        document.dispatchEvent(new Event("WebViewJavascriptBridgeReady"));
    })()
    • 可以使用 uglyjs 把代码压缩成一行

      js 复制代码
      String bdg = "window.cm={},window.java2js=function(f,m){var oldCb=window.cm[f];oldCb&&oldCb(window.atob(m)),window.cm[f]=null},window.WebViewJavascriptBridge={init:function(){},registerHandler:function(){},callHandler:function(f,m,c){window.cm[f]=c,gJavaObj.call(f,m)}},document.dispatchEvent(new Event(\"WebViewJavascriptBridgeReady\"));"

完整的 java, html 代码

java
  • 代码

    json 复制代码
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.net.http.SslError;
    import android.util.Base64;
    import android.view.ViewGroup;
    import android.webkit.JavascriptInterface;
    import android.webkit.SslErrorHandler;
    import android.webkit.WebResourceRequest;
    import android.webkit.WebResourceResponse;
    import android.webkit.WebSettings;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    
    import java.io.ByteArrayInputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.function.Consumer;
    
    public class WebviewHelper {
        public static WebviewHelper instance = null;
    
        private RelativeLayout mLayoutRoot;
        private WebView mWebview;
    
        private static Map<String, BridgeHandler> mJsCb = new HashMap<>();
    
        public static void showWebview(final Activity activity, final String url, final ActivityMgr.CodeRunnable task) {
            closeWebview(activity, () -> {
                instance = new WebviewHelper();
                instance.show(activity, url);
                if (task != null) {
                    task.run(ActivityMgr.Ok, "");
                }
            });
        }
    
        public static void closeWebview(final Activity activity, final Runnable task) {
            activity.runOnUiThread(() -> {
                if (instance != null) {
                    instance.destroy();
                }
    
                if (task != null) {
                    task.run();
                }
            });
        }
    
        public static boolean goBack() {
            ActivityMgr.Act.moveTaskToBack(true);
            return false;
        }
    
        @SuppressLint("SetJavaScriptEnabled")
        public void show(Activity activity, final String url) {
            final RelativeLayout rLayout = new RelativeLayout(activity);
            mLayoutRoot = rLayout;
            RelativeLayout.LayoutParams rParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
            LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            final WebView wv = new WebView(activity);
            wv.setWebViewClient(new WebviewClientHelper());
            mWebview = wv;
            wv.setLayoutParams(lParams);
            rLayout.addView(wv);
            activity.addContentView(rLayout, rParams);
    
            mWebview.addJavascriptInterface(new JsUtils(), "gJavaObj");//AndroidtoJS类对象映射到js的test对象
    
            wv.loadUrl(url);
    
            // 设置webview
            WebSettings settings = wv.getSettings();
            settings.setJavaScriptCanOpenWindowsAutomatically(true);
            settings.setJavaScriptEnabled(true);
            settings.setDomStorageEnabled(true);
            settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // 有缓存就使用缓存
            settings.setSupportZoom(false);
            settings.setBuiltInZoomControls(true);
        }
    
        public static void regHandler(String name, BridgeHandler bh) {
            mJsCb.put(name, bh);
        }
    
        private void destroy() {
            if (mWebview != null) {
                mWebview.destroy();
                mWebview = null;
            }
    
            if (mLayoutRoot != null) {
                ViewGroup vg = (ViewGroup) mLayoutRoot.getParent();
                vg.removeView(mLayoutRoot);
                mLayoutRoot = null;
            }
    
            instance = null;
        }
    
        public interface BridgeHandler {
            void handler(String var1, Consumer<String> var2);
        }
    
        public static class JsUtils {
            @JavascriptInterface
            public void call(String funcName, String jsonMsg) {
                BridgeHandler bh = mJsCb.get(funcName);
                if (bh == null) {
                    ActivityMgr.E("no func: %s", funcName);
                    return;
                }
    
                bh.handler(jsonMsg, (result) -> {
                    try {
                        // 交互是需要 base64 处理一下
                        result = Base64.encodeToString((result != null ? result : "").getBytes(StandardCharsets.UTF_8), Base64.DEFAULT);
                        String callStr = String.format("window['java2js'](`%s`, `%s`)", funcName, result);
                        instance.mWebview.evaluateJavascript(callStr, null);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
        }
    
        public static class WebviewClientHelper extends WebViewClient {
            public boolean isLoadBdg = false;
    
            @Override
            public void onPageFinished(WebView view, String url) {
                if (!isLoadBdg) {
                    String bdg = "window.cm={},window.java2js=function(f,m){var oldCb=window.cm[f];oldCb&&oldCb(window.atob(m)),window.cm[f]=null},window.WebViewJavascriptBridge={init:function(){},registerHandler:function(){},callHandler:function(f,m,c){window.cm[f]=c,gJavaObj.call(f,m)}},document.dispatchEvent(new Event(\"WebViewJavascriptBridgeReady\"));";
                    view.loadUrl("javascript:" + bdg);
                    isLoadBdg = true;
                }
                super.onPageFinished(view, url);
            }
        }
    }

html
  • 代码

    html 复制代码
    <!DOCTYPE html>
    <html>
    <head>
        <script>
            document.addEventListener(
                'WebViewJavascriptBridgeReady'
                , function() {
                    console.log("--- WebViewJavascriptBridgeReady");
                },
                false
            );
    
            function js2java() {
                console.log("--- js2java");
                // gJavaObj.hello("Hello Terry")
    
                var funcName = "StartInfo"
                var jsonMsg = "World 002"
                window.WebViewJavascriptBridge.callHandler(funcName, jsonMsg, function(responseData) {
                    console.log("--- responseData:", responseData);
                })
            }
    
            console.log("--- web loaded");
        </script>
        <title>Test Webview</title>
    </head>
    
    <body>
        <div id="mydiv">
            <br /><br /><button onclick="js2java()"> js2java </button>
        </div>
    </body>
    </html>

相关推荐
CYRUS_STUDIO8 小时前
Frida 检测与对抗实战:进程、maps、线程、符号全特征清除
android·逆向
csj509 小时前
安卓基础之《(28)—Service组件》
android
lhbian11 小时前
PHP、C++和C语言对比:哪个更适合你?
android·数据库·spring boot·mysql·kafka
catoop12 小时前
Android 最佳实践、分层架构与全流程解析(2025)
android
ZHANG13HAO13 小时前
Android 13 特权应用(Android Studio 开发)调用 AOSP 隐藏 API 完整教程
android·ide·android studio
田梓燊13 小时前
leetcode 142
android·java·leetcode
angerdream13 小时前
Android手把手编写儿童手机远程监控App之JAVA基础
android
菠萝地亚狂想曲14 小时前
Zephyr_01, environment
android·java·javascript
sTone8737514 小时前
跨端框架通信机制全解析:从 URL Schema 到 JSI 到 Platform Channel
android·前端
sTone8737514 小时前
Java 注解完全指南:从 "这是什么" 到 "自己写一个"
android·前端