自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

WebView的核心用法與最佳實(shí)踐,避免常見(jiàn)陷阱和優(yōu)化技巧

移動(dòng)開(kāi)發(fā) Android
WebView在使用過(guò)程中存在一些常見(jiàn)問(wèn)題「性能問(wèn)題」WebView加載H5頁(yè)面時(shí),由于JS解析過(guò)程復(fù)雜、前端頁(yè)面涉及較多的JS代碼文件,以及Android機(jī)型碎片化導(dǎo)致的手機(jī)硬件性能差異,可能會(huì)導(dǎo)致頁(yè)面加載速度較慢。

WebView介紹

WebView是Android平臺(tái)中用于顯示網(wǎng)頁(yè)內(nèi)容的控件,基于Chromium項(xiàng)目(并非完整版的Chrome瀏覽器,不包括Chrome中的所有功能)。WebView使用WebKit引擎來(lái)渲染網(wǎng)頁(yè),可以很好地兼容Web標(biāo)準(zhǔn),可以顯示HTML、CSS和JavaScript等內(nèi)容,還可以用于動(dòng)態(tài)加載網(wǎng)頁(yè)內(nèi)容,并與網(wǎng)頁(yè)進(jìn)行交互,如點(diǎn)擊鏈接、輸入文本等。

WebView在Android應(yīng)用開(kāi)發(fā)中非常有用,在需要展示網(wǎng)頁(yè)內(nèi)容或者與網(wǎng)頁(yè)交互的場(chǎng)景中。例如,在微信或微博等應(yīng)用程序中,WebView常用于打開(kāi)應(yīng)用程序內(nèi)的共享超鏈接。通過(guò)WebView在應(yīng)用中直接展示網(wǎng)頁(yè)內(nèi)容,提供了更為豐富的用戶體驗(yàn)。

WebView的生命周期:

  1. onResume():當(dāng)WebView處于活躍狀態(tài)時(shí),會(huì)回調(diào)此方法。WebView可以正常執(zhí)行網(wǎng)頁(yè)的響應(yīng),包括加載網(wǎng)頁(yè)內(nèi)容、執(zhí)行JavaScript等。
  2. onPause():當(dāng)WebView被切換到后臺(tái)或失去焦點(diǎn)時(shí),會(huì)回調(diào)此方法。WebView會(huì)暫停所有進(jìn)行中的動(dòng)作,如DOM的解析、CSS和JavaScript的執(zhí)行等,以降低CPU功耗。
  3. destroy():當(dāng)WebView需要被銷毀以釋放資源時(shí),會(huì)調(diào)用此方法。在這個(gè)階段,應(yīng)確保所有與WebView相關(guān)的資源都被正確清理,以避免內(nèi)存泄漏。

為了正確管理WebView的生命周期,應(yīng)跟隨Activity的生命周期方法來(lái)調(diào)用WebView的生命周期方法。例如,當(dāng)Activity進(jìn)入onResume狀態(tài)時(shí),應(yīng)調(diào)用WebView的onResume方法;當(dāng)Activity進(jìn)入onPause狀態(tài)時(shí),應(yīng)調(diào)用WebView的onPause方法;當(dāng)Activity被銷毀時(shí),應(yīng)確保WebView也被正確銷毀。

@Override
protected void onResume() {
    super.onResume();
    //恢復(fù)webview的狀態(tài)(不靠譜)
    webView.resumeTimers();
    //激活webView的狀態(tài),能正常加載網(wǎng)頁(yè)
    webView.onResume();
}
 
@Override
protected void onPause() {
    super.onPause();
    //當(dāng)頁(yè)面被失去焦點(diǎn)被切換到后臺(tái)不可見(jiàn)狀態(tài),需要執(zhí)行onPause
    //通過(guò)onPause動(dòng)作通知內(nèi)核暫停所有的動(dòng)作,比如DOM的解析、plugin的執(zhí)行、JavaScript執(zhí)行。
    webView.onPause();
 
    //當(dāng)應(yīng)用程序(存在webview)被切換到后臺(tái)時(shí),這個(gè)方法不僅僅針對(duì)當(dāng)前的webview而是全局的全應(yīng)用程序的webview
    //它會(huì)暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。(不靠譜)
    webView.pauseTimers();
}
 
@Override
protected void onDestroy() {
 super.onDestroy();
 //在關(guān)閉了Activity時(shí),如果Webview的音樂(lè)或視頻,還在播放。就必須銷毀Webview
 //但是注意:webview調(diào)用destory時(shí),webview仍綁定在Activity上
 //這是由于自定義webview構(gòu)建時(shí)傳入了該Activity的context對(duì)象
 //因此需要先從父容器中移除webview,然后再銷毀webview:
 ViewGroup parent = findViewById(R.id.container);
 parent.removeView(webView);
 webView.destroy();
}

