【Android View】使用WebViewJavaScriptBridge

本文介绍在Android应用中实现H5页面调用Java方法的方法,包括WebView配置、注入JS文件及提供可调用的Android方法等关键技术点。


最近接手一个需求,涉及到h5页面调用java方法。

虽然开发Android三年了,但我并没有开发过需要h5页面调用java方法的需求。在做相关的业务开发之前,我自己研究了一些js调用java代码的背景知识,这里做一下总结。

WebView基本使用方法:

(1)可动态添加、也可在xml内添加

xml中添加

<WebView
                android:id="@+id/webview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />
动态添加
webViewContainer = (LinearLayout) mRootView.findViewById(R.id.h5_webview_container);
        webViewContainer.removeAllViews();
        webView = new H5WebView(context);
        webView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        //初始化
        webViewContainer.addView(webView);

(2)设置WebView相关属性
private void initWebViewSetting() {
        WebSettings webSetting = this.getSettings();
        if(VERSION.SDK_INT >= 16) {
            webSetting.setAllowFileAccessFromFileURLs(true);
            webSetting.setAllowUniversalAccessFromFileURLs(true);
        }

        if(Env.isTestEnv() && VERSION.SDK_INT > 19) {
            setWebContentsDebuggingEnabled(true);
        }

        if(VERSION.SDK_INT >= 21) {
            webSetting.setMixedContentMode(0);
        }

        if(VERSION.SDK_INT >= 17) {
            webSetting.setMediaPlaybackRequiresUserGesture(false);
        }

        this.setVerticalScrollBarEnabled(false);
        this.setHorizontalScrollBarEnabled(false);
        this.setOverScrollMode(2);
        String padFlag = "";
        if(DeviceInfoUtil.isTablet()) {
            padFlag = "_Ctrip_Pad_App_";
        }

        String dbPath;
        if(StringUtil.emptyOrNull(H5Global.USER_AGENT_STRING) || !H5Global.USER_AGENT_STRING.contains("CtripWireless_")) {
            dbPath = webSetting.getUserAgentString() + "_eb64_" + padFlag + this.getCustomAppName() + "CtripWireless_" + H5UtilPlugin.getAppVersion(this.getContext());
            H5Global.USER_AGENT_STRING = dbPath;
        }

        webSetting.setUserAgentString(H5Global.USER_AGENT_STRING);
        if(VERSION.SDK_INT >= 11) {
            webSetting.setAllowContentAccess(true);
        }

        webSetting.setJavaScriptEnabled(true);
        webSetting.setDomStorageEnabled(true);
        dbPath = this.getContext().getApplicationContext().getDir("database", 0).getPath();
        webSetting.setDatabasePath(dbPath);
        webSetting.setUseWideViewPort(true);
        webSetting.setLoadWithOverviewMode(true);
        webSetting.setAppCacheEnabled(true);
        webSetting.setAppCacheMaxSize(10506250L);
        webSetting.setAppCachePath(dbPath);
        webSetting.setTextSize(TextSize.NORMAL);
        webSetting.setRenderPriority(RenderPriority.HIGH);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
        this.setWebChromeClient(new VideoEnabledWebChromeClient() {
            {
                Object var3 = null;
                if(EncodeUtil.classVerify) {
                    System.out.println(ClassLoadVerifyPatch.class);
                }

            }

            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                String message = consoleMessage.message();
                int lineNumber = consoleMessage.lineNumber();
                String sourceID = consoleMessage.sourceId();
                String log = "日志:" + message;
                H5WebView.this.writeLog(log);
                H5WebView.this.printLogInfo(log);
                return super.onConsoleMessage(consoleMessage);
            }
        });
        this.setWebViewClient(this.getWebClient());
    }


Android如何为h5提供一个可调用方法:

(1)在WebView中添加javaScript可以直接调用的接口:

addJavascriptInterface()
这个接口有两个参数,第一个参数就是包含了JS代码需要调用的java方法的类的实例,第二个参数是给这个实例起一个名字

(2)在JS中调用java方法的代码:

Test.doSomething();

这个“Test”就是我们在上一步给实例起的名字,doSomething方法是我们写好的给js调用的方法。

(3)注意事项

在doSomething方法里的代码是要运行在主线程上的,所以要记得加上runOnUiThread


Android如何注入js文件:

1、为什么需要注入js文件?

因为在我们开发的一个app上,h5的埋点上报方法总是出错,所以希望h5的埋点上报通过调用Android的埋点上报方法来实现。关键在于,h5方面已经无法在原本的js上直接修改了,需要加入一个js文件来hook到h5的埋点上报方法,然后再调用android的原生方法。

这就需要在Android加载完每个h5页面时注入一个js文件,并且Android需要为h5提供一个埋点上报方法。

2、如何实现注入.js文件?

我们在这个app上使用的是目前使用最广泛的webViewJavaScriptBridge开源库,这个开源库提供了webView加载完成的回调方法。我们只需要在这里注入.js文件?

 try {
            InputStream is = webView.getContext().getAssets()
                    .open("CtripLocalUBT.js");
            int size = is.available();
            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();
            String js = new String(buffer);
            executeJavascript(js);
        } catch (IOException e) {
            e.printStackTrace();
        }

