杰瑞科技汇

Android中JS如何调用Java方法?

将 Java 对象或方法“注入”到 JavaScript 的全局作用域中,这样 JS 就可以通过一个约定的名字来访问并调用 Java 代码。

Android中JS如何调用Java方法?-图1
(图片来源网络,侵删)

我们将分步进行讲解,从最基础到更高级的用法。


第一步:准备工作 - 添加 WebView

你需要在你的 Activity 或 Fragment 中添加一个 WebView 控件,并加载一个 HTML 页面,这个页面将包含你的 JavaScript 代码。

布局文件 (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Java/Kotlin 代码 (MainActivity.javaMainActivity.kt)

// MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
    private WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = findViewById(R.id.webview);
        // 启用 JavaScript
        webView.getSettings().setJavaScriptEnabled(true);
        // 设置 WebViewClient,确保页面在 WebView 内部加载,而不是跳转到外部浏览器
        webView.setWebViewClient(new WebViewClient());
        // 加载本地 HTML 文件
        // 假设你的 html 文件放在 assets 文件夹下
        webView.loadUrl("file:///android_asset/my_page.html");
    }
}

重要: 为了让 WebView 能够正常工作,你还需要在 AndroidManifest.xml 中添加网络权限(即使加载本地文件,有时也需要)。

<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application ...>
        ...
    </application>
</manifest>

第二步:基础用法 - JS 调用 Java 无参方法

这是最简单的场景,JS 调用一个不需要参数的 Java 方法。

Android中JS如何调用Java方法?-图2
(图片来源网络,侵删)

创建一个 Java 接口

这个接口将作为 JS 和 Java 之间的桥梁,接口中的方法就是 JS 可以调用的方法。

// JsInterface.java
package com.example.webviewdemo;
public interface JsInterface {
    void showToastFromJava();
}

在 Activity 中实现接口并注入

我们将上面的接口在 MainActivity 中实现,并将其注入到 WebView 的 JavaScript 环境中。

// MainActivity.java (修改后)
public class MainActivity extends AppCompatActivity implements JsInterface {
    private WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = findViewById(R.id.webview);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient());
        // 关键步骤:将实现了 JsInterface 的对象注入到 WebView 中
        // 参数1: 对象的引用 (this)
        // 参数2: 在 JavaScript 中可以调用的对象名称 ( android)
        webView.addJavascriptInterface(this, "android");
        webView.loadUrl("file:///android_asset/my_page.html");
    }
    @Override
    public void showToastFromJava() {
        // 这个方法将在 JS 被调用时执行
        Toast.makeText(this, "Hello from Java!", Toast.LENGTH_SHORT).show();
    }
}

注意: 从 Android 4.2 (API 17) 开始,为了安全,所有被注入的接口都必须被 @JavascriptInterface 注解标记,如果你不使用接口,而是直接注入一个类,那么需要注解类中的公共方法。

// 另一种方式:直接注入一个类 (不推荐,但常见于旧代码)
// 从 API 17 开始,方法必须有 @JavascriptInterface 注解
public class JsInterfaceClass {
    @JavascriptInterface
    public void showToastFromJava() {
        // ...
    }
}
// 在 Activity 中使用
// webView.addJavascriptInterface(new JsInterfaceClass(), "android");

编写 HTML 和 JavaScript 代码

在你的 assets 文件夹下创建 my_page.html 文件。

Android中JS如何调用Java方法?-图3
(图片来源网络,侵删)
<!-- assets/my_page.html -->
<!DOCTYPE html>
<html>
<head>JS Call Java Demo</title>
    <script type="text/javascript">
        function callJavaMethod() {
            // 通过我们注入的名称 "android" 调用 Java 方法
            // android.showToastFromJava();
            if (window.android) {
                android.showToastFromJava();
            } else {
                alert("Android interface not found!");
            }
        }
    </script>
</head>
<body>
    <h1>WebView JS to Java Demo</h1>
    <button onclick="callJavaMethod()">Call Java showToast()</button>
</body>
</html>

运行 App,点击按钮,你就能看到一个 Toast 提示了。


第三步:进阶用法 - JS 调用 Java 带参方法