WebView使用

添加網(wǎng)絡(luò)權(quán)限

<uses-permission android:name="android.permission.INTERNET" />
  1. 布局文件添加WebView控件
<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  1. 初始化WebView
WebView webView = (WebView) findViewById(R.id.webview);
  1. 設(shè)置WebSettings 通過(guò)WebSettings類來(lái)配置WebView的一些設(shè)置項(xiàng),比如是否支持JavaScript,是否允許縮放等。
//聲明WebSettings子類
WebSettings webSettings = webView.getSettings();
 
//如果訪問(wèn)的頁(yè)面中要與Javascript交互,則webview必須設(shè)置支持Javascript
webSettings.setJavaScriptEnabled(true);  
 
//支持插件
webSettings.setPluginsEnabled(true); 
 
//設(shè)置自適應(yīng)屏幕,兩者合用
webSettings.setUseWideViewPort(true); //將圖片調(diào)整到適合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 縮放至屏幕的大小
 
//縮放操作
webSettings.setSupportZoom(true); //支持縮放,默認(rèn)為true。是下面那個(gè)的前提。
webSettings.setBuiltInZoomControls(true); //設(shè)置內(nèi)置的縮放控件。若為false,則該WebView不可縮放
webSettings.setDisplayZoomControls(false); //隱藏原生的縮放控件
 
//其他細(xì)節(jié)操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //關(guān)閉webview中緩存 
webSettings.setAllowFileAccess(true); //設(shè)置可以訪問(wèn)文件 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通過(guò)JS打開(kāi)新窗口 
webSettings.setLoadsImagesAutomatically(true); //支持自動(dòng)加載圖片
webSettings.setDefaultTextEncodingName("utf-8");//設(shè)置編碼格式
  1. 加載網(wǎng)頁(yè)內(nèi)容 WebView可以加載遠(yuǎn)程網(wǎng)頁(yè)或本地HTML資源。使用loadUrl方法加載一個(gè)網(wǎng)頁(yè)的URL,或者使用loadData方法加載一段HTML數(shù)據(jù)。
webView.loadUrl("https://www.baidu.com"); // 加載遠(yuǎn)程網(wǎng)頁(yè)

加載本地的HTML文件:

webView.loadUrl("file:///android_asset/index.html"); // 加載本地HTML文件

加載HTML數(shù)據(jù):

String goods_content="<p>我的第一個(gè)段落。</p>";
webView.loadDataWithBaseURL(null, WebUtil.getHtmlData(goods_content), "text/html", "utf-8", null);
 
public static String getHtmlData(String bodyHTML) {
 String head = "<head>" +
   "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\"> " +
   "<style>div,p,img{max-width: 100%; width: 100% !important; height: auto !important;}" +
   "body {" +
   "margin-right:8px;" +//限定網(wǎng)頁(yè)中的文字右邊距為15px(可根據(jù)實(shí)際需要進(jìn)行行管屏幕適配操作)
   "margin-left:8px;" +//限定網(wǎng)頁(yè)中的文字左邊距為15px(可根據(jù)實(shí)際需要進(jìn)行行管屏幕適配操作)
   "margin-top:8px;" +//限定網(wǎng)頁(yè)中的文字上邊距為15px(可根據(jù)實(shí)際需要進(jìn)行行管屏幕適配操作)
   "font-size:16px;" +//限定網(wǎng)頁(yè)中文字的大小為40px,請(qǐng)務(wù)必根據(jù)各種屏幕分辨率進(jìn)行適配更改
   "word-wrap:break-word;" +//允許自動(dòng)換行(漢字網(wǎng)頁(yè)應(yīng)該不需要這一屬性,這個(gè)用來(lái)強(qiáng)制英文單詞換行,類似于word/wps中的西文換行)
   "}" +
   "p { margin: 0; }" +
   "</style>" +
   "</head>";
 return "<html>" + head + "<body>" + bodyHTML + "</body><ml>";
}
  1. 處理網(wǎng)頁(yè)加載事件 常規(guī)用法,復(fù)寫(xiě)shouldOverrideUrlLoading()方法,使打開(kāi)網(wǎng)頁(yè)時(shí)不調(diào)用系統(tǒng)瀏覽器, 而是在WebView中顯示。
webView.setWebViewClient(new WebViewClient(){
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
          view.loadUrl(url);
          return true;
      }
});

通過(guò)WebViewClient或WebChromeClient類來(lái)處理網(wǎng)頁(yè)加載過(guò)程中的一些事件,比如頁(yè)面開(kāi)始加載、頁(yè)面加載完成、出現(xiàn)錯(cuò)誤等。

