Android WebView 使用匯總

最近和WebView打了不少交道,遇到許多問題抗碰,踩了許多坑。做一次總結(jié),鞏固一下和方便以后回頭查看查看

WebView常用方法

1.加載
加載一個(gè)網(wǎng)頁:
loadUrl(String url);
加載apk包中的一個(gè)html頁面
loadUrl("file:///android_asset/test.html");
加載手機(jī)本地的一個(gè)html頁面的方法:
loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");

2.前進(jìn)和后退
goBack()//后退
goForward()//前進(jìn)
goBackOrForward(intsteps) //以當(dāng)前的index為起始點(diǎn)前進(jìn)或者后退到歷史記錄中指定的steps羽莺,如果steps為負(fù)數(shù)則為后退,正數(shù)則為前進(jìn)
canGoForward()//是否可以前進(jìn)
canGoBack() //是否可以后退

3.清除緩存數(shù)據(jù):
clearCache(true);//清除網(wǎng)頁訪問留下的緩存洞豁,由于內(nèi)核緩存是全局的因此這個(gè)方法不僅僅針對(duì)webview而是針對(duì)整個(gè)應(yīng)用程序.
clearHistory()//清除當(dāng)前webview訪問的歷史記錄盐固,只會(huì)webview訪問歷史記錄里的所有記錄除了當(dāng)前訪問記錄.
clearFormData()//這個(gè)api僅僅清除自動(dòng)完成填充的表單數(shù)據(jù),并不會(huì)清除WebView存儲(chǔ)到本地的數(shù)據(jù)族跛。

4.WebView的狀態(tài):
onResume() //激活WebView為活躍狀態(tài)闰挡,能正常執(zhí)行網(wǎng)頁的響應(yīng)
onPause()//當(dāng)頁面被失去焦點(diǎn)被切換到后臺(tái)不可見狀態(tài),需要執(zhí)行onPause動(dòng)過礁哄, onPause動(dòng)作通知內(nèi)核暫停所有的動(dòng)作长酗,比如DOM的解析、plugin的執(zhí)行桐绒、JavaScript執(zhí)行夺脾。
pauseTimers()//當(dāng)應(yīng)用程序被切換到后臺(tái)我們使用了webview, 這個(gè)方法不僅僅針對(duì)當(dāng)前的webview而是全局的全應(yīng)用程序的webview茉继,它會(huì)暫停所有webview的layout咧叭,parsing,javascripttimer烁竭。降低CPU功耗菲茬。
resumeTimers()//恢復(fù)pauseTimers時(shí)的動(dòng)作。
destroy()//銷毀派撕,關(guān)閉了Activity時(shí)婉弹,音樂或視頻,還在播放终吼。就必須銷毀镀赌。

5.頁面大小屬性
getScrollY() //方法返回的是當(dāng)前可見區(qū)域的頂端距整個(gè)頁面頂端的距離,也就是當(dāng)前內(nèi)容滾動(dòng)的距離.
getHeight()或者getBottom() //方法都返回當(dāng)前WebView這個(gè)容器的高度
getContentHeight()返回的是整個(gè)html的高度,但并不等同于當(dāng)前整個(gè)頁面的高度,因?yàn)閃ebView有縮放功能,所以當(dāng)前整個(gè)頁面的高度實(shí)際上應(yīng)該是原始html的高度再乘上縮放比例.因此,更正后的結(jié)果,準(zhǔn)確的判斷方法應(yīng)該是:

踩坑

1、調(diào)用destroy()方法的時(shí)候际跪,此時(shí)webview仍綁定在Activity上.這是由于自定義webview構(gòu)建時(shí)傳入了該Activity的context對(duì)象,因此需要先從父容器中移除webview,然后再銷毀webview

例如:

@Override
    public void onDestroyView() {
        super.onDestroyView();
        webView.removeAllViews();
        webView.destroy();
        webView=null;
    }

2商佛、判斷webview是否已經(jīng)滾動(dòng)到頁面底端或者頂端:

 if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
        //已經(jīng)處于底端
    }

 if(webView.getScrollY() == 0){
        //處于頂端
    }

WebSettings常用方法

