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¶m2=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 传入的数据