WebView全面總結(jié)

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

Github代碼地址:

https://github.com/running-libo/Webview

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娃殖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子议谷,更是在濱河造成了極大的恐慌炉爆,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卧晓,死亡現(xiàn)場(chǎng)離奇詭異芬首,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)逼裆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門郁稍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人胜宇,你說(shuō)我怎么就攤上這事耀怜。” “怎么了桐愉?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵财破,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我从诲,道長(zhǎng)左痢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮抖锥,結(jié)果婚禮上亿眠,老公的妹妹穿的比我還像新娘。我一直安慰自己磅废,他們只是感情好纳像,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拯勉,像睡著了一般竟趾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宫峦,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天岔帽,我揣著相機(jī)與錄音,去河邊找鬼导绷。 笑死犀勒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妥曲。 我是一名探鬼主播贾费,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼檐盟!你這毒婦竟也來(lái)了褂萧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤葵萎,失蹤者是張志新(化名)和其女友劉穎导犹,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羡忘,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谎痢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卷雕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舶得。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爽蝴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纫骑,我是刑警寧澤蝎亚,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站先馆,受9級(jí)特大地震影響发框,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜煤墙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一梅惯、第九天 我趴在偏房一處隱蔽的房頂上張望宪拥。 院中可真熱鬧,春花似錦铣减、人聲如沸她君。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缔刹。三九已至,卻和暖如春劣针,著一層夾襖步出監(jiān)牢的瞬間校镐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工捺典, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸟廓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓襟己,卻偏偏與公主長(zhǎng)得像引谜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子稀蟋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容