Webview在我們平時(shí)開發(fā)中十分常用竹揍,幾乎項(xiàng)目里面都會(huì)有嵌套網(wǎng)頁(yè)呕寝。但是Webview可不是像我們平時(shí)loadUrl()就完了达舒,它還有很多屬性方法我們平時(shí)可能就沒(méi)有開發(fā)出來(lái)只嚣。
最基本功能使用:
//加載一個(gè)遠(yuǎn)程網(wǎng)頁(yè)
webView.loadUrl("https://www.baidu.com");
// 加載assets中資源
webView.loadUrl("file:///android_asset/web.html");
//加載sdcard中資源
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
-
WebSettings類有哪些屬性可以設(shè)置?
WebSettings webSettings = webView.getSettings();
//設(shè)置支持javascript
webSettings.setJavaScriptEnabled(true);
//支持插件
webSettings.setPluginsEnabled(true);
//設(shè)置自適應(yīng)屏幕灿渴,兩者合用
webSettings.setUseWideViewPort(true); //將圖片調(diào)整到適合webview的大小
webSettings.setLoadWithOverviewMode(true); // 縮放至屏幕的大小
webSettings.setTextZoom(100);//字體百分比洛波,替代原API:setTextSize
//縮放操作
webSettings.setSupportZoom(true); //支持縮放,默認(rèn)為true骚露。是下面那個(gè)的前提蹬挤。
webSettings.setBuiltInZoomControls(true); //設(shè)置內(nèi)置的縮放控件。若為false棘幸,則該WebView不可縮放
webSettings.setDisplayZoomControls(false); //隱藏屏幕中的虛擬縮放按鈕
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //開啟webview中緩存
webSettings.setAllowFileAccess(true); //設(shè)置可以訪問(wèn)文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通過(guò)JS打開新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自動(dòng)加載圖片
webSettings.setBlockNetworkImage(true); //阻塞圖片加載
webSettings.setDefaultTextEncodingName("utf-8");//設(shè)置編碼格式
//優(yōu)先使用緩存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
-
Webview屬性
webView.clearCache(true); 清除緩存
webView.clearHistory()焰扳; 清除歷史記錄
webView.reload(); 重新加載
Https 加載 Http 混合模式
當(dāng) WebView 加載 https 的地址中有 http 的地址時(shí)(比如 https 地址含有 http 的圖片) WebView 無(wú)法加載 http 的資源,可使用setMixedContentMode方法設(shè)置误续。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
-
頁(yè)面監(jiān)聽與攔截
1.WebViewClient
WebViewClient主要用來(lái)處理請(qǐng)求和加載頁(yè)面監(jiān)聽吨悍。示例如下:
public class MyWebViewClient extends WebViewClient {
private Context context;
public MyWebViewClient(Context context) {
this.context = context;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//用戶可選擇是否攔截加載 URL
//如果返回值為 true,攔截 WebView 加載 url蹋嵌,false 允許 WebView 加載 url
//所以在實(shí)際項(xiàng)目中育瓜,可以在這里處理自定義的一些跳轉(zhuǎn)協(xié)議。
if (url.startsWith("tel:")) { //比如點(diǎn)擊到已經(jīng)定義好的 url 協(xié)議 電話號(hào)碼 tel:// 時(shí)栽烂,那么可以在這里做攔截躏仇,跳轉(zhuǎn)到系統(tǒng)撥號(hào)界面。
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//開始載入頁(yè)面調(diào)用的
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
//在頁(yè)面加載結(jié)束時(shí)調(diào)用
super.onPageFinished(view, url);
}
@Override
public void onLoadResource(WebView view, String url) {
//在加載頁(yè)面資源時(shí)會(huì)調(diào)用愕鼓,每一個(gè)資源(比如圖片)的加載都會(huì)調(diào)用一次钙态。
super.onLoadResource(view, url);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
//App里面使用webview控件的時(shí)候遇到了諸如404這類的錯(cuò)誤的時(shí)候,若也顯示瀏覽器里面的那種錯(cuò)誤提示頁(yè)面就顯得很丑陋了菇晃,那么這個(gè)時(shí)候我們的app就需要加載一個(gè)本地的錯(cuò)誤提示頁(yè)面
// view.loadUrl("file:///android_assets/error_handle.html");
super.onReceivedError(view, request, error);
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
//響應(yīng)服務(wù)器返回的 Http 錯(cuò)誤册倒,當(dāng)一個(gè) http 正常響應(yīng)時(shí),狀態(tài)碼會(huì)是 200磺送,當(dāng)狀態(tài)碼異常時(shí)可以用該方法監(jiān)聽驻子。
int code = errorResponse.getStatusCode();
switch (code) {
case 400:
// 重新登錄
break;
}
super.onReceivedHttpError(view, request, errorResponse);
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
//SSL 證書驗(yàn)證錯(cuò)誤
super.onReceivedSslError(view, handler, error);
}
}
-
WebChromeClient
WebChromeClient主要輔助WebView處理Javascript的對(duì)話框灿意、網(wǎng)站圖標(biāo)、網(wǎng)站標(biāo)題崇呵、加載進(jìn)度等缤剧。
public class MyWebChromeClient extends WebChromeClient {
private Context context;
public MyWebChromeClient(Context context) {
this.context = context;
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
//這個(gè)方法會(huì)在網(wǎng)頁(yè)加載過(guò)程中多次觸發(fā),當(dāng) newProgress = 100 時(shí)域慷,可以認(rèn)為網(wǎng)頁(yè)加載完成荒辕。這個(gè)方法比 onPageFinished 更為準(zhǔn)確,一般用來(lái)實(shí)現(xiàn)自定義進(jìn)度條加載犹褒。
Log.i("minfo", "當(dāng)前加載進(jìn)度: " + newProgress);
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
//顯示頁(yè)面標(biāo)題 title為該頁(yè)面標(biāo)題
Log.i("minfo", "頁(yè)面title: " + title);
super.onReceivedTitle(view, title);
}
/**
* 頁(yè)面提示框
* @param message alert 彈出窗口中的提示信息(提示或警告信息對(duì)話框抵窒,僅一個(gè)確認(rèn)按鈕)
* @param result 向網(wǎng)頁(yè)中的 Javascript 代碼反饋本次操作結(jié)果(result.confirm 代表點(diǎn)擊了確定按鈕,result.cancel 代表點(diǎn)擊了取消按鈕)
*/
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//頁(yè)面提示框 onJsAlert()
new AlertDialog.Builder(context)
.setTitle("JsAlert")
.setMessage(message)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setCancelable(false)
.show();
return super.onJsAlert(view, url, message, result);
}
/**
* 頁(yè)面選擇框
* @param message confirm 彈出窗口中的提示信息(確認(rèn)對(duì)話框叠骑,有確認(rèn)李皇、取消兩個(gè)按鈕)
* @param result 向網(wǎng)頁(yè)中的 Javascript 代碼反饋本次操作結(jié)果(result.confirm 代表點(diǎn)擊了確定按鈕,result.cancel 代表點(diǎn)擊了取消按鈕)
*/
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
}
-
Webview內(nèi)存泄漏解決
1宙枷、在使用webview時(shí)不用xml布局中引用掉房,在代碼中創(chuàng)建并用viewgroup調(diào)用addView()的方式。
2慰丛、在使用Activity的onDestroy方法中卓囚,讓webview加載空,移除webview璧帝,webview銷毀并置null捍岳。
@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
-
Webview設(shè)置緩存機(jī)制
WebSettings settings = webView.getSettings();
//設(shè)置緩存路徑
String cacheDirPath = getFilesDir().getAbsolutePath()+"cache/";
settings.setAppCachePath(cacheDirPath);
//設(shè)置緩存大小
settings.setAppCacheMaxSize(20*1024*1024);
//開啟AppCache存儲(chǔ)機(jī)制
settings.setAppCacheEnabled(true);
-
啟動(dòng)指定瀏覽器
在Android程序中我們可以通過(guò)發(fā)送顯式Intent來(lái)啟動(dòng)指定的瀏覽器。例如睬隶,啟動(dòng)手機(jī)自帶瀏覽器。
Intent intent =newIntent();
intent.setAction("android.intent.action.VIEW");
Uri content_url =Uri.parse("https://www.baidu.com");
intent.setData(content_url);
intent.setClassName("com.android.browser","com.android.browser.BrowserActivity");
startActivity(intent);
啟動(dòng)其他瀏覽器页徐,只要修改以intent.setClassName(package,activity)中2個(gè)參數(shù)苏潜,對(duì)應(yīng)的應(yīng)用瀏覽器程序packagename和要啟動(dòng)的activity即可啟動(dòng)其他瀏覽器。
uc瀏覽器 | com.uc.browser | com.uc.browser.ActivityUpdate |
---|---|---|
opera瀏覽器 | com.opera.mini.android | com.opera.mini.android.Browser |
qq瀏覽器 | com.tencent.mtt | com.tencent.mtt.MainActivity |
Webview基本功能總結(jié)如上变勇,最后恤左,還有其他功能Webview與Android交互。
問(wèn)題:
-
WebView 的 addJavascriptInterface()的作用
webView.addJavascriptInterface(this, "android")
-定義一個(gè)與 JS 對(duì)象映射關(guān)系的 Android 類:AndroidtoJs:
1.定義 JS 需要調(diào)用的方法搀绣,被 JS 調(diào)用的方法必須加入@JavascriptInterface
注解飞袋。
2.通過(guò) addJavascriptInterface()將 Java 對(duì)象映射到 JS 對(duì)象。
-
前進(jìn) / 后退網(wǎng)頁(yè)
//是否可以后退
Webview.canGoBack()
//后退網(wǎng)頁(yè)
Webview.goBack()
//是否可以前進(jìn)
Webview.canGoForward()
//前進(jìn)網(wǎng)頁(yè)
Webview.goForward()
//以當(dāng)前頁(yè)面為準(zhǔn)链患,前進(jìn)或者后退到歷史記錄中指定的steps頁(yè)面數(shù)
//如果steps為負(fù)數(shù)則為后退巧鸭,正數(shù)則為前進(jìn)
Webview.goBackOrForward(int steps)
-
按系統(tǒng)back鍵怎么控制網(wǎng)頁(yè)后退而不是直接關(guān)閉webview?
在當(dāng)前展示W(wǎng)ebview的Activity中處理Back事件麻捻,監(jiān)聽系統(tǒng)back鍵點(diǎn)擊纲仍,在其中調(diào)用webview.goBack()方法呀袱。
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
webview cookie管理
什么是cookie:最簡(jiǎn)單理解就是由http衍生出來(lái)的一種特殊的瀏覽器的緩存,特點(diǎn)是具有時(shí)效性郑叠、賬戶相關(guān)性夜赵、存儲(chǔ)在客戶端等。Android 中Cookie的管理相關(guān):說(shuō)到cookie的管理乡革,其實(shí)本質(zhì)上就是數(shù)據(jù)的存儲(chǔ)問(wèn)題寇僧。在早期的cookie是由CookieSyncManager進(jìn)行管理的,但是在API 21 之后CookieSyncManager被拋棄了沸版,換成了CookieManager來(lái)進(jìn)行管理嘁傀。
Android中Cookie的存儲(chǔ):項(xiàng)目中使用 WebView 其實(shí)會(huì)自動(dòng)將 Cookie 保存在本地?cái)?shù)據(jù)庫(kù)中。保存是路徑為 data/data/package_name/app_WebView/Cookies 雖然不是 .db 結(jié)尾的推穷,實(shí)際就是一個(gè) .db 文件
webview有一個(gè)CookieManager這個(gè)類心包,他是專門管理cookie的,這個(gè)類可以設(shè)置一個(gè)或多個(gè)cookie馒铃,而且當(dāng)你在里面設(shè)置好cookie以后接口會(huì)自動(dòng)根據(jù)你設(shè)置時(shí)的url來(lái)使用蟹腾。
public class CookieHandle {
private CookieManager cookieManager;
public void setCookies(Activity context, String url) {
HttpCookie cookie = new HttpCookie("name", "value");
cookie.setDomain("baidu.com"); //設(shè)置域名
cookie.setPath("files"); //設(shè)置域名下的path
cookie.setMaxAge(10000); //設(shè)置過(guò)期時(shí)間
// 調(diào)用CookieManager 的方法設(shè)置cookie
// 具有相同的 host 和 path 和 name 的任何現(xiàn)有的 Cookie 將會(huì)被替換為新的 Cookie
CookieManager.getInstance().setCookie(url, cookie.toString());
}
/**
* 刪除cookie操作:底層實(shí)現(xiàn)是異步清除數(shù)據(jù)庫(kù)的記錄
*/
public void deleteCookie() {
CookieManager.getInstance().removeAllCookies(null);
CookieManager.getInstance().flush(); //這個(gè)flush()方法就是立即同步cookie的操作
}
/**
* 設(shè)置是否保存cookie
*/
fun setAcceptCookies(accept: Boolean) {
CookieManager.getInstance().setAcceptCookie(accept)
}
/**
* 清理cookie
*/
fun clearCookie() {
CookieManager.getInstance().removeAllCookie()
}
/**
* 獲取某個(gè)網(wǎng)站cookie
*/
fun getCookie(url: String) {
CookieManager.getInstance().getCookie(url)
}
/**
* 同步cookie
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun synchCookie() {
CookieManager.getInstance().flush()
}
/**
* 清理webview網(wǎng)站賬號(hào)密碼
*/
@RequiresApi(Build.VERSION_CODES.ECLAIR_MR1)
fun clearPasswords(context: Context) {
var db = WebViewDatabase.getInstance(context)
db.clearUsernamePassword()
db.clearHttpAuthUsernamePassword()
}
@RequiresApi(Build.VERSION_CODES.ECLAIR_MR1)
fun clearDataBase() {
WebStorage.getInstance().deleteAllData()
}
fun clearCache() {
WebIconDatabase.getInstance().removeAllIcons()
}
/**
* 清理緩存
*/
fun clearAllData(context: Context) {
clearCookie()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR_MR1) {
clearPasswords(context)
clearDataBase()
}
clearCache()
}
}
注:只有cookie的domain和path與請(qǐng)求的URL匹配才會(huì)發(fā)送這個(gè)cookie。
WebView調(diào)用本地相冊(cè)
1.重寫方法(WebChromeClient類中的onShowFileChooser)
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
mUploadCallbackAboveL = filePathCallback;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
context.startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
return true;
}
2.在調(diào)起的activity中重寫onActivityResult方法獲取data中選擇的本地文件区宇。
參考:
https://juejin.cn/post/7152861867973705758
http://www.reibang.com/p/0d1bd9443caa