Android java 设计封装增强型WebView组件(兼容Android 4.4+)
* 特性:
* 1. 全生命周期管理
* 2. 智能硬件加速
* 3. 链式配置API
* 4. 安全下载管理
* 5. 全屏视频支持
public class EnhancedWebView extends WebView {
private CustomWebChromeClient mChromeClient;
private DownloadManager mDownloadManager;
// 链式配置构建器
public static class Builder {
private final Context mContext;
private boolean mJavaScriptEnabled = true;
private int mCacheMode = WebSettings.LOAD_DEFAULT;
public Builder(Context context) {
mContext = context;
}
public Builder setJavaScriptEnabled(boolean enabled) {
mJavaScriptEnabled = enabled;
return this;
}
public Builder setCacheMode(@NonNull int cacheMode) {
mCacheMode = cacheMode;
return this;
}
public EnhancedWebView build() {
EnhancedWebView webView = new EnhancedWebView(mContext);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(mJavaScriptEnabled);
settings.setCacheMode(mCacheMode);
// ... 其他配置项
return webView;
}
}
public EnhancedWebView(Context context) {
super(context);
initWebView(context);
}
private void initWebView(Context context) {
// 智能硬件加速(API 14+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
// 安全下载管理
mDownloadManager = new DownloadManager(context);
setDownloadListener(this::handleDownload);
}
// 全生命周期管理
public void onResume() {
resumeTimers();
if (mChromeClient != null) mChromeClient.onResume();
}
public void onPause() {
pauseTimers();
if (mChromeClient != null) mChromeClient.onPause();
}
public void onDestroy() {
loadUrl("about:blank");
stopLoading();
setWebChromeClient(null);
setWebViewClient(null);
destroy();
}
// 全屏视频支持
@Override
public void setWebChromeClient(WebChromeClient client) {
mChromeClient = new CustomWebChromeClient(getContext());
super.setWebChromeClient(mChromeClient);
}
// 安全下载处理
private void handleDownload(String url, String userAgent,
String contentDisposition,
String mimeType, long contentLength) {
if (isUnsafeFileType(mimeType)) {
showSecurityWarning();
return;
}
mDownloadManager.startDownload(url, mimeType);
}
// 自定义WebChromeClient(处理全屏视频)
private class CustomWebChromeClient extends WebChromeClient {
private View mCustomView;
private CustomViewCallback mCustomViewCallback;
public CustomWebChromeClient(Context context) {
// 初始化全屏处理相关参数
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
// 实现全屏视频逻辑
if (mCustomView != null) {
onHideCustomView();
return;
}
mCustomView = view;
mCustomViewCallback = callback;
// 将自定义视图添加到DecorView
}
@Override
public void onHideCustomView() {
// 退出全屏处理
if (mCustomView == null) return;
// 移除自定义视图
mCustomViewCallback.onCustomViewHidden();
mCustomView = null;
}
}
}
关键实现说明:
- 生命周期管理
- 提供onResume()/onPause()/onDestroy()方法与Activity/Fragment生命周期绑定
- 在销毁时主动清理资源,防止内存泄漏
- 智能硬件加速
- 根据API版本自动启用硬件加速层(LAYER_TYPE_HARDWARE)
- 兼容Android 4.0+设备
- 链式配置API
- 采用Builder模式实现流畅配置接口
- 支持常见配置项:缓存策略、JavaScript开关等
4. 安全下载管理
- 内置文件类型安全检查
- 集成DownloadManager实现安全下载
- 支持自定义安全策略扩展
- 全屏视频支持
- 通过自定义WebChromeClient处理全屏回调
- 维护全屏视图状态机
- 兼容系统全屏回调接口
使用示例:
// 链式配置
EnhancedWebView webView = new EnhancedWebView.Builder(context)
.setJavaScriptEnabled(true)
.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK)
.build();
// 生命周期绑定
@Override
protected void onResume() {
super.onResume();
webView.onResume();
}
@Override
protected void onDestroy() {
webView.onDestroy();
super.onDestroy();
}
重新整理兼容低版本
/**
* EnhancedWebView.java
*
* 增强型 WebView 组件(兼容 Android 4.4+ 与低版本 Java)
*
* 主要特性:
* 1. 多进程数据隔离(API 17+)
* 2. 硬件加速与网络优化设置
* 3. 安全策略:URL 白名单和禁止协议验证、SSL 错误处理
* 4. 全屏视频支持(通过自定义 WebChromeClient 与 FullScreenHandler)
* 5. 内存优化:分步释放资源、反射销毁处理低版本兼容
* 6. Builder 链式配置 API
* 7. 提供 JavaScript 桥接接口(注意安全性)
*
* 注意:
* (1)所有 WebView 操作务必在主线程中执行
* (2)请在 Activity 的生命周期 onResume/onPause/onDestroy 中调用相应的 onResumeWebView()/onPauseWebView()/destroy() 方法
* (3)多进程模式需要在 AndroidManifest.xml 中做相应配置,例如:
*
* <activity
* android:name=".WebActivity"
* android:process=":webview" />
*/
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.DownloadListener;
import android.webkit.SslErrorHandler;
import android.webkit.SslError;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class EnhancedWebView extends WebView {
private static final String PROCESS_SUFFIX = ":webview";
private FullScreenHandler mFullScreenHandler;
private SecurityConfig mSecurityConfig = new SecurityConfig();
private boolean mIsMultiProcess = false;
// ========== 构造函数 ==========
public EnhancedWebView(Context context) {
super(context);
initWebView(context);
}
public EnhancedWebView(Context context, AttributeSet attrs) {
super(context, attrs);
initWebView(context);
}
public EnhancedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initWebView(context);
}
// ========== 初始化各模块 ==========
/**
* 初始化 WebView 参数、功能配置、下载监听等
*/
private void initWebView(Context context) {
initMultiProcess(context);
initHardwareAcceleration();
initNetworkSettings();
initSecuritySettings();
initFullScreenSupport(context);
// 设置下载监听器(低版本 Java,不使用 lambda)
setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent,
String contentDisposition,
String mimeType, long contentLength) {
handleDownload(url, userAgent, contentDisposition, mimeType, contentLength);
}
});
}
/**
* 初始化多进程支持(仅 API 17 及以上有效)
*/
private void initMultiProcess(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
String processName = getProcessName(context);
if (!processName.endsWith(PROCESS_SUFFIX)) {
mIsMultiProcess = true;
WebView.setDataDirectorySuffix(processName); // 设置独立数据目录
}
}
}
/**
* 根据系统版本设置硬件或软件加速
*/
private void initHardwareAcceleration() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
/**
* 初始化 WebSettings 相关配置,包括 JS、DOM 存储、混合内容模式等。
*/
private void initNetworkSettings() {
WebSettings settings = getSettings();
// 启用 JavaScript、DOM 及数据库支持
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
// 针对 Lollipop 及以上版本,允许混合内容(兼容 HTTP 与 HTTPS 混合)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
}
// 视图和布局优化
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
} else {
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
}
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
}
/**
* 初始化安全设置,可根据需要扩展
*/
private void initSecuritySettings() {
// 例如:禁用文件访问,防止本地文件注入风险
getSettings().setAllowFileAccess(false);
}
/**
* 初始化全屏视频支持,该功能需要传入 Activity 对象
*/
private void initFullScreenSupport(Context context) {
if (context instanceof Activity) {
mFullScreenHandler = new FullScreenHandler((Activity) context);
}
}
// ========== 安全策略处理 ==========
/**
* 对 URL 进行安全验证
* 检查是否采用禁止的协议,或是否符合配置的白名单规则
* @param url 待验证的 URL
* @return 如果 URL 符合安全策略则返回 true,否则返回 false
*/
private boolean validateUrlSecurity(String url) {
try {
Uri uri = Uri.parse(url);
// 检查协议是否被禁止
String scheme = uri.getScheme();
if (scheme != null) {
for (int i = 0; i < mSecurityConfig.mForbiddenSchemes.size(); i++) {
if (scheme.equals(mSecurityConfig.mForbiddenSchemes.get(i))) {
return false;
}
}
}
// 如果设置了白名单,URL 必须匹配其中至少一个规则
if (!mSecurityConfig.mUrlWhitelist.isEmpty()) {
for (int i = 0; i < mSecurityConfig.mUrlWhitelist.size(); i++) {
Pattern pattern = mSecurityConfig.mUrlWhitelist.get(i);
if (pattern.matcher(url).matches()) {
return true;
}
}
return false; // 未匹配白名单
}
return true;
} catch (Exception e) {
return false;
}
}
/**
* 重载 loadUrl 方法,加载之前进行安全策略检测
*/
@Override
public void loadUrl(String url) {
if (validateUrlSecurity(url)) {
super.loadUrl(url);
} else {
handleSecurityViolation(url);
}
}
@Override
public void loadUrl(String url, java.util.Map<String, String> additionalHttpHeaders) {
if (validateUrlSecurity(url)) {
super.loadUrl(url, additionalHttpHeaders);
} else {
handleSecurityViolation(url);
}
}
/**
* 当检测到不安全的 URL 请求时,展示安全提示对话框
*/
private void handleSecurityViolation(String url) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("安全警告")
.setMessage("尝试访问不安全资源:" + url)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create().show();
}
// ========== 下载管理 ==========
/**
* 下载文件时的处理逻辑。实际项目中建议接入系统 DownloadManager,注意运行时权限。
*/
private void handleDownload(String url, String userAgent, String contentDisposition,
String mimeType, long contentLength) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("下载提示")
.setMessage("是否下载文件?\n" + url)
.setNegativeButton("取消", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setPositiveButton("下载", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
// 此处实现下载逻辑,例如调用系统 DownloadManager
dialog.dismiss();
}
})
.create().show();
}
// ========== 全屏视频支持 ==========
/**
* 重写 setWebChromeClient 方法,注入自定义的 WebChromeClient
* 用于处理全屏视频的进入与退出
*/
@Override
public void setWebChromeClient(WebChromeClient client) {
// 无论外部如何设置,我们强制使用内部 CustomWebChromeClient
super.setWebChromeClient(new CustomWebChromeClient());
}
/**
* 自定义 WebChromeClient,用于全屏视频、SSL 错误处理等
*/
private class CustomWebChromeClient extends WebChromeClient {
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if (mFullScreenHandler != null) {
mFullScreenHandler.enterFullScreen(EnhancedWebView.this, view, callback);
}
}
@Override
public void onHideCustomView() {
if (mFullScreenHandler != null) {
mFullScreenHandler.exitFullScreen();
}
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// 如果允许自签名证书,则放行;否则取消请求
if (!mSecurityConfig.mAllowSelfSignedCerts) {
handler.cancel();
} else {
// 实际开发中建议显示提示对话框,让用户决定
handler.proceed();
}
}
}
// ========== 生命周期处理 ==========
/**
* 请在 Activity 的 onResume 中调用此方法,以恢复 WebView 内部定时器等
*/
public void onResumeWebView() {
resumeTimers();
if (mFullScreenHandler != null) {
mFullScreenHandler.onResume();
}
}
/**
* 请在 Activity 的 onPause 中调用此方法,暂停 WebView 的状态
*/
public void onPauseWebView() {
pauseTimers();
if (mFullScreenHandler != null) {
mFullScreenHandler.onPause();
}
}
/**
* 释放 WebView 的资源,防止内存泄漏
*/
@Override
public void destroy() {
removeAllViews();
clearHistory();
clearCache(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
super.destroy();
} else {
try {
Method method = WebView.class.getDeclaredMethod("destroy");
method.setAccessible(true);
method.invoke(this, (Object[]) null);
} catch (Exception e) {
super.destroy();
}
}
}
// ========== 工具方法 ==========
/**
* 获取当前进程名称
* @param context 上下文
* @return 当前进程名称,若获取失败返回空字符串
*/
private static String getProcessName(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
if (processes != null) {
int pid = android.os.Process.myPid();
for (int i = 0; i < processes.size(); i++) {
ActivityManager.RunningAppProcessInfo info = processes.get(i);
if (info.pid == pid) {
return info.processName;
}
}
}
return "";
}
// ========== Builder 链式配置 ==========
public static class Builder {
private Context mContext;
private SecurityConfig mSecurityConfig = new SecurityConfig();
public Builder(Context context) {
mContext = context.getApplicationContext();
}
/**
* 添加 URL 白名单规则(正则表达式)
*/
public Builder addUrlWhitelist(String regex) {
mSecurityConfig.addUrlWhitelist(regex);
return this;
}
/**
* 设置是否允许自签名证书(仅建议开发阶段测试)
*/
public Builder setAllowSelfSignedCerts(boolean allow) {
mSecurityConfig.mAllowSelfSignedCerts = allow;
return this;
}
/**
* 构建 EnhancedWebView 实例
*/
public EnhancedWebView build() {
EnhancedWebView webView = new EnhancedWebView(mContext);
webView.mSecurityConfig = this.mSecurityConfig;
return webView;
}
}
// ========== 安全配置内部类 ==========
/**
* SecurityConfig 用于配置 URL 白名单、禁止协议、以及是否允许自签名证书
*/
public static class SecurityConfig {
private List<Pattern> mUrlWhitelist;
private List<String> mForbiddenSchemes;
private boolean mAllowSelfSignedCerts;
public SecurityConfig() {
mUrlWhitelist = new ArrayList<Pattern>();
mForbiddenSchemes = new ArrayList<String>();
// 默认禁止 file 与 tel 协议
mForbiddenSchemes.add("file");
mForbiddenSchemes.add("tel");
mAllowSelfSignedCerts = false;
}
/**
* 添加白名单规则(正则表达式字符串)
*/
public SecurityConfig addUrlWhitelist(String regex) {
try {
Pattern pattern = Pattern.compile(regex);
mUrlWhitelist.add(pattern);
} catch (Exception e) {
// 如果正则表达式错误,则忽略该规则
}
return this;
}
/**
* 设置禁止协议列表
*/
public SecurityConfig setForbiddenSchemes(List<String> schemes) {
if (schemes != null) {
mForbiddenSchemes = schemes;
}
return this;
}
}
// ========== JavaScript 桥接 ==========
/**
* 添加 JavaScript 接口,以便页面调用
* 注意:请确保接口安全,避免暴露敏感接口!
* @param bridge 接口对象,需在方法上添加 @JavascriptInterface 注解
* @param name 在 JavaScript 中使用的名称
*/
public void addJavascriptBridge(Object bridge, String name) {
super.addJavascriptInterface(bridge, name);
}
}
FullScreenHandler.java
/**
* FullScreenHandler.java
*
* 该类用于处理 WebView 全屏视频播放模式,
* 通过接管 Activity 的 DecorView 添加/移除全屏自定义视图。
*
* 使用说明:
* 1. 由 EnhancedWebView 在初始化时传入 Activity 对象。
* 2. 在 WebChromeClient 的 onShowCustomView() 和 onHideCustomView() 回调中调用本类的方法。
* 3. 确保 Activity 的屏幕方向及系统 UI 状态在全屏与正常模式间切换。
*/
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
public class FullScreenHandler {
private Activity mActivity;
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private int mOriginalSystemUiVisibility;
private int mOriginalOrientation;
/**
* 构造函数,传入当前 Activity 对象
* @param activity 当前 Activity
*/
public FullScreenHandler(Activity activity) {
mActivity = activity;
}
/**
* 进入全屏模式
* @param webView 当前使用的 WebView 对象(用于退出时恢复显示)
* @param customView 自定义的全屏视图(例如视频播放界面)
* @param callback 全屏视图回调接口,当退出全屏时调用
*/
public void enterFullScreen(View webView, View customView, WebChromeClient.CustomViewCallback callback) {
// 保存当前系统 UI 状态与屏幕方向
mOriginalSystemUiVisibility = mActivity.getWindow().getDecorView().getSystemUiVisibility();
mOriginalOrientation = mActivity.getRequestedOrientation();
// 隐藏 WebView
webView.setVisibility(View.GONE);
// 添加全屏视图到 Activity 的 DecorView
ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
decorView.addView(customView, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mCustomView = customView;
mCustomViewCallback = callback;
// 设置全屏标志(隐藏状态栏、导航栏)
mActivity.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
/**
* 退出全屏模式,移除全屏视图并恢复之前的 UI 状态
*/
public void exitFullScreen() {
if (mCustomView == null) {
return;
}
// 从 DecorView 中移除全屏视图
ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
decorView.removeView(mCustomView);
mCustomView = null;
// 恢复之前的系统 UI 状态与屏幕方向
mActivity.getWindow().getDecorView().setSystemUiVisibility(mOriginalSystemUiVisibility);
mActivity.setRequestedOrientation(mOriginalOrientation);
// 通知 WebView 全屏视图已被隐藏
if (mCustomViewCallback != null) {
mCustomViewCallback.onCustomViewHidden();
}
}
/**
* Activity onResume 时调用(扩展接口,如需恢复状态可添加代码)
*/
public void onResume() {
// 可扩展代码,如重置全屏 UI 状态
}
/**
* Activity onPause 时调用(扩展接口,如需暂停视频播放可添加代码)
*/
public void onPause() {
// 可扩展代码
}
}
使用示例
在 Activity 中使用上述组件示例代码如下:
// 在 Activity 的 onCreate 中构建 EnhancedWebView 实例
EnhancedWebView webView = new EnhancedWebView.Builder(this)
.addUrlWhitelist("^https://(.*\\.)?example\\.com/")
.setAllowSelfSignedCerts(false) // 生产环境建议设为 false
.build();
// 将 webView 添加到布局中,例如:
setContentView(webView);
webView.loadUrl("https://www.example.com");
// 在 Activity onResume 中调用
@Override
protected void onResume() {
super.onResume();
webView.onResumeWebView();
}
// 在 Activity onPause 中调用
@Override
protected void onPause() {
webView.onPauseWebView();
super.onPause();
}
// 在 Activity onDestroy 中调用
@Override
protected void onDestroy() {
webView.destroy();
super.onDestroy();
}