WebViewClient webViewClient = new WebViewClient() {
     /**
  * shouldOverrideUrlLoading
  * <p>
  * 當(dāng)加載的網(wǎng)頁(yè)需要重定向的時(shí)候就會(huì)回調(diào)這個(gè)函數(shù)告知我們應(yīng)用程序是否需要接管控制網(wǎng)頁(yè)加載,如果應(yīng)用程序接管,
  *并且return true意味著主程序接管網(wǎng)頁(yè)加載,如果返回false讓webview自己處理。
  * </p>
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            即將要被加載的url
  * @return true 當(dāng)前應(yīng)用程序要自己處理這個(gè)url, 返回false則不處理。 注:"post"請(qǐng)求方式不會(huì)調(diào)用這個(gè)回調(diào)函數(shù)
  */
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, String url) {
  if (Uri.parse(url).getHost().equals("www.baidu.com")) {
   Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   context.startActivity(intent);
   return true;
  }
  return false;
 }
 
 /**
  * onPageStarted 當(dāng)內(nèi)核開(kāi)始加載訪問(wèn)的url時(shí),會(huì)通知應(yīng)用程序,對(duì)每個(gè)main frame
  * 這個(gè)函數(shù)只會(huì)被調(diào)用一次,頁(yè)面包含iframe或者framesets 不會(huì)另外調(diào)用一次onPageStarted,
     * 當(dāng)網(wǎng)頁(yè)內(nèi)內(nèi)嵌的frame 發(fā)生改變時(shí)也不會(huì)調(diào)用onPageStarted。
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            即將要被加載的url
  * @param favicon
  *            如果這個(gè)favicon已經(jīng)存儲(chǔ)在本地?cái)?shù)據(jù)庫(kù)中,則會(huì)返回這個(gè)網(wǎng)頁(yè)的favicon,否則返回為null。
  */
 @Override
 public void onPageStarted(WebView view, String url, Bitmap favicon) {
  // TODO Auto-generated method stub
  super.onPageStarted(view, url, favicon);
  Log.i(TAG, "onPageStarted:頁(yè)面開(kāi)始加載");
 }
 
 /**
  * onPageFinished 當(dāng)內(nèi)核加載完當(dāng)前頁(yè)面時(shí)會(huì)通知我們的應(yīng)用程序,這個(gè)函數(shù)只有在main
  * frame情況下才會(huì)被調(diào)用,當(dāng)調(diào)用這個(gè)函數(shù)之后,渲染的圖片不會(huì)被更新,如果需要獲得新圖片的通知可以使用@link
  * WebView.PictureListener#onNewPicture。 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            即將要被加載的url
  */
 @Override
 public void onPageFinished(WebView view, String url) {
  // TODO Auto-generated method stub
  super.onPageFinished(view, url);
  Log.i(TAG, "onPageStarted:頁(yè)面加載結(jié)束");
 }
 
 /**
  * onLoadResource 通知應(yīng)用程序WebView即將加載url 制定的資源
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            即將加載的url 資源
  */
 @Override
 public void onLoadResource(WebView view, String url) {
  // TODO Auto-generated method stub
  super.onLoadResource(view, url);
  Log.i(TAG, "onLoadResource:加載資源指定的網(wǎng)址");
 }
 
 /**
  * shouldInterceptRequest
  * 通知應(yīng)用程序內(nèi)核即將加載url制定的資源,應(yīng)用程序可以返回本地的資源提供給內(nèi)核,若本地處理返回?cái)?shù)據(jù),內(nèi)核不從網(wǎng)絡(luò)上獲取數(shù)據(jù)。
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            raw url 制定的資源
  * @return 返回WebResourceResponse包含數(shù)據(jù)對(duì)象,或者返回null
  */
 @Override
 public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
  // TODO Auto-generated method stub
  Log.i(TAG, "shouldInterceptRequest");
  return super.shouldInterceptRequest(view, url);
 }
 
 /**
  * onReceivedError
  * <p>
  * 當(dāng)瀏覽器訪問(wèn)制定的網(wǎng)址發(fā)生錯(cuò)誤時(shí)會(huì)通知我們應(yīng)用程序 參數(shù)說(shuō)明:
  * </p>
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param errorCode
  *            錯(cuò)誤號(hào)可以在WebViewClient.ERROR_* 里面找到對(duì)應(yīng)的錯(cuò)誤名稱。
  * @param description
  *            描述錯(cuò)誤的信息
  * @param failingUrl
  *            當(dāng)前訪問(wèn)失敗的url,注意并不一定是我們主url
  */
 @Override
 public void onReceivedError(WebView view, int errorCode,
   String description, String failingUrl) {
  // TODO Auto-generated method stub
  super.onReceivedError(view, errorCode, description, failingUrl);
  view.loadUrl("file:///android_asset/error.html");
  Log.i(TAG, "onReceivedError");
 }
 
 /**
  * 如果瀏覽器需要重新發(fā)送POST請(qǐng)求,可以通過(guò)這個(gè)時(shí)機(jī)來(lái)處理。默認(rèn)是不重新發(fā)送數(shù)據(jù)。 參數(shù)說(shuō)明
  * 
  * @param view
  *            接收WebViewClient的webview
  * @param dontResend
  *            瀏覽器不需要重新發(fā)送的參數(shù)
  * @param resend
  *            瀏覽器需要重新發(fā)送的參數(shù)
  */
 @Override
 public void onFormResubmission(WebView view, Message dontResend,
   Message resend) {
  // TODO Auto-generated method stub
  super.onFormResubmission(view, dontResend, resend);
  Log.i(TAG, "onFormResubmission");
 }
 
 /**
  * doUpdateVisitedHistory
  * 通知應(yīng)用程序可以將當(dāng)前的url存儲(chǔ)在數(shù)據(jù)庫(kù)中,意味著當(dāng)前的訪問(wèn)url已經(jīng)生效并被記錄在內(nèi)核當(dāng)中。這個(gè)函數(shù)在網(wǎng)頁(yè)加載過(guò)程中只會(huì)被調(diào)用一次。
  * 注意網(wǎng)頁(yè)前進(jìn)后退并不會(huì)回調(diào)這個(gè)函數(shù)。
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            當(dāng)前正在訪問(wèn)的url
  * @param isReload
  *            如果是true 這個(gè)是正在被reload的url
  */
 @Override
 public void doUpdateVisitedHistory(WebView view, String url,
   boolean isReload) {
  // TODO Auto-generated method stub
  super.doUpdateVisitedHistory(view, url, isReload);
  Log.i(TAG, "doUpdateVisitedHistory");
 }
 
 /**
  * 當(dāng)網(wǎng)頁(yè)加載資源過(guò)程中發(fā)現(xiàn)SSL錯(cuò)誤會(huì)調(diào)用此方法。我們應(yīng)用程序必須做出響應(yīng),是取消請(qǐng)求handler.cancel(),還是繼續(xù)請(qǐng)求handler.
  * proceed();內(nèi)核的默認(rèn)行為是handler.cancel();
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param handler
  *            處理用戶請(qǐng)求的對(duì)象。
  * @param error
  *            SSL錯(cuò)誤對(duì)象
  * 
  */
 @Override
 public void onReceivedSslError(WebView view, SslErrorHandler handler,
   SslError error) {
  // view.loadUrl("file:///android_asset/error.html");
  // TODO Auto-generated method stub
  super.onReceivedSslError(view, handler, error);
  Log.i(TAG, "onReceivedSslError");
 }
 
 /**
  * onReceivedHttpAuthRequest 通知應(yīng)用程序WebView接收到了一個(gè)Http
  * auth的請(qǐng)求,應(yīng)用程序可以使用supplied 設(shè)置webview的響應(yīng)請(qǐng)求。默認(rèn)行為是cancel 本次請(qǐng)求。
  * 
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param handler
  *            用來(lái)響應(yīng)WebView請(qǐng)求的對(duì)象
  * @param host
  *            請(qǐng)求認(rèn)證的host
  * @param realm
  *            認(rèn)真請(qǐng)求所在的域
  */
 @Override
 public void onReceivedHttpAuthRequest(WebView view,
   HttpAuthHandler handler, String host, String realm) {
  // TODO Auto-generated method stub
  super.onReceivedHttpAuthRequest(view, handler, host, realm);
  Log.i(TAG, "onReceivedHttpAuthRequest");
 }
 
 /**
  * shouldOverrideKeyEvent
  * 提供應(yīng)用程序同步一個(gè)處理按鍵事件的機(jī)會(huì),菜單快捷鍵需要被過(guò)濾掉。如果返回true,webview不處理該事件,如果返回false,
  * webview會(huì)一直處理這個(gè)事件,因此在view 鏈上沒(méi)有一個(gè)父類可以響應(yīng)到這個(gè)事件。默認(rèn)行為是return false;
  * 
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param event
  *            鍵盤(pán)事件名
  * @return 如果返回true,應(yīng)用程序處理該時(shí)間,返回false 交由webview處理。
  */
 @Override
 public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
  Log.i(TAG, "shouldOverrideKeyEvent");
  // TODO Auto-generated method stub
  return super.shouldOverrideKeyEvent(view, event);
 }
 
 /**
  * 通知應(yīng)用程序webview 要被scale。應(yīng)用程序可以處理改事件,比如調(diào)整適配屏幕。
  */
 @Override
 public void onScaleChanged(WebView view, float oldScale, float newScale) {
  // TODO Auto-generated method stub
  super.onScaleChanged(view, oldScale, newScale);
  Log.i(TAG, "onScaleChanged");
 }
 
 /**
  * onReceivedLoginRequest 通知應(yīng)用程序有個(gè)自動(dòng)登錄的帳號(hào)過(guò)程
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            請(qǐng)求登陸的webview
  * @param realm
  *            賬戶的域名,用來(lái)查找賬戶。
  * @param account
  *            一個(gè)可選的賬戶,如果是null 需要和本地的賬戶進(jìn)行check, 如果是一個(gè)可用的賬戶,則提供登錄。
  * @param args
  *            驗(yàn)證制定參數(shù)的登錄用戶
  */
 @Override
 public void onReceivedLoginRequest(WebView view, String realm,
   String account, String args) {
  // TODO Auto-generated method stub
  super.onReceivedLoginRequest(view, realm, account, args);
  Log.i(TAG, "onReceivedLoginRequest");
 
 }
});