3、如何为h5提供可调用的Android方法?
registerHandler("trackJSLog", new WVJBHandler() {
                @Override
                public void request(Object data, WVJBResponseCallback callback) {
                    Log.e(TAG, "track_js_callback");
                    String d = (String) data;
                    if (!TextUtils.isEmpty(d)) {
                        try {
                            JSONObject object = new JSONObject(d);
                            String code = object.optString("code");
                            JSONObject tags = object.optJSONObject("tags");
                            HashMap<String, String> map = JsonHelper.JSONObjectToHashMap(tags);
                            CtripActionLogUtil.trackJSLog(code, map);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
<think>嗯,用户询问Android WebView桥接的实现与使用方法,这个问题需要结合站内引用内容来分析回答。从引用[1]可以看出,WebView桥接的核心是实现JavaScript与Native的通信,引用中提到了使用WebView控件是Android的特性之一。引用[2]对比了主流桥接库的优缺点,比如JsBridge和DSBridge-Android的特性差异,这对回答很有参考价值。引用[3]展示了实际代码中使用BridgeWebView的布局示例,可以当作具体实现的示范。 用户可能正在开发Hybrid应用,需要选择适合的桥接方案。考虑到用户是开发者,应该重点提供技术选型建议和具体实现步骤。需要强调几个关键点:基础原理是addJavascriptInterface方法的安全性隐患,以及主流库如何解决这个问题;对比库时要突出JsBridge的轻量和DSBridge的双平台支持特性;实际集成时要注意WebView配置和回调处理。 在组织回答结构时,准备分原理、库对比、实现步骤三部分。原理部分要用数学公式说明函数映射关系,比如用$f_{native} \leftrightarrow f_{js}$表示双向调用。对比表格需要包含安全性和平台支持等维度。代码示例将采用JsBridge,因为引用[3]的示例也是基于这个库,用户可能更熟悉。 最后考虑设计相关问题来延伸讨论,比如混合开发优化和安全防护,这能帮助用户应对更复杂的场景。需要确保所有行内代码和公式都用$...$包裹,独立公式如Promise机制要单独成段。每个技术要点都要自然关联引用标记,比如解释@JavascriptInterface时标注[^2]。 </think>以下是Android WebView桥接的实现与使用指南,结合技术原理和主流方案: ### 一、桥接核心原理 WebView桥接本质是建立**JavaScript与Native代码的双向通信通道**: 1. **JS调用Native** - 通过`WebView.addJavascriptInterface()`注入Java对象(需API≥17添加`@JavascriptInterface`注解) - 拦截特定格式URL请求(如`jsbridge://method?params=xxx`) ```java // 原生注入示例 class JSBridge { @JavascriptInterface public void showToast(String msg) { Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } } webView.addJavascriptInterface(new JSBridge(), "AndroidBridge"); ``` ```javascript // JS调用 AndroidBridge.showToast("Hello from JS!"); ``` 2. **Native调用JS** 通过`WebView.loadUrl("javascript:func()")`或`evaluateJavascript()`(API≥19) ```java // 执行JS函数 webView.evaluateJavascript("window.updateData('"+data+"')", null); ``` > 安全性注意:API<17的`addJavascriptInterface`存在漏洞,需用URL拦截方案替代[^1][^2] ### 二、主流桥接库对比 | **库名称** | **优势** | **劣势** | **适用场景** | |------------------|----------------------------------|----------------------------------|--------------------------| | **原生方案** | 无需第三方库 | 需自行处理兼容性和安全 | 简单交互场景 | | **JsBridge** | 轻量级,无额外JS依赖 | 仅支持Android,接口管理不便 | 纯Android项目 | | **DSBridge** | 支持iOS/Android,接口按类管理 | 需引入JS文件,继承自定义WebView | 跨平台混合开发 | | **官方WebMessage**| Android官方方案,安全性高 | 仅支持API≥23 | 新项目开发 | ### 三、JsBridge实战步骤(引用[3]示例) 1. **添加依赖** ```gradle implementation 'com.github.lzyzsd:jsbridge:1.0.4' ``` 2. **XML布局** ```xml <com.github.lzyzsd.jsbridge.BridgeWebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent"/> ``` 3. **Native注册方法** ```java BridgeWebView webView = findViewById(R.id.webview); webView.registerHandler("scanQR", (data, callback) -> { // 执行扫码逻辑 callback.onResult("QR_RESULT"); }); ``` 4. **JS调用Native** ```javascript WebViewJavascriptBridge.callHandler('scanQR', {}, function(response) { alert("扫码结果: " + response); }); ``` 5. **Native调用JS** ```java webView.callHandler("updateCart", "{\"items\":5}", data -> { Log.d("JS回调", data); }); ``` ### 四、安全实践 1. **开启HTTPS**防止中间人攻击 2. **校验域名白名单** ```java webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (!isSafeDomain(url)) throw new SecurityException(); return super.shouldOverrideUrlLoading(view, url); } }); ``` 3. **关闭敏感权限** ```java webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setAllowFileAccess(false); // 禁用文件访问 ``` > 关键建议:复杂项目推荐DSBridge管理接口,小型项目可用JsBridge快速实现[^2][^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值