欢迎光临升邦信息网
详情描述

Android 与 JavaScript 交互主要有两种方式:WebView 原生 API 和第三方库。以下是详细实现方法:

一、WebView 原生 API

1. Android 调用 JS

// 方法1:直接执行 JS 代码
webView.evaluateJavascript("javascript:callFromAndroid('Hello JS')", null);

// 方法2:加载 URL 方式(API 19 前)
webView.loadUrl("javascript:callFromAndroid('Hello JS')");

// 推荐的安全调用方式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    webView.evaluateJavascript("yourFunction('参数')", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            // 处理 JS 返回值
        }
    });
} else {
    webView.loadUrl("javascript:yourFunction('参数')");
}

2. JS 调用 Android

方式一:使用 @JavascriptInterface(推荐)

Android 端:

public class WebAppInterface {
    private Context context;

    @JavascriptInterface
    public void showToast(String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }

    @JavascriptInterface
    public String getDeviceInfo() {
        return Build.MODEL;
    }
}

// WebView 配置
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebAppInterface(), "Android");

JavaScript 端:

// 调用 Android 方法
Android.showToast("Hello from JS");

// 获取 Android 返回值
const deviceInfo = Android.getDeviceInfo();
console.log(deviceInfo);
方式二:通过 URL Scheme

Android 端:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();
        if (url.startsWith("js://")) {
            // 解析并处理 JS 调用
            handleJSCall(url);
            return true;
        }
        return super.shouldOverrideUrlLoading(view, request);
    }
});

JS 端:

location.href = "js://method?param1=value1&param2=value2";
方式三:通过 prompt()/alert()/console.log() 拦截
webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public boolean onJsPrompt(WebView view, String url, 
            String message, String defaultValue, 
            JsPromptResult result) {
        // 处理 JS prompt 调用
        if (message.startsWith("jsbridge://")) {
            handleBridgeCall(message);
            result.confirm("处理完成");
            return true;
        }
        return super.onJsPrompt(view, url, message, defaultValue, result);
    }
});

二、使用第三方库

1. JsBridge(推荐)

依赖:

implementation 'com.github.lzyzsd:jsbridge:1.0.4'

Android 端:

BridgeWebView webView = new BridgeWebView(context);
webView.getSettings().setJavaScriptEnabled(true);

// 注册 Handler
webView.registerHandler("getUserInfo", new BridgeHandler() {
    @Override
    public void handler(String data, CallBackFunction function) {
        User user = getUser();
        function.onCallBack(new Gson().toJson(user));
    }
});

// 调用 JS
webView.callHandler("jsFunction", "参数", new CallBackFunction() {
    @Override
    public void onCallBack(String data) {
        // 处理返回数据
    }
});

JS 端:

// 调用 Android
WebViewJavascriptBridge.callHandler('getUserInfo', 
    {'param': 'value'}, 
    function(responseData) {
        console.log(responseData);
    }
);

// 注册供 Android 调用的函数
WebViewJavascriptBridge.registerHandler('jsFunction', 
    function(data, responseCallback) {
        responseCallback('JS Response');
    }
);

2. SafeJavaJsBridge(安全增强版)

提供更安全的交互机制,防止 XSS 攻击。

三、双向通信最佳实践

1. 完整交互示例

public class JSBridgeActivity extends AppCompatActivity {
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        webView = new WebView(this);
        setContentView(webView);

        setupWebView();
        loadWebPage();
    }

    private void setupWebView() {
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);

        // 添加 JS 接口
        webView.addJavascriptInterface(new JSInterface(), "NativeBridge");

        // 设置 WebViewClient
        webView.setWebViewClient(new CustomWebViewClient());

        // 设置 WebChromeClient
        webView.setWebChromeClient(new CustomWebChromeClient());
    }

    // JS 接口类
    private class JSInterface {
        @JavascriptInterface
        public String getAppVersion() {
            return BuildConfig.VERSION_NAME;
        }

        @JavascriptInterface
        public void navigateTo(String screen) {
            runOnUiThread(() -> {
                // 处理导航逻辑
            });
        }
    }

    // 调用 JS 函数
    private void callJSFunction() {
        String jsCode = "window.handleNativeCall('data');";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            webView.evaluateJavascript(jsCode, null);
        } else {
            webView.loadUrl("javascript:" + jsCode);
        }
    }
}

2. 安全注意事项

// 1. 限制可访问的 JS 接口
webView.removeJavascriptInterface("searchBoxJavaBridge_");
webView.removeJavascriptInterface("accessibility");
webView.removeJavascriptInterface("accessibilityTraversal");

// 2. 设置域名白名单
private static final List<String> ALLOWED_DOMAINS = 
    Arrays.asList("yourdomain.com", "trusted.com");

// 3. 验证来源
@JavascriptInterface
public void sensitiveOperation(String data) {
    if (!isTrustedSource()) {
        return; // 拒绝执行
    }
    // 执行操作
}

// 4. 使用 HTTPS
webView.getSettings().setMixedContentMode(
    WebSettings.MIXED_CONTENT_NEVER_ALLOW);

四、高级功能

1. Promise 风格封装