WebChromeClient輔助WebVlew處理Javascrlpt的對(duì)話框,網(wǎng)站圖標(biāo),網(wǎng)站tltle,加載進(jìn)度等。

webView.setWebChromeClient(new WebChromeClient() {
 /**
  * onProgressChanged 通知應(yīng)用程序當(dāng)前網(wǎng)頁(yè)加載的進(jìn)度。
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebChromeClient的的webview實(shí)例
  * @param newProgress
  *            webview接受的進(jìn)度
  */
 @Override
 public void onProgressChanged(WebView view, int newProgress) {
  // TODO Auto-generated method stub
  super.onProgressChanged(view, newProgress);
  if (newProgress <= 100) {
   Log.i(TAG, newProgress + "===onProgressChanged===");
  }
 }
 
 /**
  * 當(dāng)document 的title變化時(shí),會(huì)通知應(yīng)用程序
  * 
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的webview實(shí)例
  * @param title
  *            document新的title
  */
 @Override
 public void onReceivedTitle(WebView view, String title) {
  // TODO Auto-generated method stub
  super.onReceivedTitle(view, title);
  Message message = new Message();
  message.what = 100;
  message.obj = title;
  handler.sendMessage(message);
 
 }
 
 /**
  * 當(dāng)前頁(yè)面有個(gè)新的favicon時(shí)候,會(huì)回調(diào)這個(gè)函數(shù)。 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param icon
  *            當(dāng)前頁(yè)面的favicon 注:很多時(shí)間不會(huì)跳轉(zhuǎn)到此回調(diào)函數(shù),因?yàn)楹芏嗑W(wǎng)站設(shè)置了icon,沒(méi)有設(shè)置favicon,
  */
 @Override
 public void onReceivedIcon(WebView view, Bitmap icon) {
  // TODO Auto-generated method stub
  super.onReceivedIcon(view, icon);
  Message message = new Message();
  message.what = 200;
  message.obj = icon;
  handler.sendMessage(message);
 }
 
 /**
  * 通知應(yīng)用程序 apple-touch-icon的 url
  * 
  * 參數(shù)說(shuō)明:
  * 
  * @param view
  *            接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個(gè)webview。
  * @param url
  *            apple-touch-icon 的服務(wù)端地址
  * @param precomposed
  *            如果precomposed 是true 則touch-icon是預(yù)先創(chuàng)建的
  * 
  *            Tips
  * 
  *            如果應(yīng)用程序需要這個(gè)icon的話, 可以通過(guò)這個(gè)url獲取得到 icon。
  */
 @Override
 public void onReceivedTouchIconUrl(WebView view, String url,
   boolean precomposed) {
  // TODO Auto-generated method stub
  super.onReceivedTouchIconUrl(view, url, precomposed);
  Log.i(TAG, "====onReceivedTouchIconUrl====");
 }
 
  
 /**
  * webview請(qǐng)求得到focus,發(fā)生這個(gè)主要是當(dāng)前webview不是前臺(tái)狀態(tài),是后臺(tái)webview。
  */
 @Override
 public void onRequestFocus(WebView view) {
  // TODO Auto-generated method stub
  super.onRequestFocus(view);
  Log.i(TAG, "====onRequestFocus====");
 }
 
 /**
  * 覆蓋默認(rèn)的window.alert展示界面,
  */
 @Override
 public boolean onJsAlert(final WebView view, String url, String message,
   JsResult result) {
  final AlertDialog.Builder builder = new AlertDialog.Builder(
    view.getContext());
 
  builder.setTitle("對(duì)話框").setMessage(message)
    .setPositiveButton("確定", null);
  builder.setOnKeyListener(new OnKeyListener() {
   public boolean onKey(DialogInterface dialog, int keyCode,
     KeyEvent event) {
    Log.v("onJsAlert", "keyCode==" + keyCode + "event=" + event);
    return true;
   }
  });
  // 禁止響應(yīng)按back鍵的事件
  builder.setCancelable(false);
  AlertDialog dialog = builder.create();
  dialog.show();
  result.confirm();// 因?yàn)闆](méi)有綁定事件,需要強(qiáng)行confirm,否則頁(yè)面會(huì)變黑顯示不了內(nèi)容。
  return true;
  // return super.onJsAlert(view, url, message, result);
 }
 
 /**
  * 覆蓋默認(rèn)的window.confirm展示界面,
  */
 @Override
 public boolean onJsConfirm(final WebView view, String url, String message,
   final JsResult result) {
  final AlertDialog.Builder builder = new AlertDialog.Builder(
    view.getContext());
  builder.setTitle("對(duì)話框").setMessage(message)
    .setPositiveButton("確定", new OnClickListener() {
     public void onClick(DialogInterface dialog, int which) {
      result.confirm();
     }
    }).setNeutralButton("取消", new OnClickListener() {
     public void onClick(DialogInterface dialog, int which) {
      result.cancel();
     }
    });
  builder.setOnCancelListener(new OnCancelListener() {
   @Override
   public void onCancel(DialogInterface dialog) {
    result.cancel();
   }
  });
 
  // 屏蔽keycode等于84之類的按鍵,避免按鍵后導(dǎo)致對(duì)話框消息而頁(yè)面無(wú)法再?gòu)棾鰧?duì)話框的問(wèn)題
  builder.setOnKeyListener(new OnKeyListener() {
   @Override
   public boolean onKey(DialogInterface dialog, int keyCode,
     KeyEvent event) {
    Log.v("onJsConfirm", "keyCode==" + keyCode + "event=" + event);
    return true;
   }
  });
  // 禁止響應(yīng)按back鍵的事件
  // builder.setCancelable(false);
  AlertDialog dialog = builder.create();
  dialog.show();
  return true;
 }
 
 /**
  * 覆蓋默認(rèn)的window.prompt展示界面,
  */
 @Override
 public boolean onJsPrompt(WebView view, String url, String message,
   String defaultValue, final JsPromptResult result) {
  final AlertDialog.Builder builder = new AlertDialog.Builder(
    view.getContext());
 
  builder.setTitle("對(duì)話框").setMessage(message);
 
  final EditText et = new EditText(view.getContext());
  et.setSingleLine();
  et.setText(defaultValue);
  builder.setView(et).setPositiveButton("確定", new OnClickListener() {
   public void onClick(DialogInterface dialog, int which) {
    result.confirm(et.getText().toString());
   }
 
  }).setNeutralButton("取消", new OnClickListener() {
   public void onClick(DialogInterface dialog, int which) {
    result.cancel();
   }
  });
 
  // 屏蔽keycode等于84之類的按鍵,避免按鍵后導(dǎo)致對(duì)話框消息而頁(yè)面無(wú)法再?gòu)棾鰧?duì)話框的問(wèn)題
  builder.setOnKeyListener(new OnKeyListener() {
   public boolean onKey(DialogInterface dialog, int keyCode,
     KeyEvent event) {
    Log.v("onJsPrompt", "keyCode==" + keyCode + "event=" + event);
    return true;
   }
  });
 
  // 禁止響應(yīng)按back鍵的事件
  // builder.setCancelable(false);
  AlertDialog dialog = builder.create();
  dialog.show();
  return true;
  // return super.onJsPrompt(view, url, message, defaultValue,
  // result);
 }
});
  1. 處理JavaScript與Android代碼的交互 如果網(wǎng)頁(yè)中包含JavaScript,并且需要與Android代碼進(jìn)行交互,可以使用WebView的addJavascriptInterface方法來(lái)實(shí)現(xiàn)。在Android代碼中定義一個(gè)對(duì)象,并在JavaScript中調(diào)用這個(gè)對(duì)象的方法。