setWebViewClient(WebViewClient client)//為WebView指定一個(gè)WebViewClient對(duì)象
setWebChromeClient(WebChromeClient client)//為WebView指定一個(gè)WebChromeClient對(duì)象

webview.requestFocusFromTouch();//支持獲取手勢(shì)焦點(diǎn)喉钢,輸入用戶名、密碼或其他
setJavaScriptEnabled(true);  //支持js
setPluginsEnabled(true);  //支持插件 
webSettings.setRenderPriority(RenderPriority.HIGH);  //提高渲染的優(yōu)先級(jí)

設(shè)置自適應(yīng)屏幕良姆,兩者合用
setUseWideViewPort(true);  //將圖片調(diào)整到適合webview的大小 
setLoadWithOverviewMode(true); // 縮放至屏幕的大小



setSupportZoom(true);  //支持縮放肠虽,默認(rèn)為true。是下面那個(gè)的前提歇盼。
//若上面方法設(shè)置為false舔痕,則該WebView不可縮放,這個(gè)不管設(shè)置什么都不能縮放豹缀。
setBuiltInZoomControls(true); //設(shè)置內(nèi)置的縮放控件伯复。


setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持內(nèi)容重新布局  
supportMultipleWindows();  //多窗口 
setCacheMode(WebSettings.LOAD_NO_CACHE);//不使用緩存
setAllowFileAccess(true);  //設(shè)置可以訪問文件 
setNeedInitialFocus(true); //當(dāng)webview調(diào)用requestFocus時(shí)為webview設(shè)置節(jié)點(diǎn)
setJavaScriptCanOpenWindowsAutomatically(true); //支持通過JS打開新窗口 
setLoadsImagesAutomatically(true);  //支持自動(dòng)加載圖片
setDefaultTextEncodingName("utf-8");//設(shè)置編碼格式

踩坑

1、和JavaScript的交互
如果訪問的頁面中有 Javascript,則 WebView 初始化的時(shí)候必須設(shè)置支持 Javascript邢笙。

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

通過創(chuàng)建JavaScript的接口可以讓JavaScript和安卓客戶端進(jìn)行交互啸如。比如說JavaScript可以調(diào)用本地的安卓代碼展示一個(gè)Dialog而不是使用JavaScript的alter()方法。通過addJavascriptInterface()方法創(chuàng)建接口氮惯。
示例:
定義一個(gè)“接口”類

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

在addJavascriptInterface方法中創(chuàng)建接口

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

在HTML的JavaScript中調(diào)用WebView顯示toast消息叮雳,

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

注意:
1 addJavascriptInterface方法中要綁定的Java對(duì)象及方法運(yùn)行在另外的線程中,而不是運(yùn)行在構(gòu)造他的線程中。
2 使用addJavascriptInterface將會(huì)使javaScript可以操控安卓本地代碼妇汗。因此有可能導(dǎo)致安全性問題帘不,請(qǐng)確保所有HTML代碼都是你所知道的。
3 從Android4.2開始杨箭。 只有添加 @JavascriptInterface 聲明的Java方法才可以被JavaScript調(diào)用寞焙。


2、使用緩存的友好方法:

if (NetStatusUtil.isConnected(getApplicationContext())) {
    webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根據(jù)cache-control決定是否從網(wǎng)絡(luò)上取數(shù)據(jù)互婿。
} else {
    webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//沒網(wǎng)捣郊,則從本地獲取,即離線加載
}
webSettings.setDomStorageEnabled(true); // 開啟 DOM storage API 功能
webSettings.setDatabaseEnabled(true);   //開啟 database storage API 功能
webSettings.setAppCacheEnabled(true);//開啟 Application Caches 功能

String cacheDirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "webviewcache"
webSettings.setAppCachePath(cacheDirPath); //設(shè)置  Application Caches 緩存目錄

注意: 每個(gè) Application 只調(diào)用一次WebSettings.setAppCachePath()慈参,WebSettings.setAppCacheMaxSize()

WebViewClient

用來輔助WebView處理各種通知與請(qǐng)求事件呛牲!

