核心概念
Android 和 JavaScript 运行在不同的环境中:

- Android (Java/Kotlin): 运行在 Dalvik/ART 虚拟机中,拥有应用的生命周期、UI 线程等。
- JavaScript: 运行在
WebView内部的 V8 (Chrome) 引擎中,是单线程的。
WebView 就像一个桥梁,连接了这两个世界。evaluateJavascript() 方法允许我们从 Android 端向桥的另一端(WebView 内部)发送一段 JavaScript 代码并执行,同时还能获取到执行结果。
基础步骤与核心代码
第一步:在 XML 布局文件中添加 WebView
<!-- activity_main.xml -->
<WebView
android:id="@+id/my_webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
第二步:在 Activity/Fragment 中获取 WebView 实例并设置基本属性
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
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.my_webview);
// 必须设置,否则会在默认浏览器中打开链接
webView.setWebViewClient(new WebViewClient());
// 启用 JavaScript
webView.getSettings().setJavaScriptEnabled(true);
// 加载本地 HTML 文件或远程 URL
// 加载本地 assets 目录下的 HTML 文件
webView.loadUrl("file:///android_asset/my_web_page.html");
// 或者加载远程网页
// webView.loadUrl("https://www.example.com");
}
}
关键点:
webView.getSettings().setJavaScriptEnabled(true);必须调用,否则evaluateJavascript()不会生效。webView.setWebViewClient(new WebViewClient());确保链接在WebView内部打开。
第三步:调用 evaluateJavascript() 方法执行 JS 代码
这是最核心的一步。evaluateJavascript 的签名如下:
// 第一个参数:要执行的 JavaScript 代码字符串 // 第二个参数:ValueCallback,用于接收 JS 代码的执行结果 public void evaluateJavascript(String script, ValueCallback<String> resultCallback)
示例 1:调用一个无参数、无返回值的 JS 函数

假设我们的 HTML 文件中有这样一个函数:
// my_web_page.html
<script>
function showToast() {
alert("Hello from JavaScript!");
}
</script>
在 Java 中调用它:
// 在 Activity 中
webView.evaluateJavascript("showToast()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// value 是 JS 函数的返回值。
// 对于 alert() 这种没有返回值的函数,value 通常是 "null"。
// 这个回调在 UI 线程执行。
System.out.println("JS function executed, returned: " + value);
}
});
示例 2:调用一个带参数,并返回值的 JS 函数
假设 JS 函数如下:

// my_web_page.html
<script>
function addNumbers(a, b) {
return a + b;
}
</script>
在 Java 中调用它,并处理返回值:
// 在 Activity 中
String jsCode = "addNumbers(5, 10);";
webView.evaluateJavascript(jsCode, new ValueCallback<String>() {
@Override
public void onReceiveValue(String result) {
// result 是一个字符串,包含了 JS 函数的返回值
// 这里 result 会是 "15"
try {
int sum = Integer.parseInt(result);
System.out.println("The sum is: " + sum);
// 你可以在这里更新 UI
runOnUiThread(() -> {
// 更新一个 TextView
// textView.setText("Sum from JS: " + sum);
});
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
});
完整示例
my_web_page.html (放在 app/src/main/assets/ 目录下)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">Android JS Interaction</title>
<style>
body { font-family: sans-serif; text-align: center; padding-top: 50px; }
button { font-size: 18px; padding: 10px 20px; margin: 10px; }
#result { font-size: 24px; color: green; margin-top: 20px; }
</style>
</head>
<body>
<h1>WebView JavaScript Bridge</h1>
<button id="androidCallBtn">Call Android Method</button>
<button id="jsCallBtn">Call JS Method (from Android)</button>
<div id="result"></div>
<script>
// JS 函数,供 Android 调用
function showToastFromAndroid(message) {
document.getElementById('result').innerText = "Message from Android: " + message;
// 也可以用 alert
// alert(message);
}
// JS 函数,带返回值,供 Android 调用
function getGreeting() {
return "Hello from JavaScript!";
}
// JS 函数,用于 Android 调用并获取返回值
function addNumbers(a, b) {
return a + b;
}
// 当页面加载完成后,监听按钮点击事件
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('androidCallBtn').addEventListener('click', function() {
// 调用 Android 的全局方法
if (window.AndroidInterface) {
window.AndroidInterface.showToast("Hello from JavaScript!");
} else {
document.getElementById('result').innerText = "AndroidInterface not found!";
}
});
document.getElementById('jsCallBtn').addEventListener('click', function() {
document.getElementById('result').innerText = "This button is for Android to call me.";
});
});
</script>
</body>
</html>
MainActivity.java
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView;
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.my_webview);
// 1. 设置 WebViewClient
webView.setWebViewClient(new WebViewClient());
// 2. 启用 JavaScript
webView.getSettings().setJavaScriptEnabled(true);
// 可选:处理 JS 的 alert, prompt, confirm 对话框
webView.setWebChromeClient(new WebChromeClient());
// 3. 添加 JavaScript 接口(让 JS 能调用 Android)
// "AndroidInterface" 是 JS 中调用的对象名称
webView.addJavascriptInterface(new WebAppInterface(), "AndroidInterface");
// 4. 加载 HTML
webView.loadUrl("file:///android_asset/my_web_page.html");
}
// 5. 定义一个内部类作为 JavaScript 接口
public class WebAppInterface {
// @JavascriptInterface 注解是必须的,否则无法从 JS 访问此方法
// 从 Android 4.2 (API 17) 开始强制要求
@JavascriptInterface
public void showToast(String toast) {
// 在这里执行 Android 代码
// 注意:这个回调在非 UI 线程,如果需要更新 UI,必须使用 runOnUiThread
runOnUiThread(() -> Toast.makeText(getApplicationContext(), toast, Toast.LENGTH_SHORT).show());
}
}
// 6. 在 Activity 的其他地方调用 JS 函数
public void callJsFunction() {
// 示例:调用 JS 的 showToastFromAndroid 方法
webView.evaluateJavascript("showToastFromAndroid('Data received from Android!')", null);
// 示例:调用 JS 的 getGreeting 方法并处理返回值
webView.evaluateJavascript("getGreeting()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// value 会是 "Hello from JavaScript!"
runOnUiThread(() -> Toast.makeText(MainActivity.this, "JS returned: " + value, Toast.LENGTH_LONG).show());
}
});
// 示例:调用 JS 的 addNumbers 方法
webView.evaluateJavascript("addNumbers(100, 200)", new ValueCallback<String>() {
@Override
public void onReceiveValue(String result) {
// result 会是 "300"
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "Sum from JS: " + result, Toast.LENGTH_SHORT).show();
});
}
});
}
// 别忘了在 Activity 销毁时销毁 WebView
@Override
protected void onDestroy() {
if (webView != null) {
webView.destroy();
webView = null;
}
super.onDestroy();
}
}
重要注意事项与最佳实践
线程问题
evaluateJavascript()的回调onReceiveValue()是在 UI 线程 执行的,所以你不需要手动切换到 UI 线程来更新 UI。- 通过
JavascriptInterface从 JS 调用过来的方法(如上面的showToast)是在 非 UI 线程 执行的,如果你需要更新 UI(如Toast,TextView),必须使用Activity.runOnUiThread()。
@JavascriptInterface 注解
- 从 Android 4.2 (API 17) 开始,所有暴露给 JavaScript 的 Java 方法都必须使用
@JavascriptInterface注解,否则,它们在 JS 端将不可见,这是一个重要的安全措施。
返回值处理
evaluateJavascript的回调接收的返回值永远是String类型。- JS 函数没有返回值,返回值通常是
"null"。 - JS 函数抛出异常,返回值会是一个以
Uncaught Error:开头的错误信息字符串。
安全性(非常重要!)
- 不要信任来自 WebView 的任何数据,JS 可能被恶意注入(加载了不安全的远程网页)。
- 在
JavascriptInterface的方法中,永远不要执行以下操作:- 执行任意文件路径拼接。
- 执行任意 shell 命令。
- 暴露敏感信息(如密码、token)。
- 对所有来自 JS 的输入进行严格的校验和过滤。
WebView 的生命周期
- 在
Activity的onDestroy()中,务必调用webView.destroy()来释放资源,防止内存泄漏。
从 JavaScript 调用 Android (反向调用)
这在上面的完整示例中已经展示了,是 addJavascriptInterface 的用途。
步骤:
- 创建一个 Java 类,包含你希望 JS 调用的方法。
- 在这些方法上加上
@JavascriptInterface注解。 - 在
WebView实例上调用addJavascriptInterface(yourObject, "jsObjectName"),将你的对象暴露给 JS。 - 在 JS 中,就可以通过
window.jsObjectName.yourMethod()来调用。
JS 代码示例:
// 调用 Android 的 showToast 方法
window.AndroidInterface.showToast("Hello, Android!");
| 功能 | 方法 | 说明 |
|---|---|---|
| Android 调用 JS | webView.evaluateJavascript("jsCode()", callback) |
执行任意 JS 代码,并能获取返回值。 |
| JS 调用 Android | webView.addJavascriptInterface(new MyInterface(), "MyInterface") |
在 JS 中通过 window.MyInterface.method() 调用。 |
| 必备设置 | webView.getSettings().setJavaScriptEnabled(true); |
启用 JS 支持。 |
| 安全注解 | @JavascriptInterface |
必须加在暴露给 JS 的方法上 (API 17+)。 |
| 线程安全 | runOnUiThread() |
在 JavascriptInterface 回调中更新 UI 时使用。 |
通过以上方法和注意事项,你就可以在 Android 应用中灵活地与 WebView 中的 JavaScript 进行双向通信了。