JS 可以向 Java 方法传递基本数据类型(如 String, int, double, boolean)和一些 Android 支持的类型(如 JSONObject)。

修改 Java 接口

// JsInterface.java
public interface JsInterface {
    void showToastFromJava();
    void sendValueToJava(String value, int number);
}

在 Activity 中实现新方法

// MainActivity.java
@Override
public void sendValueToJava(String value, int number) {
    String message = "Received from JS: Value = " + value + ", Number = " + number;
    Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}

修改 HTML 代码

<!-- assets/my_page.html (修改后) -->
<script type="text/javascript">
    function callJavaMethod() {
        android.showToastFromJava();
    }
    function sendValueToJava() {
        var myText = "Hello WebView";
        var myNumber = 2025;
        // 调用带参方法,并传递参数
        android.sendValueToJava(myText, myNumber);
    }
</script>
...
<body>
    ...
    <button onclick="callJavaMethod()">Call Java showToast()</button>
    <button onclick="sendValueToJava()">Send Value to Java</button>
</body>

第四步:安全警告与最佳实践

直接使用 addJavascriptInterface 存在严重的安全风险,主要针对 Android 4.1.1 (API 16) 及更低的版本,这个漏洞被称为 JavaScript Interface Injection,恶意网站可以通过反射调用你注入的任何 Java 对象的公共方法,可能导致敏感信息泄露或执行恶意代码。

如何安全地使用 addJavascriptInterface

  1. 最低 SDK 版本:如果你的 minSdkVersion 大于等于 17 (Android 4.2),那么你只需要给要暴露的方法加上 @JavascriptInterface 注解即可,风险大大降低。
  2. 最低 SDK 版本 < 17:如果你必须支持低于 API 17 的系统,强烈建议不要使用 addJavascriptInterface,你应该采用更安全的替代方案。

安全的替代方案:@JavascriptInterface + 限制 URL

这是目前最推荐的通用安全做法,即使在高版本上也是良好实践。

核心思想: 只在 WebView 完全加载了受信任的 URL 之后,才将接口注入进去。

// MainActivity.java
public class MainActivity extends AppCompatActivity implements JsInterface {
    private WebView webView;
    private static final String TRUSTED_URL = "file:///android_asset/my_page.html"; // 或者你自己的域名
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = findViewById(R.id.webview);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                // 只在页面加载完成,URL 是我们信任的 URL 时,才注入接口
                if (url.equals(TRUSTED_URL)) {
                    view.addJavascriptInterface(MainActivity.this, "android");
                }
            }
        });
        // 加载页面
        webView.loadUrl(TRUSTED_URL);
    }
    // ... 其他方法
}

通过这种方式,即使你的 App 加载了恶意网页,由于 onPageFinished 中的 URL 检查,恶意网页也无法获取到 android 这个接口对象,从而避免了安全漏洞。


第五步:Java 调用 JavaScript (反向调用)

虽然你的问题只问了 JS 调用 Java,但了解反向调用也非常有用。

Java 调用 JS 非常直接,使用 WebViewevaluateJavascript() 方法。

// 在 MainActivity 的某个方法中,例如在按钮点击事件里
public void callJavaScriptMethod() {
    webView.evaluateJavascript("showAlertFromJS('Message from Java!')", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            // value 是 JS 方法的返回值,这里我们不需要,所以可以为空
            // JS 方法有返回值,value 就是那个返回值
        }
    });
}

对应的 HTML 中的 JS 方法:

// assets/my_page.html
function showAlertFromJS(message) {
    alert(message);
    // 也可以返回一个值
    // return "JS received: " + message;
}

场景 步骤 关键代码/说明
JS 调 Java 创建接口 public interface JsInterface { ... }
实现接口 public class MainActivity implements JsInterface
注入接口 webView.addJavascriptInterface(this, "android");
JS 调用 android.javaMethodName();
安全 限制注入时机 WebViewClient.onPageFinished() 中检查 URL 后再注入。
Java 调 JS 执行 JS 代码 webView.evaluateJavascript("jsFunctionName(args)", callback);

在处理 WebView 和 JavaScript 交互时,安全永远是第一位的,始终采用 @JavascriptInterface 并限制注入 URL 的策略。

分享:
扫描分享到社交APP
上一篇
下一篇