精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

WebView的核心用法與最佳實踐,避免常見陷阱和優化技巧

移動開發 Android
WebView在使用過程中存在一些常見問題「性能問題」WebView加載H5頁面時,由于JS解析過程復雜、前端頁面涉及較多的JS代碼文件,以及Android機型碎片化導致的手機硬件性能差異,可能會導致頁面加載速度較慢。

WebView介紹

WebView是Android平臺中用于顯示網頁內容的控件,基于Chromium項目(并非完整版的Chrome瀏覽器,不包括Chrome中的所有功能)。WebView使用WebKit引擎來渲染網頁,可以很好地兼容Web標準,可以顯示HTML、CSS和JavaScript等內容,還可以用于動態加載網頁內容,并與網頁進行交互,如點擊鏈接、輸入文本等。

WebView在Android應用開發中非常有用,在需要展示網頁內容或者與網頁交互的場景中。例如,在微信或微博等應用程序中,WebView常用于打開應用程序內的共享超鏈接。通過WebView在應用中直接展示網頁內容,提供了更為豐富的用戶體驗。

WebView的生命周期:

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

為了正確管理WebView的生命周期,應跟隨Activity的生命周期方法來調用WebView的生命周期方法。例如,當Activity進入onResume狀態時,應調用WebView的onResume方法;當Activity進入onPause狀態時,應調用WebView的onPause方法;當Activity被銷毀時,應確保WebView也被正確銷毀。

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

WebView使用

添加網絡權限

<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. 設置WebSettings 通過WebSettings類來配置WebView的一些設置項,比如是否支持JavaScript,是否允許縮放等。
//聲明WebSettings子類
WebSettings webSettings = webView.getSettings();
 
//如果訪問的頁面中要與Javascript交互,則webview必須設置支持Javascript
webSettings.setJavaScriptEnabled(true);  
 
//支持插件
webSettings.setPluginsEnabled(true); 
 
//設置自適應屏幕,兩者合用
webSettings.setUseWideViewPort(true); //將圖片調整到適合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 縮放至屏幕的大小
 
//縮放操作
webSettings.setSupportZoom(true); //支持縮放,默認為true。是下面那個的前提。
webSettings.setBuiltInZoomControls(true); //設置內置的縮放控件。若為false,則該WebView不可縮放
webSettings.setDisplayZoomControls(false); //隱藏原生的縮放控件
 
//其他細節操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //關閉webview中緩存 
webSettings.setAllowFileAccess(true); //設置可以訪問文件 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通過JS打開新窗口 
webSettings.setLoadsImagesAutomatically(true); //支持自動加載圖片
webSettings.setDefaultTextEncodingName("utf-8");//設置編碼格式
  1. 加載網頁內容 WebView可以加載遠程網頁或本地HTML資源。使用loadUrl方法加載一個網頁的URL,或者使用loadData方法加載一段HTML數據。
webView.loadUrl("https://www.baidu.com"); // 加載遠程網頁

加載本地的HTML文件:

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

加載HTML數據:

String goods_content="<p>我的第一個段落。</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;" +//限定網頁中的文字右邊距為15px(可根據實際需要進行行管屏幕適配操作)
   "margin-left:8px;" +//限定網頁中的文字左邊距為15px(可根據實際需要進行行管屏幕適配操作)
   "margin-top:8px;" +//限定網頁中的文字上邊距為15px(可根據實際需要進行行管屏幕適配操作)
   "font-size:16px;" +//限定網頁中文字的大小為40px,請務必根據各種屏幕分辨率進行適配更改
   "word-wrap:break-word;" +//允許自動換行(漢字網頁應該不需要這一屬性,這個用來強制英文單詞換行,類似于word/wps中的西文換行)
   "}" +
   "p { margin: 0; }" +
   "</style>" +
   "</head>";
 return "<html>" + head + "<body>" + bodyHTML + "</body><ml>";
}
  1. 處理網頁加載事件 常規用法,復寫shouldOverrideUrlLoading()方法,使打開網頁時不調用系統瀏覽器, 而是在WebView中顯示。
webView.setWebViewClient(new WebViewClient(){
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
          view.loadUrl(url);
          return true;
      }
});

通過WebViewClient或WebChromeClient類來處理網頁加載過程中的一些事件,比如頁面開始加載、頁面加載完成、出現錯誤等。

