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>

相关推荐
风和先行22 分钟前
adb 命令查看设备存储占用情况
android·adb
AaVictory.1 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰2 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶2 小时前
Android——网络请求
android
干一行,爱一行2 小时前
android camera data -> surface 显示
android
断墨先生2 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
天郁青3 小时前
数据库交互的本地项目:后台管理系统
数据库·交互
无极程序员4 小时前
PHP常量
android·ide·android studio
梓贤Vigo4 小时前
【Axure高保真原型】2级下钻条形图
交互·产品经理·axure·原型·中继器
萌面小侠Plus5 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机