編寫(xiě)html文件,放到assets文件里面:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
 </head>
 <body>
   <div>
    function say(value){</br>
      callJS(value);</br>
    }
   </div>
 </body>
 
 <script>
  function callJS(value){
   alert(value);
   return value;
  }
 </script>
</html>

Android調(diào)用js:

public class MainActivity extends AppCompatActivity {
    private WebView webview;
    private TextView tvAndroid;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        webview = (WebView) findViewById(R.id.webview);
        tvAndroid = (TextView) findViewById(R.id.tv_android);
        tvAndroid.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //Android調(diào)用js方法
                //Android 4.4以下使用loadUrl,Android 4.4以上evaluateJavascript
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    webview.loadUrl("javascript:callJS('aaa')");
                } else {
                    webview.evaluateJavascript("javascript:callJS('aaa')", new ValueCallback<String>() {
                        @Override
                        public void onReceiveValue(String value) {
                            //此處為 js 返回的結(jié)果
                            Toast.makeText(MainActivity.this,value,Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });
        
        initWebView();
    }
 
 
    public void initWebView() {
        //啟用JS腳本
        webview.getSettings().setJavaScriptEnabled(true);
        // 設(shè)置允許JS彈窗
        webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
 
        //加載網(wǎng)頁(yè)
        webview.loadUrl("file:///android_asset/index.html");
 
        // 由于設(shè)置了彈窗檢驗(yàn)調(diào)用結(jié)果,所以需要支持js對(duì)話框
        // webview只是載體,內(nèi)容的渲染需要使用webviewChromClient類去實(shí)現(xiàn)
        // 通過(guò)設(shè)置WebChromeClient對(duì)象處理JavaScript的對(duì)話框
        //設(shè)置響應(yīng)js 的Alert()函數(shù)
        webview.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult jsResult) {
                new AlertDialog.Builder(view.getContext()).setMessage(message).setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        jsResult.confirm();
                    }
                }).setCancelable(false).create().show();
                return true;
            }
        });
 
        //覆蓋WebView默認(rèn)使用第三方或系統(tǒng)默認(rèn)瀏覽器打開(kāi)網(wǎng)頁(yè)的行為,使網(wǎng)頁(yè)用WebView打開(kāi)
        webview.setWebViewClient(new WebViewClient() {
            //override
            public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
                handler.proceed("admin", "sunlight");
                int d = Log.d("MyWebViewClient", "onReceivedHttpAuthRequest");
            }
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String uri) {
                // TODO Auto-generated method stub
                //返回值是true的時(shí)候控制去WebView打開(kāi),為false調(diào)用系統(tǒng)瀏覽器或第三方瀏覽器
                view.loadUrl(uri);
                return true;
            }
        });
    }
}