WebViewClient webViewClient = new WebViewClient() {
     /**
  * shouldOverrideUrlLoading
  * <p>
  * 當加載的網頁需要重定向的時候就會回調這個函數告知我們應用程序是否需要接管控制網頁加載,如果應用程序接管,
  *并且return true意味著主程序接管網頁加載,如果返回false讓webview自己處理。
  * </p>
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param url
  *            即將要被加載的url
  * @return true 當前應用程序要自己處理這個url, 返回false則不處理。 注:"post"請求方式不會調用這個回調函數
  */
 @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 當內核開始加載訪問的url時,會通知應用程序,對每個main frame
  * 這個函數只會被調用一次,頁面包含iframe或者framesets 不會另外調用一次onPageStarted,
     * 當網頁內內嵌的frame 發生改變時也不會調用onPageStarted。
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param url
  *            即將要被加載的url
  * @param favicon
  *            如果這個favicon已經存儲在本地數據庫中,則會返回這個網頁的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:頁面開始加載");
 }
 
 /**
  * onPageFinished 當內核加載完當前頁面時會通知我們的應用程序,這個函數只有在main
  * frame情況下才會被調用,當調用這個函數之后,渲染的圖片不會被更新,如果需要獲得新圖片的通知可以使用@link
  * WebView.PictureListener#onNewPicture。 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個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:頁面加載結束");
 }
 
 /**
  * onLoadResource 通知應用程序WebView即將加載url 制定的資源
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個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:加載資源指定的網址");
 }
 
 /**
  * shouldInterceptRequest
  * 通知應用程序內核即將加載url制定的資源,應用程序可以返回本地的資源提供給內核,若本地處理返回數據,內核不從網絡上獲取數據。
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param url
  *            raw url 制定的資源
  * @return 返回WebResourceResponse包含數據對象,或者返回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>
  * 當瀏覽器訪問制定的網址發生錯誤時會通知我們應用程序 參數說明:
  * </p>
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param errorCode
  *            錯誤號可以在WebViewClient.ERROR_* 里面找到對應的錯誤名稱。
  * @param description
  *            描述錯誤的信息
  * @param failingUrl
  *            當前訪問失敗的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");
 }
 
 /**
  * 如果瀏覽器需要重新發送POST請求,可以通過這個時機來處理。默認是不重新發送數據。 參數說明
  * 
  * @param view
  *            接收WebViewClient的webview
  * @param dontResend
  *            瀏覽器不需要重新發送的參數
  * @param resend
  *            瀏覽器需要重新發送的參數
  */
 @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
  * 通知應用程序可以將當前的url存儲在數據庫中,意味著當前的訪問url已經生效并被記錄在內核當中。這個函數在網頁加載過程中只會被調用一次。
  * 注意網頁前進后退并不會回調這個函數。
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param url
  *            當前正在訪問的url
  * @param isReload
  *            如果是true 這個是正在被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");
 }
 
 /**
  * 當網頁加載資源過程中發現SSL錯誤會調用此方法。我們應用程序必須做出響應,是取消請求handler.cancel(),還是繼續請求handler.
  * proceed();內核的默認行為是handler.cancel();
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param handler
  *            處理用戶請求的對象。
  * @param error
  *            SSL錯誤對象
  * 
  */
 @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 通知應用程序WebView接收到了一個Http
  * auth的請求,應用程序可以使用supplied 設置webview的響應請求。默認行為是cancel 本次請求。
  * 
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param handler
  *            用來響應WebView請求的對象
  * @param host
  *            請求認證的host
  * @param realm
  *            認真請求所在的域
  */
 @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
  * 提供應用程序同步一個處理按鍵事件的機會,菜單快捷鍵需要被過濾掉。如果返回true,webview不處理該事件,如果返回false,
  * webview會一直處理這個事件,因此在view 鏈上沒有一個父類可以響應到這個事件。默認行為是return false;
  * 
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param event
  *            鍵盤事件名
  * @return 如果返回true,應用程序處理該時間,返回false 交由webview處理。
  */
 @Override
 public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
  Log.i(TAG, "shouldOverrideKeyEvent");
  // TODO Auto-generated method stub
  return super.shouldOverrideKeyEvent(view, event);
 }
 
 /**
  * 通知應用程序webview 要被scale。應用程序可以處理改事件,比如調整適配屏幕。
  */
 @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 通知應用程序有個自動登錄的帳號過程
  * 
  * 參數說明:
  * 
  * @param view
  *            請求登陸的webview
  * @param realm
  *            賬戶的域名,用來查找賬戶。
  * @param account
  *            一個可選的賬戶,如果是null 需要和本地的賬戶進行check, 如果是一個可用的賬戶,則提供登錄。
  * @param args
  *            驗證制定參數的登錄用戶
  */
 @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的對話框,網站圖標,網站tltle,加載進度等。