onPageStared(WebView view,String url)// 通知主程序網(wǎng)頁開始加載
onPageFinished(WebView view,String url,Bitmap favicon)//通知主程序,網(wǎng)頁加載完畢
doUpdateVisitedHistory(WebView view,String url,boolean isReload)//url,boolean isReload)//更新歷史記錄
onLoadResource(WebView view,String url)//通知主程序WebView即將加載指定url的資源
onScaleChanged(WebView view,float oldScale,float newScale)//ViewView的縮放發(fā)生改變時(shí)調(diào)用
shouldOverrideKeyEvent(WebView view,KeyEvent event)//控制webView是否處理按鍵時(shí)間,如果返回true,則WebView不處理,返回false則處理
shouldOverrideUrlLoading(WebView view,String url)//控制對(duì)新加載的Url的處理,返回true,說明主程序處理WebView不做處理,返回false意味著WebView會(huì)對(duì)其進(jìn)行處理
onReceivedError(WebView view,int errorCode,String description,String failingUrl)//遇到不可恢復(fù)的錯(cuò)誤信息時(shí)調(diào)用

踩坑

1、當(dāng)用戶點(diǎn)擊webview中的網(wǎng)頁鏈接的時(shí)候驮配,安卓系統(tǒng)默認(rèn)會(huì)啟動(dòng)一個(gè)新的應(yīng)用專門成立url的跳轉(zhuǎn)娘扩。如果希望點(diǎn)擊鏈接繼續(xù)在當(dāng)前webview中響應(yīng),而不是新開Android的系統(tǒng)browser中響應(yīng)該鏈接,必須覆蓋 WebView的WebViewClient對(duì)象. 并重寫shouldOverrideUrlLoading方法。

webView.setWebViewClient(new WebViewClient(){
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);//繼續(xù)在webview中訪問
      return true;
      }
  });

** net::ERR_UNKNOWN_URL_SCHEME錯(cuò)誤 **
我的需求中壮锻,在webview中跳轉(zhuǎn)的時(shí)候如果重寫了shouldOverrideUrlLoading琐旁,在某些頁面會(huì)報(bào)net::ERR_UNKNOWN_URL_SCHEME錯(cuò)(比如去哪兒網(wǎng)機(jī)票查詢網(wǎng)站進(jìn)行頁面跳轉(zhuǎn)),我的解決方法是:

webView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //解決 net::ERR_UNKNOWN_URL_SCHEME
                //屏蔽掉錯(cuò)誤的重定向url
                if (url.startsWith("http:") || url.startsWith("https:")){
                    view.loadUrl(url);
                }
                return true;
            }
        });

詳細(xì)解決方法點(diǎn)這里


2躯保、當(dāng)webview的url進(jìn)行跳轉(zhuǎn)的時(shí)候旋膳,自動(dòng)回記錄進(jìn)入歷史界面澎语,可以使用goBack()方法和goForward()方法途事,進(jìn)行返回和前進(jìn)验懊。
webview的canGoBack方法將會(huì)判斷歷史記錄中是否還有頁面,如果還有上一級(jí)頁面尸变,將會(huì)返回true义图。

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode==KeyEvent.KEYCODE_BACK){
            //監(jiān)聽還回鍵
            if (webView.canGoBack()){
                webView.goBack();
            }
        }
        return super.onKeyDown(keyCode, event);
    }

WebChromeClient

onJsAlert(WebView view,String url,String message,JsResult result)//處理Js中的Alert對(duì)話框
onJsConfirm(WebView view,String url,String message,JsResult result)//處理Js中的Confirm對(duì)話框
onJsPrompt(WebView view,String url,String message,String defaultValue,JsPromptResult result)//處理Js中的Prompt對(duì)話框
onProgressChanged(WebView view,int newProgress)//當(dāng)加載進(jìn)度條發(fā)生改變時(shí)調(diào)用
onReceivedIcon(WebView view, Bitmap icon)//獲得網(wǎng)頁的icon
onReceivedTitle(WebView view, String title) //獲得網(wǎng)頁的標(biāo)題

踩坑

1、隱藏標(biāo)題欄

在我的項(xiàng)目中召烂,有部分?jǐn)?shù)據(jù)是需要使用webview來呈現(xiàn)碱工,但是有一個(gè)問題就是網(wǎng)頁自帶了頂部標(biāo)題欄。現(xiàn)在我的需求就是隱藏標(biāo)題欄

重寫了WebChromeClient:

webView.setWebChromeClient(new MyWebChromeClient());

private class MyWebChromeClient extends WebChromeClient{
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            //頁面加載到5%的時(shí)候 注入JS來隱藏導(dǎo)航欄
            if (newProgress>5){
                hideTitle(view);
            }
        }

        private void hideTitle(WebView webView){
            webView.loadUrl("javascript:(function() " +
                    "{ " +
                    "document.querySelectorAll('.header')[0].style.display='none';"+
                    "})()");
            //document.getElementsByClassName('header')[0].style.display='none';
        }
    }

WebView內(nèi)存泄漏優(yōu)化

1奏夫、銷毀WebView的友好方法

/**
 * Description: release the memory of web view, otherwise it's resource will not be recycle.
 * Created by Michael Lee on 7/18/16 20:38
 */
public void clearWebViewResource() {
    if (web_view_ != null) {
        LogUtils.d(TAG,"Clear webview's resources");
        web_view_.removeAllViews();
        // in android 5.1(sdk:21) we should invoke this to avoid memory leak
        // see (https://coolpers.github.io/webview/memory/leak/2015/07/16/
        // android-5.1-webview-memory-leak.html)
        ((ViewGroup) web_view_.getParent()).removeView(web_view_);
        web_view_.setTag(null);
        web_view_.clearHistory();
        web_view_.destroy();
        web_view_ = null;
    }
}

2怕篷、可以將 Webview 的 Activity 新起一個(gè)進(jìn)程,結(jié)束的時(shí)候直接System.exit(0);退出當(dāng)前進(jìn)程酗昼;
啟動(dòng)新進(jìn)程廊谓,主要代碼: AndroidManifest.xml 配置文件代碼如下

<activity
    android:name=".ui.activity.Html5Activity"
    android:process=":lyl.boon.process.web">
    <intent-filter>
        <action android:name="com.lyl.boon.ui.activity.htmlactivity"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

在新進(jìn)程中啟動(dòng) Activity ,里面?zhèn)髁?一個(gè) Url:

Intent intent = new Intent("com.lyl.boon.ui.activity.htmlactivity");
Bundle bundle = new Bundle();
bundle.putString("url", gankDataEntity.getUrl());
intent.putExtra("bundle",bundle);
startActivity(intent);

然后在 Html5Activity 的onDestory() 最后加上 System.exit(0); 殺死當(dāng)前進(jìn)程麻削。

參考連接

談?wù)刉ebView的使用【從零開始搭建android框架系列(5)
WebView(網(wǎng)頁視圖)基本用法
WebView內(nèi)存泄漏優(yōu)化之路

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蒸痹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呛哟,更是在濱河造成了極大的恐慌叠荠,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扫责,死亡現(xiàn)場(chǎng)離奇詭異榛鼎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)公给,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門借帘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淌铐,你說我怎么就攤上這事肺然。” “怎么了腿准?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵际起,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我吐葱,道長(zhǎng)街望,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任弟跑,我火速辦了婚禮灾前,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孟辑。我一直安慰自己哎甲,他們只是感情好蔫敲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著炭玫,像睡著了一般奈嘿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吞加,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天裙犹,我揣著相機(jī)與錄音,去河邊找鬼衔憨。 笑死叶圃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的践图。 我是一名探鬼主播盗似,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼平项!你這毒婦竟也來了赫舒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤闽瓢,失蹤者是張志新(化名)和其女友劉穎接癌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扣讼,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缺猛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椭符。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荔燎。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖销钝,靈堂內(nèi)的尸體忽然破棺而出有咨,到底是詐尸還是另有隱情,我是刑警寧澤蒸健,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布座享,位于F島的核電站,受9級(jí)特大地震影響似忧,放射性物質(zhì)發(fā)生泄漏渣叛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一盯捌、第九天 我趴在偏房一處隱蔽的房頂上張望淳衙。 院中可真熱鬧,春花似錦、人聲如沸箫攀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匠童。三九已至,卻和暖如春塑顺,著一層夾襖步出監(jiān)牢的瞬間汤求,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工严拒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扬绪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓裤唠,卻偏偏與公主長(zhǎng)得像挤牛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子种蘸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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