使用 WebView2 控件時,如果你嘗試從 WebView2 加載的頁面訪問本地靜態 HTML 資源,并且遇到了跨域資源共享(CORS)問題,這通常是因為 WebView2 遵循同源策略,這意味著默認情況下,它不允許從一個源加載的頁面訪問另一個源的資源。
解決此問題的方法取決于你的具體場景和需求。下面是一些可能的解決方案:
對于本地開發或測試,你可以在 WebView2 控件上設置 allow-local-file-access 屬性為 true,這將允許 WebView2 加載的頁面訪問本地文件系統上的資源。
csharpawait webView2.CoreWebView2.Settings.PutBoolean("allowLocalFileAccess", true);
請注意,這只應該在受信任的環境中使用,因為啟用本地文件訪問可能會引入安全風險。
如果你正在嘗試從 WebView2 加載的頁面訪問本地服務器上托管的資源,并且該服務器支持 CORS,你可以配置服務器以發送適當的 CORS 響應頭。這允許跨源請求。
例如,在 ASP.NET Core 中,你可以使用 CORS 中間件來配置 CORS 策略。
csharppublic void ConfigureServices(IServiceCollection services)
{
services.AddCors(options=>
{
options.AddPolicy("MyCorsPolicy", builder=>
{
builder.WithOrigins("http://example.com", "http://www.example.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// ... 其他服務配置 ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ... 其他中間件配置 ...
app.UseCors("MyCorsPolicy");
// ... 其他中間件配置 ...
}
如果你無法修改資源服務器的 CORS 配置,你可以設置一個代理服務器來繞過 CORS 限制。代理服務器會接收來自 WebView2 的請求,然后轉發到目標資源服務器,并將響應返回給 WebView2。代理服務器可以設置適當的 CORS 響應頭來允許跨源請求。
如果可能的話,將你的靜態 HTML 資源和 WebView2 控件部署到相同的源(即相同的域名、端口和協議)。這樣,同源策略就不會阻止它們之間的交互。
對于本地文件,你可以使用一個簡單的 Web 服務器(如 IIS Express、Kestrel 或其他任何服務器)來托管這些文件,并通過 HTTP 訪問它們,而不是直接通過文件系統。這樣,你就可以通過配置服務器來處理 CORS 請求。
者:Mino
原因:html代碼下載到WebView后,webkit開始解析網頁各個節點,發現有外部樣式文件或者外部腳本文件時,會異步發起網絡請求下載文件,但如果在這之前也有解析到image節點,那勢必也會發起網絡請求下載相應的圖片。在網絡情況較差的情況下,過多的網絡請求就會造成帶寬緊張,影響到css或js文件加載完成的時間,造成頁面空白loading過久。
解決方法:告訴WebView先不要自動加載圖片,等頁面finish后再發起圖片加載。
//設置是否開啟密碼保存功能,不建議開啟,默認已經做了處理,存在盜取密碼的危險
WebView.setSavePassword(false);
原因:4.0以上的系統我們開啟硬件加速后,WebView渲染頁面更加快速,拖動也更加順滑。但有個副作用就是,當WebView視圖被整體遮住一塊,然后突然恢復時(比如使用SlideMenu將WebView從側邊滑出來時),這個過渡期會出現白塊同時界面閃爍。
解決方法:是在過渡期前將WebView的硬件加速臨時關閉,過渡期后再開啟。
/**
* 請求網絡出現error
* @param view view
* @param errorCode 錯誤
* @param description description
* @param failingUrl 失敗鏈接
*/
@Override
public void onReceivedError(WebView view, int errorCode, String description, String
failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
if (errorCode==404) {
//用javascript隱藏系統定義的404頁面信息
String data="Page NO FOUND!";
view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\"");
} else {
if (webListener!=null){
webListener.showErrorView();
}
}
}
// 向主機應用程序報告Web資源加載錯誤。這些錯誤通常表明無法連接到服務器。
// 值得注意的是,不同的是過時的版本的回調,新的版本將被稱為任何資源(iframe,圖像等)
// 不僅為主頁。因此,建議在回調過程中執行最低要求的工作。
// 6.0 之后
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.M) {
X5WebUtils.log("服務器異常"+error.getDescription().toString());
}
//ToastUtils.showToast("服務器異常6.0之后");
//當加載錯誤時,就讓它加載本地錯誤網頁文件
//mWebView.loadUrl("file:///android_asset/errorpage/error.html");
if (webListener!=null){
webListener.showErrorView();
}
}
/**
* 這個方法主要是監聽標題變化操作的
* @param view view
* @param title 標題
*/
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (title.contains("404") || title.contains("網頁無法打開")){
if (webListener!=null){
webListener.showErrorView();
}
} else {
// 設置title
}
}
原因:WebView.loadUrl("url") 不會立馬就回調 onPageStarted 或者 onProgressChanged 因為在這一時間段,WebView 有可能在初始化內核,也有可能在與服務器建立連接,這個時間段容易出現白屏,白屏用戶體驗是很糟糕的。
解決方法:提前顯示進度條雖然不是提升性能 , 但是對用戶體驗來說也是很重要的一點。
/**
* 在加載資源時通知主機應用程序發生SSL錯誤
* 作用:處理https請求
* @param view view
* @param handler handler
* @param error error
*/
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
if (error!=null){
String url=error.getUrl();
}
//https忽略證書問題
if (handler!=null){
//表示等待證書響應
handler.proceed();
// handler.cancel(); //表示掛起連接,為默認方式
// handler.handleMessage(null); //可做其他處理
}
}
原因:WebView 默認開啟密碼保存功能 mWebView.setSavePassword(true),如果該功能未關閉,在用戶輸入密碼時,會彈出提示框,詢問用戶是否保存密碼,如果選擇”是”,密碼會被明文保到 /data/data/com.package.name/databases/webview.db 中,這樣就有被盜取密碼的危險。
解決方法:通過 WebSettings.setSavePassword(false) 關閉密碼保存提醒功能。
@Override
protected void onDestroy() {
try {
//有音頻播放的web頁面的銷毀邏輯
//在關閉了Activity時,如果Webview的音樂或視頻,還在播放。就必須銷毀Webview
//但是注意:webview調用destory時,webview仍綁定在Activity上
//這是由于自定義webview構建時傳入了該Activity的context對象
//因此需要先從父容器中移除webview,然后再銷毀webview:
if (webView !=null) {
ViewGroup parent=(ViewGroup) webView.getParent();
if (parent !=null) {
parent.removeView(webView);
}
webView.removeAllViews();
webView.destroy();
webView=null;
}
} catch (Exception e) {
}
super.onDestroy();
}
原因:當WebView加載頁面出錯時(一般為404 NOT FOUND,Android WebView會默認顯示一個出錯界面。當WebView加載出錯時,會在WebViewClient實例中的onReceivedError(),還有onReceivedTitle方法接收到錯誤。
解決方法:自定義錯誤頁面樣式。
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
String host=Uri.parse(url).getHost();
if (!BuildConfig.IS_DEBUG) {
if (Arrays.binarySearch(domainList, host) < 0) {
//不在白名單內,非法網址,這個時候給用戶強烈而明顯的提示
} else {
//合法網址
}
}
}
原因:webView加載一些別人的url時候,有時候會發生證書認證錯誤的情況。
解決方法:要將正常的呈現頁面給用戶,我們需要忽略證書錯誤,需要調用WebViewClient類的onReceivedSslError方法,調用handler.proceed()來忽略該證書錯誤。
//在onResume里面設置setJavaScriptEnabled(true)。
@Override
protected void onResume() {
super.onResume();
if (mWebView !=null) {
mWebView.getSettings().setJavaScriptEnabled(true);
}
}
//在onStop里面設置setJavaScriptEnabled(false);
@Override
protected void onStop() {
super.onStop();
if (mWebView !=null) {
mWebView.getSettings().setJavaScriptEnabled(false)
}
}
原因:WebView頁面中播放了音頻,退出Activity后音頻仍然在播放。
解決方法:需要在Activity的onDestory()中從父容器中移除WebView。
@Override
protected void onDestroy() {
try {
//有音頻播放的web頁面的銷毀邏輯
//在關閉了Activity時,如果Webview的音樂或視頻,還在播放。就必須銷毀Webview
//但是注意:webview調用destory時,webview仍綁定在Activity上
//這是由于自定義webview構建時傳入了該Activity的context對象
//因此需要先從父容器中移除webview,然后再銷毀webview:
if (webView !=null) {
ViewGroup parent=(ViewGroup) webView.getParent();
if (parent !=null) {
parent.removeView(webView);
}
webView.removeAllViews();
webView.destroy();
webView=null;
}
} catch (Exception e) {
}
super.onDestroy();
}
原因:客戶端內的WebView都是可以通過客戶端的某個schema打開的,而要打開頁面的URL很多都并不寫在客戶端內,而是可以由URL中的參數傳遞過去的。上面4.0.5 使用scheme協議打開鏈接風險已經說明了scheme使用的危險性。
解決方法:設置運行訪問的白名單,或者當用戶打開外部鏈接前給用戶強烈而明顯的提示。設置白名單操作其實和過濾廣告是一個意思,這里你可以放一些合法的網址允許訪問。
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
String host=Uri.parse(url).getHost();
if (!BuildConfig.IS_DEBUG) {
if (Arrays.binarySearch(domainList, host) < 0) {
//不在白名單內,非法網址,這個時候給用戶強烈而明顯的提示
} else {
//合法網址
}
}
}
原因:有些手機你如果webView加載的html里,有一些js一直在執行比如動畫之類的東西,如果此刻webView 掛在了后臺這些資源是不會被釋放用戶也無法感知。導致一直占有cpu 耗電特別快。
解決方法:WebView在后臺的時候,會調用onStop方法,即此時關閉js交互,回到前臺調用onResume再開啟js交互。
//在onResume里面設置setJavaScriptEnabled(true)。
@Override
protected void onResume() {
super.onResume();
if (mWebView !=null) {
mWebView.getSettings().setJavaScriptEnabled(true);
}
}
//在onStop里面設置setJavaScriptEnabled(false);
@Override
protected void onStop() {
super.onStop();
if (mWebView !=null) {
mWebView.getSettings().setJavaScriptEnabled(false)
}
}
原因:WebView從Lollipop(5.0)開始webView默認不允許混合模式, https當中不能加載http資源, 而開發的時候可能使用的是https的鏈接,但是鏈接中的圖片可能是http的,所以顯示圖片失敗。
解決方案:需要設置開啟。
天在調試android webview加載本地html文件時,對三種不同位置html的加載方式總結如下:
1.//打開本包內asset目錄下的index.html文件
wView.loadUrl(" file:///android_asset/index.html ");
2.//打開本地sd卡內的index.html文件
wView.loadUrl("content://com.android.htmlfileprovider/sdcard/index.html");
3.//打開指定URL的html文件
wView.loadUrl(" http://m.oschina.net");
今天就分享這一個知識點,祝大家好運!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。