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>

相关推荐
百锦再17 分钟前
Android Studio开发 SharedPreferences 详解
android·ide·android studio
梓贤Vigo22 分钟前
【Axure教程】表格嵌套卡片
交互·产品经理·axure·原型·教程
青春给了狗29 分钟前
Android 14 修改侧滑手势动画效果
android
CYRUS STUDIO36 分钟前
Android APP 热修复原理
android·app·frida·hotfix·热修复
火柴就是我1 小时前
首次使用Android Studio时,http proxy,gradle问题解决
android
limingade2 小时前
手机打电话时电脑坐席同时收听对方说话并插入IVR预录声音片段
android·智能手机·电脑·蓝牙电话·电脑打电话
浩浩测试一下2 小时前
计算机网络中的DHCP是什么呀? 详情解答
android·网络·计算机网络·安全·web安全·网络安全·安全架构
青春给了狗4 小时前
Android 14 系统统一修改app启动时图标大小和圆角
android
pengyu4 小时前
【Flutter 状态管理 - 柒】 | InheritedWidget:藏在组件树里的"魔法"✨
android·flutter·dart
居然是阿宋6 小时前
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
android·开发语言·kotlin