webView.setWebChromeClient(new WebChromeClient() {
 /**
  * onProgressChanged 通知應用程序當前網頁加載的進度。
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebChromeClient的的webview實例
  * @param newProgress
  *            webview接受的進度
  */
 @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===");
  }
 }
 
 /**
  * 當document 的title變化時,會通知應用程序
  * 
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的webview實例
  * @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);
 
 }
 
 /**
  * 當前頁面有個新的favicon時候,會回調這個函數。 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param icon
  *            當前頁面的favicon 注:很多時間不會跳轉到此回調函數,因為很多網站設置了icon,沒有設置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);
 }
 
 /**
  * 通知應用程序 apple-touch-icon的 url
  * 
  * 參數說明:
  * 
  * @param view
  *            接收WebViewClient的那個實例,前面看到webView.setWebViewClient(new
  *            MyAndroidWebViewClient()),即是這個webview。
  * @param url
  *            apple-touch-icon 的服務端地址
  * @param precomposed
  *            如果precomposed 是true 則touch-icon是預先創建的
  * 
  *            Tips
  * 
  *            如果應用程序需要這個icon的話, 可以通過這個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請求得到focus,發生這個主要是當前webview不是前臺狀態,是后臺webview。
  */
 @Override
 public void onRequestFocus(WebView view) {
  // TODO Auto-generated method stub
  super.onRequestFocus(view);
  Log.i(TAG, "====onRequestFocus====");
 }
 
 /**
  * 覆蓋默認的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("對話框").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;
   }
  });
  // 禁止響應按back鍵的事件
  builder.setCancelable(false);
  AlertDialog dialog = builder.create();
  dialog.show();
  result.confirm();// 因為沒有綁定事件,需要強行confirm,否則頁面會變黑顯示不了內容。
  return true;
  // return super.onJsAlert(view, url, message, result);
 }
 
 /**
  * 覆蓋默認的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("對話框").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之類的按鍵,避免按鍵后導致對話框消息而頁面無法再彈出對話框的問題
  builder.setOnKeyListener(new OnKeyListener() {
   @Override
   public boolean onKey(DialogInterface dialog, int keyCode,
     KeyEvent event) {
    Log.v("onJsConfirm", "keyCode==" + keyCode + "event=" + event);
    return true;
   }
  });
  // 禁止響應按back鍵的事件
  // builder.setCancelable(false);
  AlertDialog dialog = builder.create();
  dialog.show();
  return true;
 }
 
 /**
  * 覆蓋默認的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("對話框").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之類的按鍵,避免按鍵后導致對話框消息而頁面無法再彈出對話框的問題
  builder.setOnKeyListener(new OnKeyListener() {
   public boolean onKey(DialogInterface dialog, int keyCode,
     KeyEvent event) {
    Log.v("onJsPrompt", "keyCode==" + keyCode + "event=" + event);
    return true;
   }
  });
 
  // 禁止響應按back鍵的事件
  // builder.setCancelable(false);
  AlertDialog dialog = builder.create();
  dialog.show();
  return true;
  // return super.onJsPrompt(view, url, message, defaultValue,
  // result);
 }
});
  1. 處理JavaScript與Android代碼的交互 如果網頁中包含JavaScript,并且需要與Android代碼進行交互,可以使用WebView的addJavascriptInterface方法來實現。在Android代碼中定義一個對象,并在JavaScript中調用這個對象的方法。

編寫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調用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調用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 返回的結果
                            Toast.makeText(MainActivity.this,value,Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });
        
        initWebView();
    }
 
 
    public void initWebView() {
        //啟用JS腳本
        webview.getSettings().setJavaScriptEnabled(true);
        // 設置允許JS彈窗
        webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
 
        //加載網頁
        webview.loadUrl("file:///android_asset/index.html");
 
        // 由于設置了彈窗檢驗調用結果,所以需要支持js對話框
        // webview只是載體,內容的渲染需要使用webviewChromClient類去實現
        // 通過設置WebChromeClient對象處理JavaScript的對話框
        //設置響應js 的Alert()函數
        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默認使用第三方或系統默認瀏覽器打開網頁的行為,使網頁用WebView打開
        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的時候控制去WebView打開,為false調用系統瀏覽器或第三方瀏覽器
                view.loadUrl(uri);
                return true;
            }
        });
    }
}

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

js調用Android方法: 通過WebView的addJavascriptInterface()進行對象映射

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
 </head>
 <body>
   <button style="width:100%;height:50px; margin-top: 100px;" onclick="aa.showToast('哈哈哈')">js調用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://繼承自Object類,別名是aa,即在html可以直接用aa.showToast(\"哈哈哈\")來調用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() {
        // 設置與Js交互的權限
        webview.getSettings().setJavaScriptEnabled(true);
 
        //將java對象暴露給JavaScript腳本
        //參數1:java對象,里面定義了java方法
        //參數2:Java對象在js里的對象名,可以看作第一個參數的別名,可以隨便取,即在html可以直接用aa.showToast("哈哈哈")來調用android方法
        webview.addJavascriptInterface(new MyObject(), "aa");//AndroidtoJS類對象映射到js的test對象
 
        //加載網頁
        webview.loadUrl("file:///android_asset/index2.html");
    }
 
    //繼承自Object類,別名是aa,即在html可以直接用aa.showToast("哈哈哈")來調用android方法
    public class MyObject extends Object {
        // 定義JS需要調用的方法
        // 被JS調用的方法必須加入@JavascriptInterface注解
        @JavascriptInterface
        public void showToast(String name){
            Toast.makeText(MainActivity2.this, "您好!"+name, Toast.LENGTH_SHORT).show();
        }
    }
}
  1. 頁面返回
@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();
//優先使用緩存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 
//只在緩存中讀取
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
/不使用緩存
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
  1. 清除緩存
//清除網頁訪問留下的緩存,由于內核緩存是全局的因此這個方法不僅僅針對webview而是針對整個應用程序.
webview.clearCache(true);
//清除當前webview訪問的歷史記錄,只會webview訪問歷史記錄里的所有記錄除了當前訪問記錄.
webview.clearHistory (); 
//這個api僅僅清除自動完成填充的表單數據,并不會清除WebView存儲到本地的數據。
webview.clearFormData ();

注意

WebView在使用過程中存在一些常見問題「性能問題」WebView加載H5頁面時,由于JS解析過程復雜、前端頁面涉及較多的JS代碼文件,以及Android機型碎片化導致的手機硬件性能差異,可能會導致頁面加載速度較慢。每次加載H5頁面都會產生較多的網絡請求,包括HTML的主URL請求以及HTML引用的外部JS、CSS、字體文件、圖片文件等,會耗費一定的流量和時間。

「內存管理問題」WebView是依附于Activity的,而Activity的生命周期和WebView啟動的線程的生命周期可能不一致,可能導致WebView一直持有對Activity的引用而無法釋放,從而引發內存泄漏問題。WebView使用不當,可能會導致應用程序在運行過程中占用大量內存,甚至引發應用崩潰。

「安全漏洞」WebView中可能存在一些安全漏洞,如遠程代碼執行漏洞、密碼明文存儲漏洞和域控制不嚴格漏洞等??赡軐е鹿粽呃肳ebView執行任意Java對象的方法,竊取用戶信息,甚至控制用戶設備。

「兼容性問題」不同版本的Android系統或不同品牌的手機可能存在WebView兼容性問題。例如,一些機型可能不支持WebGL,導致部分網頁內容無法正常顯示。WebView在加載某些特定格式的網頁或執行某些特定操作時也可能出現兼容性問題。

責任編輯:武曉燕 來源: 沐雨花飛蝶
相關推薦

2025-06-10 01:55:00

代碼Promise

2025-07-02 07:05:00

多線程Java開發

2017-03-22 09:44:04

DevOps轉型陷阱實踐

2025-05-12 01:33:00

異步函數Promise

2018-11-18 16:31:14

Kubernetes監控容器

2021-02-28 13:19:42

大數據IT數據管理

2011-12-31 10:18:33

響應設計

2023-07-25 11:22:31

2022-03-08 09:26:41

物聯網安全物聯網

2024-03-08 10:50:44

Spring技術應用程序

2013-12-31 09:26:31

JavaScript技巧

2025-02-17 01:00:00

.NET性能服務器

2025-04-11 03:00:55

2021-08-24 10:51:19

多云云計算云平臺

2018-11-15 08:07:33

Kubernetes監控IT團隊

2014-12-17 09:46:30

AndroidListView最佳實踐

2010-07-06 09:07:09

2018-08-02 15:09:20

PyTorch深度學習神經網絡

2013-05-17 11:43:55

主數據數據管理

2021-03-01 15:52:14

開源開源軟件陷阱
點贊
收藏

51CTO技術棧公眾號

国产精品自拍小视频| 亚洲精品自在久久| 激情五月六月婷婷| 天天躁日日躁狠狠躁伊人| 日韩午夜av| 在线播放国产一区二区三区| 日韩欧美理论片| 黄视频网站在线观看| 欧美—级在线免费片| 91国产丝袜在线放| 五月天婷婷激情| 91综合网人人| 日韩h在线观看| 中文字幕一区久久| 久久人体大尺度| 国产精品不卡一区| 好吊色欧美一区二区三区四区 | 91福利在线看| 国产日韩第一页| 男女污污视频在线观看| 国产一区二区三区美女| 国产高清在线不卡| 国产一级黄色av| 国产高清一区二区| 亚洲欧美另类人妖| 亚洲女则毛耸耸bbw| 精品三区视频| 欧美三级xxx| 亚洲中文字幕无码一区二区三区| 成人激情电影在线看| 99精品久久只有精品| 91青青草免费在线看| 这里只有精品免费视频| 国产精品美女| 午夜精品一区二区三区在线视| 情侣偷拍对白清晰饥渴难耐| 国产精品一区二区三区av麻 | 在线视频婷婷| 久久久精品黄色| 国产一区免费| 黄色一级大片在线免费看国产一| 久久99蜜桃精品| 国产精品久久久久久久午夜| av大全在线观看| 一区在线视频观看| 久久免费视频网站| 久久伊人成人网| 午夜久久一区| 欧美日韩国产成人在线观看| 顶臀精品视频www| 欧美第一精品| 久久久精品欧美| 在线免费看av网站| 91亚洲成人| 久久久精品电影| 日本a级片视频| 自产国语精品视频| 久久久精品美女| 欧美激情图片小说| 午夜精品电影| 午夜精品久久久久久久99热| 久久夜色精品亚洲| 亚洲欧美不卡| 国产精品成人在线| 最好看的日本字幕mv视频大全| 日韩成人一级大片| 国产在线观看91精品一区| 一级黄色大片网站| 久久国产日韩欧美精品| 91精品国产综合久久香蕉| 中文字幕人妻丝袜乱一区三区| 日本免费在线视频不卡一不卡二| 国产精品久久久久久亚洲影视| 亚洲精品91天天久久人人| 美女视频一区二区| 91夜夜未满十八勿入爽爽影院| 97人妻人人澡人人爽人人精品| 国产一区二区三区免费播放| 国产日韩二区| 国内精品在线视频| 亚洲图片你懂的| 免费的一级黄色片| 亚洲人成在线网站| 欧美群妇大交群中文字幕| 男人添女人荫蒂国产| 国产一区二区三区亚洲| 亚洲性无码av在线| 日韩视频中文字幕在线观看| 亚洲激情亚洲| 国产精品视频yy9099| 精品人妻无码一区二区色欲产成人| 成人国产精品免费| 亚洲v国产v在线观看| 羞羞的视频在线看| 色综合久久中文综合久久牛| 不卡的在线视频| 卡一精品卡二卡三网站乱码| 国产亚洲成av人片在线观看桃| www.av免费| 国产一区二区三区的电影| 国产精品伦子伦免费视频| 国产黄色片免费| 久久久久国产一区二区三区四区| 国产美女视频免费| 美女扒开腿让男人桶爽久久软| 在线观看免费一区| 亚洲午夜久久久久久久久| 日韩大片在线| 97视频人免费观看| 国产日韩免费视频| 久久久激情视频| 久久亚洲a v| 国产成人免费| 精品一区二区三区三区| 91人妻一区二区三区蜜臀| 羞羞答答国产精品www一本| 91夜夜未满十八勿入爽爽影院| 国内av一区二区三区| 亚洲成人动漫在线观看| 日韩欧美中文在线视频| 国产欧美日韩视频在线| 国语对白做受69| 国产免费黄色大片| 亚洲国产精品99久久久久久久久 | 精品国产伦一区二区三区观看体验| 国产极品视频在线观看| 性xx色xx综合久久久xx| 国产成人av一区二区三区| www.av在线播放| 色综合色狠狠天天综合色| xxxxxx黄色| 伊人成人在线视频| 91精品黄色| 高清全集视频免费在线| 欧美日韩精品综合在线| 永久免费av无码网站性色av| 性伦欧美刺激片在线观看| 国内精品一区二区| 91九色在线播放| 亚洲电影免费观看高清完整版在线| 午夜精品一区二区三区视频| 狠狠色丁香婷婷综合久久片| 亚洲国产一区在线| 精品久久毛片| 日韩在线观看免费av| 在线免费av网| 中文字幕一区免费在线观看 | 成人看片毛片免费播放器| 亚洲跨种族黑人xxx| 在线能看的av| 久久久久久久久久久久久女国产乱| 精品欧美一区免费观看α√| 男人的天堂久久| 97超级碰在线看视频免费在线看 | 久久国产精品影视| 国产人妖一区二区| 亚洲黄色免费电影| 亚洲欧美日韩偷拍| 在线综合亚洲| 欧美大香线蕉线伊人久久| 天天综合网站| 日韩在线视频一区| 国内老熟妇对白xxxxhd| 亚洲综合自拍偷拍| 一本色道综合久久欧美日韩精品 | 自拍偷拍21p| 99久久精品网站| 91精品天堂| av剧情在线观看| 亚洲天堂视频在线观看| 中文字幕制服诱惑| 亚洲精品国产第一综合99久久| 久久久久中文字幕亚洲精品| 精久久久久久| 日韩av电影免费在线| 亚洲精品大全| 久久人人爽人人爽人人片av高清| 亚洲区小说区图片区| 欧美亚洲国产bt| www欧美com| 91免费看片在线观看| 天天综合网日韩| 欧美久久成人| 欧美12av| 国产免费av国片精品草莓男男| 高清视频欧美一级| 大片免费播放在线视频| 日韩欧美另类在线| 天堂网视频在线| 亚洲欧美偷拍三级| 国产精品无码网站| 国内精品伊人久久久久影院对白| 日本一本中文字幕| 精品九九在线| 豆国产97在线| 成人免费在线观看视频| 久久久久久91| 91美女视频在线| 亚洲精品wwww| aa视频在线免费观看| 日本丶国产丶欧美色综合| 丰满少妇被猛烈进入一区二区| 久久众筹精品私拍模特| 国内精品国产三级国产aⅴ久| 国产一区二区三区久久久久久久久| 最新国产精品久久| 国产一区二区三区网| 成人羞羞视频免费| 欧美成人三级| 国产国语刺激对白av不卡| av伦理在线| 欧美成人国产va精品日本一级| 欧美日韩在线中文字幕| 精品欧美一区二区在线观看| 亚洲无码久久久久| 日韩欧美国产成人| 国产 日韩 欧美 成人| 亚洲欧美一区二区视频| 久久久精品成人| 久久中文字幕电影| 午夜男人的天堂| 国产69精品久久99不卡| 久久久精品高清| 奇米影视一区二区三区小说| 欧美韩国日本在线| 在线日韩av| 波多野结衣 作品| 亚洲国产不卡| 在线观看国产一区| 欧美成人激情| 亚洲精品一品区二品区三品区| 欧美极品在线观看| 蜜桃麻豆www久久国产精品| 超碰成人免费| 国产精品乱码视频| 91精品入口| 51成人做爰www免费看网站| 97久久精品一区二区三区的观看方式 | 日本精品600av| 久久成人国产精品| 成人在线观看亚洲| www.美女亚洲精品| 成人在线视频亚洲| 欧美夫妻性视频| 久久www人成免费看片中文| 九九久久国产精品| 九色91在线| 97精品国产97久久久久久| 国产白丝在线观看| 国模极品一区二区三区| 免费v片在线观看| 欧美在线激情网| 欧美成人ⅴideosxxxxx| 国产成人aa精品一区在线播放| 欧美羞羞视频| 国产精品一区二区性色av| 欧美xnxx| 91天堂在线观看| 88久久精品| 欧美二区在线| 99久久99久久精品国产片桃花| 日本三级福利片| 国产精品magnet| 大j8黑人w巨大888a片| 久久久久国产精品一区二区| 国产精品乱码久久久久| 麻豆精品久久久| 特种兵之深入敌后| av影院午夜一区| 欧美做受xxxxxⅹ性视频| 国产精品美女视频| 欧美国产精品一二三| 亚洲成人激情自拍| 香蕉污视频在线观看| 欧美精品久久久久久久久老牛影院| 国产欧美久久久精品免费| 欧美xxxxxxxx| 国产午夜在线视频| 久久成人精品一区二区三区| а√天堂中文资源在线bt| 国产97在线亚洲| 国产欧美视频在线| 九色综合日本| 婷婷久久一区| 鲁一鲁一鲁一鲁一澡| 蜜桃久久精品一区二区| 人妻精油按摩bd高清中文字幕| 91视频91自| 成年人午夜剧场| 色天天综合色天天久久| 国产成人a人亚洲精品无码| 精品夜色国产国偷在线| av毛片在线看| 日本电影亚洲天堂| 日韩精品视频中文字幕| 欧洲精品一区色| 欧美精品国产| 污片在线免费看| av电影在线观看一区| 国产黄色录像片| 欧美三级免费观看| 亚洲精品久久久狠狠狠爱 | 麻豆影视国产在线观看| 777午夜精品福利在线观看| 精品69视频一区二区三区| 国产专区一区二区| 亚洲成人三区| 一级片视频免费观看| 99re这里都是精品| 亚洲av鲁丝一区二区三区| 欧美三级资源在线| 无码精品人妻一区二区| 久久99亚洲精品| 婷婷激情成人| 日韩三级在线播放| 亚洲欧美日韩一区在线观看| 国产一精品一aⅴ一免费| 国产精品传媒视频| 做爰视频毛片视频| 亚洲色图第一页| 三妻四妾的电影电视剧在线观看| 亚洲一区二区中文字幕| 欧美日韩伦理| 国产精品亚洲二区在线观看| 成人av在线一区二区三区| 欧美日韩一级大片| 69堂成人精品免费视频| 91电影在线播放| 国产精品第8页| 精品不卡一区| 无人在线观看的免费高清视频| 91色porny蝌蚪| 日韩av黄色片| 亚洲第一精品福利| sm性调教片在线观看| 成人黄色片视频网站| 欧美 日韩 国产 一区| 91插插插影院| 亚洲人成伊人成综合网小说| 国产精品毛片一区二区在线看舒淇| 永久免费看mv网站入口亚洲| 婷婷激情一区| 日韩欧美在线电影| 蜜臀久久99精品久久久久宅男| 亚洲最大成人综合网| 欧美性一区二区| 日本中文字幕在线看| 国产日韩欧美视频| 91成人看片| 久久aaaa片一区二区| 亚洲综合另类小说| 黄色av免费观看| 91成人在线播放| 久久超碰99| 制服丝袜中文字幕第一页| 亚洲女人****多毛耸耸8| 国内精品国产成人国产三级| 久久男人资源视频| 自拍欧美一区| 亚洲一级片网站| 亚洲免费在线播放| 欧美一区二区黄片| 日本久久亚洲电影| 999成人精品视频线3| 亚洲AV无码久久精品国产一区| 亚洲国产视频直播| 麻豆av电影在线观看| 国产一区香蕉久久| 亚洲第一黄网| 日本二区在线观看| 69av一区二区三区| av免费在线视| 亚洲精品一区二区三区av| 国产一区二区久久| 国产成人免费观看视频| 国产一区二区三区在线视频| 国产日韩一区二区三免费高清| 男人天堂手机在线视频| 国产网站一区二区三区| 99在线无码精品入口| 日本电影亚洲天堂| 综合国产精品| 国产三级av在线播放| 欧美一区二区三区影视| 亚洲福利影院| 午夜啪啪福利视频| 26uuu精品一区二区三区四区在线| 欧美一级做a爰片免费视频| 欧美高清自拍一区| av亚洲免费| 午夜不卡久久精品无码免费| 欧美色图免费看| 97在线视频免费观看完整版| 亚洲国产精品毛片| av中文字幕一区| 一区二区美女视频| 欧美中文在线观看| 欧美午夜不卡影院在线观看完整版免费| 欧美激情aaa| 亚洲福利小视频|