Android 关于注入Js处理Android和H5 Js 交互问题

0 阅读2分钟

记录一个丑陋的BUG!!!

BUG说明:

项目对接ZegoGame 的H5游戏 需要对接游戏的H5.一些Android 和H5 交互需要相互效用....

噩梦开始了!!!

js 回调不通,后台一问三不知,产品不让我联系zego技术!!!!!日了狗了

问题说明:

image.png

image.png

image.png

参考截图

  • Android端的Js配置和H5的Js调用对不上(H5没按照文档写)

解决思路

Js 注入覆盖或者修改H5的Js方法

1:WebView 配置

核心方法

  • settings.setJavaScriptEnabled(true); 开启Js桥
  • webView.addJavascriptInterface(new GameJsBridge(this), "app"); 注册回调内容
  • onPageFinished () 页面加载完成
private WebView initWebView() {
    webView.setBackgroundColor(Color.TRANSPARENT);
    //update webview settings
    WebSettings settings = webView.getSettings();
    settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
    settings.setBuiltInZoomControls(true);
    settings.setJavaScriptEnabled(true);
    settings.setDatabaseEnabled(true);
    settings.setDomStorageEnabled(true);
    //set webview client
    webView.setWebChromeClient(new WebChromeClient());
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Log.d(TAG, "onPageStarted");
        }
        @Override
        public void onPageFinished(WebView view, String url) {
            Log.d(TAG, "onPageFinished");
            webView.evaluateJavascript(
                    "(function() { " +
                            "   var originPostMessage = window.top.postMessage;" +
                            "   window.top.postMessage = function(data) { " +

                            "       var msg = (typeof data === 'string') ? data : JSON.stringify(data);" +

                            "       if(window.app && window.app.postMessage) {" +
                            "           window.app.postMessage(msg);" +
                            "       }" +

                            "       if(originPostMessage) {" +
                            "           originPostMessage.call(window.top, data, '*');" +
                            "       }" +

                            "   };" +
                            "})();",
                    null
            );

        }
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            String outUrl = request.getUrl().toString();
            view.loadUrl(outUrl);
            return true;
        }
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            Log.d(TAG, "onReceivedError: " + error);
        }
    });
    //add jsb
    webView.addJavascriptInterface(new GameJsBridge(this), "app");
    webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
  
    return webView;
}

1:Js回调桥配置


import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.JavascriptInterface;
import com.google.gson.Gson;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;

import es.dmoral.toasty.Toasty;

public class GameJsBridge {

    private static final String TAG = "Zego游戏";

    private final Context context;

    public GameJsBridge(@NotNull Context context) {
        this.context = context;
    }

    private JSONObject parseMsg(@NotNull String message) {
        try {
            return new JSONObject(message);
        } catch (JSONException e) {
            return null;
        }
    }

    @JavascriptInterface
    public void postMessage(String message) {
        Log.e(TAG, "postMessage: " + message);
        if (TextUtils.isEmpty(message)) return;
        try{

            JSONObject schemeInfo = parseMsg(message);
            if (schemeInfo == null) return;
            //'{"cid":"TO_CHARGE","params":{}
            String cid = schemeInfo.optString("cid");
            JSONObject params = schemeInfo.optJSONObject("params");
            if ("TO_CHARGE".equals(cid)) {
                // 支付
            
            } else if ("CLOSE_COCOS_VIEW".equals(cid)) {
                // 关闭全屏游戏
                if(context!=null&& context instanceof Activity)
                    ((Activity)context).finish();
            } else if ("NOTIFY_GAME_STATUS".equals(cid)) {
                if (params.optInt("status") == 4) {
                    // 🇺🇸en: When the game is settled, notify the client to refresh the balance displayed on the client
                    Toasty.normal(context, "complete").show();
                }
            }

        }catch (Exception e){

        }

    }

}

3.注入Js 代码

  • 在浏览器sources 中ctrl +shift+f 查找 GameJsBridge 中的postMessage

image.png

说明: H5 调用Js 调用的是

  • window.top.postMessage()
  • window.WTChannel.postMessage()

根据GameJsBridge 获取的是 cid 和 params

 
 String cid = schemeInfo.optString("cid");
 JSONObject params = schemeInfo.optJSONObject("params");
 

Js 代码注入 核心代码:

public void onPageFinished(WebView view, String url) {
    Log.d(TAG, "onPageFinished");
    webView.evaluateJavascript(
            "(function() { " +
                    "   var originPostMessage = window.top.postMessage;" +
                    "   window.top.postMessage = function(data) { " +

                    "       var msg = (typeof data === 'string') ? data : JSON.stringify(data);" +

                    "       if(window.app && window.app.postMessage) {" +
                    "           window.app.postMessage(msg);" +
                    "       }" +

                    "       if(originPostMessage) {" +
                    "           originPostMessage.call(window.top, data, '*');" +
                    "       }" +

                    "   };" +
                    "})();",
            null
    );

}

总结

当H5页面为三方或者外包的代码,时不时就会出现这种情况,所以移动端要想和他们撕逼.最好具备查询这种问题的能力.

  • 定位能力
  • 注入修改能力