「注意」js代碼調(diào)用一定要在onPageFinished() 回調(diào)之后才能調(diào)用,否則不會(huì)調(diào)用。

js調(diào)用Android方法: 通過(guò)WebView的addJavascriptInterface()進(jìn)行對(duì)象映射

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
 </head>
 <body>
   <button style="width:100%;height:50px; margin-top: 100px;" onclick="aa.showToast('哈哈哈')">js調(diào)用Android方法</button>
 </body>
 
</html>
public class MainActivity2 extends AppCompatActivity {
    private WebView webview;
    private TextView tvAndroid;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        
        webview = (WebView) findViewById(R.id.webview);
        tvAndroid = (TextView) findViewById(R.id.tv_android);
        tvAndroid.setText("http://繼承自O(shè)bject類,別名是aa,即在html可以直接用aa.showToast(\"哈哈哈\")來(lái)調(diào)用android方法\n" +
                "public class MyObject extends Object {\n" +
                "    @JavascriptInterface\n" +
                "    public void showToast(String name){\n" +
                "         Toast.makeText(MainActivity2.this, \"您好!\"+name, Toast.LENGTH_SHORT).show();\n" +
                "    }\n" +
                "}");
        
        initWebView();
    }
 
 
    public void initWebView() {
        // 設(shè)置與Js交互的權(quán)限
        webview.getSettings().setJavaScriptEnabled(true);
 
        //將java對(duì)象暴露給JavaScript腳本
        //參數(shù)1:java對(duì)象,里面定義了java方法
        //參數(shù)2:Java對(duì)象在js里的對(duì)象名,可以看作第一個(gè)參數(shù)的別名,可以隨便取,即在html可以直接用aa.showToast("哈哈哈")來(lái)調(diào)用android方法
        webview.addJavascriptInterface(new MyObject(), "aa");//AndroidtoJS類對(duì)象映射到j(luò)s的test對(duì)象
 
        //加載網(wǎng)頁(yè)
        webview.loadUrl("file:///android_asset/index2.html");
    }
 
    //繼承自O(shè)bject類,別名是aa,即在html可以直接用aa.showToast("哈哈哈")來(lái)調(diào)用android方法
    public class MyObject extends Object {
        // 定義JS需要調(diào)用的方法
        // 被JS調(diào)用的方法必須加入@JavascriptInterface注解
        @JavascriptInterface
        public void showToast(String name){
            Toast.makeText(MainActivity2.this, "您好!"+name, Toast.LENGTH_SHORT).show();
        }
    }
}
  1. 頁(yè)面返回
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
        webView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}
  1. 緩存配置
