[Android] WebView without HTTPS
在開發 Android 程式的時候,有需要用到 WebView 直接連結特定的網頁,但是很多時候網頁並沒有 HTTP SSL 的保護, 基本上 Android 9 以後 WebView 在顯示沒有 SSL 的網頁會直接顯示設成 Disable,詳情可以參考。本篇想要紀錄如何利用 Android WebView 連結 without HTTPS 的網站。
Note: The guidance in this section applies only to apps that target Android 8.1 (API level 27) or lower. Starting with Android 9 (API level 28), cleartext support is disabled by default.
嘗試一:增加 network_security_config.xml 到 res/xml 裡面
我們首先嘗試參考連結的解決方法,在 res/xml 裡面增加一個 network_security_config.xml 檔案如以下的內容,在 <domain includeSubdomains=”true”> </domain> 中間加入可以接受 ClearTextTraffic 的 URL。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
// Add host of your download URL in below line.
// ie. if url is "https://www.google.com/search?source=...."
// then just add "www.google.com"
<domain includeSubdomains="true">www.smarterasp.net</domain>
</domain-config>
</network-security-config>
然後在 AndroidManifest.xml 裡面增加以下的設定:
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...>
</application>
但是測試的結果是這個方法並不有效,之後嘗試方法二。其他參考資訊:連結
嘗試二:改動 WebViewClient 增加 onReceivedSslError()
在設定 webView 的時候需要設定 WebViewClient,這個方法是重新調整當 SslError 時的反應方法,在 Android 9.0 之後 onReceivedSslError 的預設方法是 handler.cancel() 此會將 WebView 變成空白頁,將 handler.cancel() 改成 handler.proceed() 之後就可以成功顯示沒有 SSL 的網頁。
webView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
handler.proceed();
}
});
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
以上的方法雖然可以解決 SSL 的問題,但是在發佈到 Google Play Store 的時候發生以下錯誤訊息,Google 方面提供相關資訊連結:https://support.google.com/faqs/answer/7071387
我們將 onReceivedSslError 近一步改進如以下,還是無法通過 Google Play 審核:
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
if (error.getPrimaryError() == SslError.SSL_IDMISMATCH ){
handler.proceed();
} else {
handler.cancel();
}
}
我們將 SslError 錯誤的情況限制在 SSL_IDMISMATCH 則可以被接受,這邊還是需要看不同的需求去改動。其他的錯誤情況可以參考以下:
public static final int SSL_NOTYETVALID = 0;
public static final int SSL_EXPIRED = 1;
public static final int SSL_IDMISMATCH = 2;
public static final int SSL_UNTRUSTED = 3;
public static final int SSL_DATE_INVALID = 4;
public static final int SSL_INVALID = 5;
@Deprecated
public static final int SSL_MAX_ERROR = 6;
最後解決方法:
在搜尋其他的解決方法之後,找到以下的方法可以通過 Google 的審核,但是並不是完美的解決方法,如果 WebView 連結沒有 SSL 的網站的話,Google 還是希望可以詢問用戶的意願來近一步保護用戶!
SslCertificate sslCertificate = error.getCertificate();
final AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setTitle("Website Loading, Continue?");
builder.setPositiveButton(R.string.NSLS_YES, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handler.proceed();
}
});
builder.setNegativeButton(R.string.NSLS_CANCEL, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handler.cancel();
}
});
final AlertDialog dialog = builder.create();
dialog.show();
其他參考連結:
https://codertw.com/android-%E9%96%8B%E7%99%BC/334517/
https://lipeng1667.github.io/2017/01/03/android-webview-https-and-taobaoke/
https://stackoverflow.com/questions/58003523/how-can-i-fix-this-android-webview-problem