public class JSBridgePromise {
    private static int callId = 0;
    private Map<String, Callback> callbacks = new HashMap<>();

    public void callJS(String method, String params, Callback callback) {
        String id = "call_" + (callId++);
        callbacks.put(id, callback);

        String js = String.format(
            "window.jsBridge.invoke('%s', '%s', '%s')",
            method, params, id
        );
        webView.evaluateJavascript(js, null);
    }

    @JavascriptInterface
    public void onResult(String id, String result) {
        Callback callback = callbacks.remove(id);
        if (callback != null) {
            callback.onResult(result);
        }
    }
}

2. JSON-RPC 协议

// 使用 JSON-RPC 2.0 规范
public class JSONRPCBridge {
    @JavascriptInterface
    public String invoke(String jsonRequest) {
        try {
            JSONObject request = new JSONObject(jsonRequest);
            String method = request.getString("method");
            JSONArray params = request.getJSONArray("params");
            String id = request.getString("id");

            // 路由到对应处理方法
            Object result = dispatch(method, params);

            JSONObject response = new JSONObject();
            response.put("jsonrpc", "2.0");
            response.put("result", result);
            response.put("id", id);

            return response.toString();
        } catch (Exception e) {
            return createErrorResponse(e);
        }
    }
}

五、调试技巧

// 启用调试
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
}

// Chrome DevTools 地址:
// chrome://inspect/#devices

选择建议:

简单需求:使用原生 @JavascriptInterface 复杂交互:使用 JsBridge 或类似库 安全性要求高:使用 SafeJavaJsBridge + 严格的校验机制 需要 Promise 支持:自行封装或使用成熟的库

关键点:

  • 始终在主线程处理 UI 更新
  • 注意内存泄漏问题
  • 做好异常处理和超时控制
  • 严格验证 JS 传入的数据
相关帖子
发芽土豆里常被提到的龙葵素到底是什么,它其实是土豆用来自我保护的一种天然物质吗?
发芽土豆里常被提到的龙葵素到底是什么,它其实是土豆用来自我保护的一种天然物质吗?
新沂市房产网站建设@网站开发制作,定制建站
新沂市房产网站建设@网站开发制作,定制建站
如何根据个人的饮食和生活习惯,优化专属的睡前口腔护理方案?
如何根据个人的饮食和生活习惯,优化专属的睡前口腔护理方案?
个人如何定期获取并查看自己的信用报告,以确保信息准确无误?
个人如何定期获取并查看自己的信用报告,以确保信息准确无误?
除了退款,消费者因外卖吃出虫子还可以主张哪些合理的赔偿项目?
除了退款,消费者因外卖吃出虫子还可以主张哪些合理的赔偿项目?
宁陵县个人小额银行信用贷款|汽车抵押借款,房产抵押贷款条件
宁陵县个人小额银行信用贷款|汽车抵押借款,房产抵押贷款条件
普洱市分期车抵押贷款#车辆抵押公司,附近个人贷款办理
普洱市分期车抵押贷款#车辆抵押公司,附近个人贷款办理
临清市债务重组垫资@汽车抵押贷款押车绿本,房产抵押应急贷款
临清市债务重组垫资@汽车抵押贷款押车绿本,房产抵押应急贷款
桐城市车子抵押业主短期周转贷款@红本抵押贷款,债务重整
桐城市车子抵押业主短期周转贷款@红本抵押贷款,债务重整
涿州市办理个人信用贷款-汽车抵押借款押车,个人房产贷款公司
涿州市办理个人信用贷款-汽车抵押借款押车,个人房产贷款公司
汝州市贷款正规公司|汽车抵押贷款办理押车,房屋抵押贷款流程
汝州市贷款正规公司|汽车抵押贷款办理押车,房屋抵押贷款流程
武江区办理小额银行信用贷款@汽车押大本借款,房本抵押消费贷款
武江区办理小额银行信用贷款@汽车押大本借款,房本抵押消费贷款
宿迁市典当行抵押汽车借款@汽车抵押贷款车被开走,公司抵押贷款
宿迁市典当行抵押汽车借款@汽车抵押贷款车被开走,公司抵押贷款
如果站在月球表面上看
如果站在月球表面上看"地食",你会看到地球的影子慢慢掠过地球还是另一种画面?
茂名市个人消费贷款|汽车抵押个人贷款,正规房抵贷
茂名市个人消费贷款|汽车抵押个人贷款,正规房抵贷
长兴县苹果手机app开发@网站制作设计服务公司,定制开发
长兴县苹果手机app开发@网站制作设计服务公司,定制开发
岳阳县汽车贷款押证不押车@房产证抵押贷款,应急贷款公司
岳阳县汽车贷款押证不押车@房产证抵押贷款,应急贷款公司
卧龙区大额银行贷款@车辆抵押贷款不押车公司,房产红本抵押银行贷款
卧龙区大额银行贷款@车辆抵押贷款不押车公司,房产红本抵押银行贷款
潜江市货车贷款#车辆抵押贷款门店办理,企业税票贷款
潜江市货车贷款#车辆抵押贷款门店办理,企业税票贷款