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>

相关推荐
二流小码农1 小时前
鸿蒙开发:loading动画的几种实现方式
android·ios·harmonyos
爱吃西红柿!2 小时前
fastadmin fildList 动态下拉框默认选中
android·前端·javascript
悠哉清闲3 小时前
工厂模式与多态结合
android·java
大耳猫4 小时前
Android SharedFlow 详解
android·kotlin·sharedflow
火柴就是我4 小时前
升级 Android Studio 后报错 Error loading build artifacts from redirect.txt
android
❀͜͡傀儡师5 小时前
完成一个可交互的k8s管理平台的页面开发
容器·kubernetes·交互
androidwork5 小时前
掌握 MotionLayout:交互动画开发
android·kotlin·交互
TiAmo zhang5 小时前
人机融合智能 | 可穿戴计算设备的多模态交互
交互
奔跑吧 android5 小时前
【android bluetooth 协议分析 14】【HFP详解 1】【案例一: 手机侧显示来电,但车机侧没有显示来电: 讲解AT+CLCC命令】
android·hfp·aosp13·telecom·ag·hf·headsetclient
Chenyu_3106 小时前
09.MySQL内外连接
android·数据库·mysql