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();}// 全屏视频支持@Overridepublic 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) {// 初始化全屏处理相关参数}@Overridepublic void onShowCustomView(View view, CustomViewCallback callback) {// 实现全屏视频逻辑if (mCustomView != null) {onHideCustomView();return;}mCustomView = view;mCustomViewCallback = callback;// 将自定义视图添加到DecorView}@Overridepublic 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() {@Overridepublic 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 方法,加载之前进行安全策略检测*/@Overridepublic void loadUrl(String url) {if (validateUrlSecurity(url)) {super.loadUrl(url);} else {handleSecurityViolation(url);}}@Overridepublic 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() {@Overridepublic 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(){@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}}).setPositiveButton("下载", new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {// 此处实现下载逻辑,例如调用系统 DownloadManagerdialog.dismiss();}}).create().show();}// ========== 全屏视频支持 ==========/*** 重写 setWebChromeClient 方法,注入自定义的 WebChromeClient* 用于处理全屏视频的进入与退出*/@Overridepublic void setWebChromeClient(WebChromeClient client) {// 无论外部如何设置,我们强制使用内部 CustomWebChromeClientsuper.setWebChromeClient(new CustomWebChromeClient());}/*** 自定义 WebChromeClient,用于全屏视频、SSL 错误处理等*/private class CustomWebChromeClient extends WebChromeClient {@Overridepublic void onShowCustomView(View view, CustomViewCallback callback) {if (mFullScreenHandler != null) {mFullScreenHandler.enterFullScreen(EnhancedWebView.this, view, callback);}}@Overridepublic void onHideCustomView() {if (mFullScreenHandler != null) {mFullScreenHandler.exitFullScreen();}}@Overridepublic 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 的资源,防止内存泄漏*/@Overridepublic 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();// 隐藏 WebViewwebView.setVisibility(View.GONE);// 添加全屏视图到 Activity 的 DecorViewViewGroup 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();
}