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>

相关推荐
三少爷的鞋5 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)9 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码10 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程14 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程15 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程15 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓16 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer