WebAppInterface.java(必须存在)
java
package com.example.chapter05;
import android.content.Context;
import android.webkit.JavascriptInterface;
import android.widget.Toast;
public class WebAppInterface {
Context mContext;
// 构造函数
WebAppInterface(Context c) {
mContext = c;
}
// 这个方法将被 JavaScript 调用
@JavascriptInterface
public void receiveDataFromAndroid(String data) {
// 在这里处理接收到的数据
Toast.makeText(mContext, "收到数据: " + data, Toast.LENGTH_SHORT).show();
// 你可以将数据存储到变量、发送广播、更新UI等
}
// 你还可以添加更多方法,例如传递复杂数据(JSON)
@JavascriptInterface
public void receiveUserData(String name, int age, String jsonExtra) {
// 处理更复杂的数据
}
}
java
package com.example.chapter05;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowInsetsController;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置透明状态栏
View decorView = getWindow().getDecorView();
getWindow().setStatusBarColor(Color.TRANSPARENT); // 保持状态栏透明
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// Android 11+ 设置状态栏图标为深色(浅色背景)
getWindow().getInsetsController().setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
} else {
// Android 10 及以下
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR // 状态栏图标变深色
);
}
webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true); // 启用JavaScript
webView.getSettings().setDomStorageEnabled(true); // 启用DOM存储
// 注入接口对象到 JavaScript 环境,允许 JS 调用 Android 方法
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
// 设置 WebViewClient,以便在 WebView 内部加载页面,并监听页面加载状态
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, android.graphics.Bitmap favicon) {
super.onPageStarted(view, url, favicon);
// 可选:显示加载动画或进度条
Log.d("WebView", "页面开始加载: " + url);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.d("WebView", "页面加载完成: " + url);
updateUIForUrl(url);
// ✅ 关键修复:在页面加载完成后,再执行 JS 传参
// 避免页面未加载时 JS 函数不存在
String username = "your_username"; // 替换为实际用户名
String password = "your_password"; // 替换为实际密码
// 对单引号进行转义,防止 JS 语法错误
String safeUsername = username.replace("'", "\\'");
String safePassword = password.replace("'", "\\'");
// 构造 JS 脚本,调用 H5 页面中的 receiveData 函数
// 添加存在性检查,避免报错
String jsCode = String.format(
"javascript:(function() {" +
" if (typeof receiveData === 'function') {" +
" receiveData('%s', '%s');" +
" } else {" +
" console.warn('H5 页面未定义 receiveData 函数');" +
" }" +
"})();",
safeUsername, safePassword
);
// 执行 JS
webView.evaluateJavascript(jsCode, null);
}
});
// 加载 H5 页面(不通过 URL 传参)
webView.loadUrl("http://xxx/h5/login");
// 添加后退事件的回调处理
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (webView.canGoBack()) {
webView.goBack(); // WebView 返回上一页
} else {
setEnabled(false); // 禁用当前回调
MainActivity.this.onBackPressed(); // 交由 Activity 处理退出
}
}
};
getOnBackPressedDispatcher().addCallback(this, callback);
// 获取并打印状态栏高度(调试用)
float statusBarHeight = getStatusBarHeight();
Log.d("MainActivity", "状态栏高度: " + statusBarHeight + "px");
}
/**
* 根据当前加载的 URL 更新 UI,例如沉浸式状态栏
*/
private void updateUIForUrl(String url) {
if (url.contains("login")) {
} else {
}
}
/**
* 获取状态栏高度(单位:px)
*
* @return 状态栏高度
*/
public float getStatusBarHeight() {
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
return getResources().getDimension(resourceId);
}
return 0;
}
}
h5页面 接收和传参
javascript
<script setup>
import { ref } from 'vue';
const username = ref('');
const password = ref('');
// 定义接收数据的函数
function receiveData(u, p) {
username.value = u;
password.value = p;
console.log('接收到数据 - 用户名: ' + u + ', 密码: ' + p);
}
// ✅ 关键:将函数挂载到 window 对象,供 Android 调用
// 这样 window.receiveData 就可以在 evaluateJavascript 中调用
window.receiveData = receiveData;
// ✅ 调用 Android 原生方法
function sendToAndroid() {
if (window.Android) {
window.Android.receiveDataFromAndroid('h5向Android发送数据');
} else {
console.error("Android 接口未注入,可能不在 App 环境");
alert("当前不在 App 中,无法调用原生功能");
}
}
// 可选:同时暴露给父组件(如果需要)
defineExpose({ receiveData });
</script>
<template>
<div>
<h2>登录页面</h2>
<p>用户名: {{ username }}</p>
<p>密码: {{ password }}</p>
<button @click="sendToAndroid">向 Android 传参</button>
</div>
</template>
<style scoped lang="less">
/* 你的样式 */
</style>