WebSettings webSettings = webView.getSettings();
//優(yōu)先使用緩存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 
//只在緩存中讀取
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
/不使用緩存
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
  1. 清除緩存
//清除網(wǎng)頁(yè)訪問(wèn)留下的緩存,由于內(nèi)核緩存是全局的因此這個(gè)方法不僅僅針對(duì)webview而是針對(duì)整個(gè)應(yīng)用程序.
webview.clearCache(true);
//清除當(dāng)前webview訪問(wèn)的歷史記錄,只會(huì)webview訪問(wèn)歷史記錄里的所有記錄除了當(dāng)前訪問(wèn)記錄.
webview.clearHistory (); 
//這個(gè)api僅僅清除自動(dòng)完成填充的表單數(shù)據(jù),并不會(huì)清除WebView存儲(chǔ)到本地的數(shù)據(jù)。
webview.clearFormData ();

注意

WebView在使用過(guò)程中存在一些常見(jiàn)問(wèn)題「性能問(wèn)題」WebView加載H5頁(yè)面時(shí),由于JS解析過(guò)程復(fù)雜、前端頁(yè)面涉及較多的JS代碼文件,以及Android機(jī)型碎片化導(dǎo)致的手機(jī)硬件性能差異,可能會(huì)導(dǎo)致頁(yè)面加載速度較慢。每次加載H5頁(yè)面都會(huì)產(chǎn)生較多的網(wǎng)絡(luò)請(qǐng)求,包括HTML的主URL請(qǐng)求以及HTML引用的外部JS、CSS、字體文件、圖片文件等,會(huì)耗費(fèi)一定的流量和時(shí)間。

