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();
}