creator-webview与Android交互

creator-webview与Android交互


前篇


java 调用 js

  • 使用 WebView.evaluateJavascript 执行 js 代码

    1
    2
    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 中一个变量, 例如:

    1
    2
    3
    4
    5
    6
    7
    8
    public static class JsUtils {
    @JavascriptInterface
    public void call(String funcName, String jsonMsg) { // 具体多少个参数对上 js 即可
    ...
    }
    }

    WebViewIns.addJavascriptInterface(new JsUtils(), "gJavaObj");
  2. 直接使用 gJavaObj 对象即可

    1
    gJavaObj.call(funcName, jsonMsg);

加载 js 代码

  • 使用 WebView.loadUrl

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 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 把代码压缩成一行

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
              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

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <!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>