「內(nèi)存管理問(wèn)題」WebView是依附于Activity的,而Activity的生命周期和WebView啟動(dòng)的線程的生命周期可能不一致,可能導(dǎo)致WebView一直持有對(duì)Activity的引用而無(wú)法釋放,從而引發(fā)內(nèi)存泄漏問(wèn)題。WebView使用不當(dāng),可能會(huì)導(dǎo)致應(yīng)用程序在運(yùn)行過(guò)程中占用大量?jī)?nèi)存,甚至引發(fā)應(yīng)用崩潰。

「安全漏洞」WebView中可能存在一些安全漏洞,如遠(yuǎn)程代碼執(zhí)行漏洞、密碼明文存儲(chǔ)漏洞和域控制不嚴(yán)格漏洞等??赡軐?dǎo)致攻擊者利用WebView執(zhí)行任意Java對(duì)象的方法,竊取用戶信息,甚至控制用戶設(shè)備。

「兼容性問(wèn)題」不同版本的Android系統(tǒng)或不同品牌的手機(jī)可能存在WebView兼容性問(wèn)題。例如,一些機(jī)型可能不支持WebGL,導(dǎo)致部分網(wǎng)頁(yè)內(nèi)容無(wú)法正常顯示。WebView在加載某些特定格式的網(wǎng)頁(yè)或執(zhí)行某些特定操作時(shí)也可能出現(xiàn)兼容性問(wèn)題。

責(zé)任編輯:武曉燕 來(lái)源: 沐雨花飛蝶
相關(guān)推薦

2017-03-22 09:44:04

DevOps轉(zhuǎn)型陷阱實(shí)踐

2021-02-28 13:19:42

大數(shù)據(jù)IT數(shù)據(jù)管理

2018-11-18 16:31:14

Kubernetes監(jiān)控容器

2011-12-31 10:18:33

響應(yīng)設(shè)計(jì)

2023-07-25 11:22:31

2024-03-08 10:50:44

Spring技術(shù)應(yīng)用程序

2022-03-08 09:26:41

物聯(lián)網(wǎng)安全物聯(lián)網(wǎng)

2013-12-31 09:26:31

JavaScript技巧

2025-04-11 03:00:55

2021-08-24 10:51:19

多云云計(jì)算云平臺(tái)

2018-11-15 08:07:33

Kubernetes監(jiān)控IT團(tuán)隊(duì)

2025-02-17 01:00:00

.NET性能服務(wù)器

2010-07-06 09:07:09

2014-12-17 09:46:30

AndroidListView最佳實(shí)踐

2018-08-02 15:09:20

PyTorch深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)

2023-11-12 11:54:55

UX性能widget

2013-05-17 11:43:55

主數(shù)據(jù)數(shù)據(jù)管理

2012-03-29 09:35:32

WEBCSS

2012-03-19 09:55:38

CSS

2025-02-13 07:42:35

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)