Android开发之路之 webview
生活随笔
收集整理的這篇文章主要介紹了
Android开发之路之 webview
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
公眾號:
歡迎關注我的個人公眾號,來一起交流Android 開發知識
一、簡介 本來不想專門找一節來介紹webview技術的,因為現在對于混合開發有很多的框架比如RN和FLutter,但是這些框架對于一些webview頁面比較少的項目來說顯得重量級了一些。因此還是單獨整理一篇出來,供以后項目的參考及學習。寫這篇文章確實花了很長的時間,一方面覺得很混亂,api很多都想說一點,另一方面覺得以后這些api到底能不能用到。因此有些章節說的比較籠統,我也給出了參考的博客地址,對于想深入了解的同學可以參考這些博客。 WebView在Android平臺上用于顯示網頁。WebView是一個基于WebKit引擎、展現Web頁面的控件,Android的WebView在低版本和高版本采用了不同的WebKit版本內。4.4后WebView內部實現并不是完全使用Chrome內核,而是部分使用了Chrome內核,其他都是與Chrome不相同的。 二、WebView的使用 webview的使用有兩種方式:一種是直接顯示網頁內容;另一種就是與JS進行交互。 2.1基本使用 2.1.1、webview加載在線的URL地址。 public class MainActivity extends AppCompatActivity { ??? private WebView mWebView; ??? @Override ??? protected void onCreate(Bundle savedInstanceState) { ??????? super.onCreate(savedInstanceState); ? ? ? ??setContentView(R.layout.activity_main); ??????? mWebView=(WebView)findViewById(R.id.webview); ? ? ? ? mWebView.loadUrl("http://www.baidu.com"); ??????? mWebView.setWebViewClient(new WebViewClient(){ ??????????? @Override ??????????? public boolean shouldOverrideUrlLoading(WebView view,?String?url) { ?? ??? ??? ??? ?mWebView.loadUrl(url); ??????????????? return true; ??????????? } ??????? }); ??????? ??? } ################ ?布局文件 ?############################ <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout ??? xmlns:android="http://schemas.android.com/apk/res/android" ??? xmlns:app="http://schemas.android.com/apk/res-auto" ??? xmlns:tools="http://schemas.android.com/tools" ??? android:layout_width="match_parent" ??? android:layout_height="match_parent"+? ? === ??? tools:context=".MainActivity"> ??? <WebView ??????? android:id="@+id/webview" ??????? android:layout_width="wrap_content" ??????? android:layout_height="wrap_content" ??????? app:layout_constraintBottom_toBottomOf="parent" ??????? app:layout_constraintLeft_toLeftOf="parent" ??????? app:layout_constraintRight_toRightOf="parent" ??????? app:layout_constraintTop_toTopOf="parent"/> </android.support.constraint.ConstraintLayout> 權限: <use-permission android:name=“android.permission.INTERNET”/> 注意:1、webview加載的url地址必須包含http://或者https://協議完整的域名地址,webview不會默認填充。 2、系統會默認通過手機瀏覽器去打開網頁,為了能夠直接通過webview顯示網頁,必須設置webviewclient.此 ?? 外還必須要添加相關權限。 2.1.2、加載本地的html文件。 加載本地的html文件有兩種,一種是加載本地assets目錄下的文件,這種html文件會打包到APK文件中,另一種是加載手機本地sdcard下的html文件。加載兩種類型的html文件同樣調用loadurl()方法,只不過url地址則需要加些前綴:- 如果html文件存放在assets目錄下則前綴為:file:///android_asset/+你的html文件名.html(注意這里有三個斜杠)
- 如果html文件存放在sdcard下,則前綴為:content://com.android.htmlprovider/sdcard/+你的html文件名.html(注意:content前綴可能會導致異常,可以使用file:///sdcard/+你的html文件.html)你可以在手機瀏覽器中將“ file:///sdcard/+你的html文件.html”復制到訪問欄可以測試能不能訪問到。
?
官方文檔給出的解釋: 我們可以通過這個方法來控制訪問新的url,如果沒有設置webviewclient,那么webview就會通過ActivityManager 為這個url選擇適當的處理方式,如果設置了webviewclient,返回true表示由APP層處理URL,如果返回false表示由 當前 webview處理url。對于使用post請求的,不會調用此方法。 簡而言之,如果我們想攔截某個url的訪問就可以重新這個方法。比如我們想攔截所有包含”blog.csdn.net“的地址,重定向訪問”www.baidu.com“可以怎么寫呢? webview.setWebViewClient(new WebViewClient(){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??@Override ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??public boolean shouldOverrideUrlLoading(WebView view, String url) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????????????????????? if(url.contains("blog.csdn.net")){ ????????????????????????????????????????????? view.loadUrl("http://www.baidu.com"); ????????????????????????????????????????? } else{ ????????????????????????????????????????????? view.loadUrl(url); ????????????????????????????????????????? } ????????????????????????????????????????? return true; ????????????????????????????????????? } ???????????????????????????????? } ??????? ); ??????? webview.loadUrl("https://blog.csdn.net/FlyRabbit_1"); ??? } 注意:這里我們返回的是true,在之前我們已經知道true表示攔截了該url,由APP層自己處理URL。對于其他的url如果不包含 ” https://blog.csdn.net/“這個地址的一定要在else中重寫view.load(url)方法,否則出現點擊鏈接沒有效果的情況。如果返回的是false我們就可以不進行判斷else中的view.loadUrl(url)的處理,原因我們前面已經說過了。 webview.setWebViewClient(new WebViewClient(){ ??????????????????????????@Override ??????????????????????????public boolean shouldOverrideUrlLoading(WebView view, String url) { ? ? ? ? ? ???? ??? ??? ????????????????????????????????????????? if(url.contains("blog.csdn.net")){ ????????????????????????????????????????????? view.loadUrl("http://www.baidu.com"); ????????????????????????????????????????? }? ????????????????????????????????????????? return false; ????????????????????????????????????? } ???????????????????????????????? } ??????? ); ??????? webview.loadUrl("https://blog.csdn.net/FlyRabbit_1"); ??? } 所以我們一般建議return false只關心攔截的url,對于其他的url不關心處理。 5.2 頁面處理 5.2.1 loading動畫 加載webview添加loading動畫需要使用webviewclient的兩個方法,onPageStarted();onPageFinished(); webview.setWebViewClient(new WebViewClient(){ ? ? ? ? ? ? ? ? ? ? ? ? ??@Override ? ? ? ? ? ? ? ? ? ? ? ? ?public boolean shouldOverrideUrlLoading(WebView view, String url){ ????????????????????????????????????????? if(url.contains("blog.csdn.net")){ ????????????????????????????????????????????? view.loadUrl("http://www.baidu.com"); ????????????????????????????????????????? } ????????????????????????????????????????? return false; ????????????????????????????????????? } ?? ??? ??? ??? ? ??????????????????????????@Override ?????????????????????????public void onPageStarted(WebView view, String url, Bitmap favicon) { ????????????????????????????????????????? super.onPageStarted(view, url, favicon); ????????????????????????????????????????? mProgress.show(); ????????????????????????????????????? } ????????????????????????????????????? @Override ????????????????????????????????????? public void onPageFinished(WebView view, String url) { ????????????????????????????????????????? super.onPageFinished(view, url); ????????????????????????????????????????? mProgress.dismiss(); ????????????????????????????????????? } ???????????????????????????????? } ??????? ); ??????? webview.loadUrl("https://blog.csdn.net/"); ??? } 5.2.2 錯誤頁面加載 我們可以在本地自定義一個錯誤頁面,調用onRecivedError()方法這個方法需要我們傳入四個參數,webview對象,錯誤碼(加載url返回的錯誤碼),錯誤描述,已經失敗地址。
我們只需要在這個方法中加載我們自定義好的錯誤頁面即可。 @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { // ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?super.onReceivedError(view, request, error); ???????????????????????????????????????? view.loadUrl("file:///android_asset/error.html"); ???????????????????????????????????? } 5.2.3onRecivedSSLError(); 這個方法是在當請求HTTPS通信的網址出現錯誤的時候的回調。默認的請求方式為super.onReceivedSslError(view, handler, error)。如果取消加載頁面我們可以調用handler.cancle(),繼續加載我們可以調用handler.proceed()來繼續加載錯誤的頁面。 還有一點要說明一下,當出現SSL錯誤的時候webview默認是取消加載頁面的,只有我們設置handler.proceed()才能繼續加載頁面。另外當SSL發生錯誤的時候onRecivedError不會產生回調。 5.2.4webviewclient的其他函數 /** * 在加載頁面資源時會調用,每一個資源(比如圖片)的加載都會調用一次 */ public void onLoadResource(WebView view, String url) /** *??(WebView發生改變時調用) *??可以參考http://www.it1352.com/191180.html的用法 */ public void onScaleChanged(WebView view, float oldScale, float newScale) /** * 重寫此方法才能夠處理在瀏覽器中的按鍵事件。 * 是否讓主程序同步處理Key Event事件,如過濾菜單快捷鍵的Key Event事件。 * 如果返回true,WebView不會處理Key Event, * 如果返回false,Key Event總是由WebView處理。默認:false */ public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) /** * 是否重發POST請求數據,默認不重發。 */ onFormResubmission(WebView view, Message dontResend, Message resend) /** * 更新訪問歷史 */ doUpdateVisitedHistory(WebView view, String url, boolean isReload) /** * 通知主程序輸入事件不是由WebView調用。是否讓主程序處理WebView未處理的Input Event。 * 除了系統按鍵,WebView總是消耗掉輸入事件或shouldOverrideKeyEvent返回true。 * 該方法由event 分發異步調用。注意:如果事件為MotionEvent,則事件的生命周期只存在方法調用過程中, * 如果WebViewClient想要使用這個Event,則需要復制Event對象。 */ onUnhandledInputEvent(WebView view, InputEvent event) /** * 通知主程序執行了自動登錄請求。 */ onReceivedLoginRequest(WebView view, String realm, String account, String args) /** * 通知主程序:WebView接收HTTP認證請求,主程序可以使用HttpAuthHandler為請求設置WebView響應。默認取消請求。 */ onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) /** * 通知主程序處理SSL客戶端認證請求。如果需要提供密鑰,主程序負責顯示UI界面。 * 有三個響應方法:proceed(), cancel() 和 ignore()。 * 如果調用proceed()和cancel(),webview將會記住response, * 對相同的host和port地址不再調用onReceivedClientCertRequest方法。 * 如果調用ignore()方法,webview則不會記住response。該方法在UI線程中執行, * 在回調期間,連接被掛起。默認cancel(),即無客戶端認證 */ onReceivedClientCertRequest(WebView view, ClientCertRequest request) 5.2.5webview的響應事件的處理 如果webview包含多個頁面通常我們點擊返回鍵,會直接finish掉app而不是返回上一個頁面,我們希望回調上個頁面而不是退出瀏覽器該怎么設置呢?在Activity中重寫onKeyDown(int keyCoder,KeyEvent event)方法,返回上一個頁面。 六、webviewChromeClient webviewChromeClient與webviewClient是針對不同webview事件的回調,webviewClient處理各種通知與請求事件,而webviewChromeClient處理js對話框、網站圖標、title、加載進度等等。 我們先看一下webviewChromeClient常用的函數有哪些 /** * 當網頁調用alert()來彈出alert彈出框前回調,用以攔截alert()函數 */ public boolean onJsAlert(WebView view, String url, String message,JsResult result) /** * 當網頁調用confirm()來彈出confirm彈出框前回調,用以攔截confirm()函數 */ public boolean onJsConfirm(WebView view, String url, String message,JsResult result) /** * 當網頁調用prompt()來彈出prompt彈出框前回調,用以攔截prompt()函數 */ public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) /** * 打印 console 信息 */ public boolean onConsoleMessage(ConsoleMessage consoleMessage) /** * 通知程序當前頁面加載進度 */ public void onProgressChanged(WebView view, int newProgress) /* * 通知頁面標題變化 */ nReceivedTitle(WebView view, String title) /* * 通知當前頁面網站新圖標 */ onReceivedIcon(WebView view, Bitmap icon) /* * 通知主程序圖標按鈕URL */ onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) /* * 通知主程序當前頁面將要顯示指定方向的View,該方法用來全屏播放視頻。 */ public interface CustomViewCallback { ???????// 通知當前頁面自定義的View被關閉 ???????public void onCustomViewHidden(); ???} onShowCustomView(View view, CustomViewCallback callback) /* * 與onShowCustomView對應,通知主程序當前頁面將要關閉Custom View */ onHideCustomView() /** * 請求主程序創建一個新的Window,如果主程序接收請求,返回true并創建一個新的WebView來裝載Window,然后添加到View中,發送帶有創建的WebView作為參數的resultMsg的給Target。如果主程序拒絕接收請求,則方法返回false。默認不做任何處理,返回false */ onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) /* * 顯示當前WebView,為當前WebView獲取焦點。 */ onRequestFocus(WebView view) /* * 通知主程序關閉WebView,并從View中移除,WebCore停止任何的進行中的加載和JS功能。 */ onCloseWindow(WebView window) /** * 告訴客戶端顯示離開當前頁面的導航提示框。如果返回true,由客戶端處理確認提示框,調用合適的JsResult方法。如果返回false,則返回默認值true給javascript接受離開當前頁面的導航。默認:false。JsResult設置false,當前頁面取消導航提示,否則離開當前頁面。 */ onJsBeforeUnload(WebView view, String url, String message, JsResult result) /** *通知主程序web內容嘗試使用定位API,但是沒有相關的權限。主程序需要調用調用指定的定位權限申請的回調。更多說明查看GeolocationPermissions相關API。 */ onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback) /* * 通知程序有定位權限請求。如果onGeolocationPermissionsShowPrompt權限申請操作被取消,則隱藏相關的UI界面。 */ onGeolocationPermissionsHidePrompt() /** *通知主程序web內容嘗試申請指定資源的權限(權限沒有授權或已拒絕),主程序必須調用PermissionRequest#grant(String[])或PermissionRequest#deny()。如果沒有覆寫該方法,默認拒絕。 */ onPermissionRequest(PermissionRequest request) /** * 通知主程序相關權限被取消。任何相關UI都應該隱藏掉。 */ onPermissionRequestCanceled(PermissionRequest request) /** * 通知主程序 執行的Js操作超時。客戶端決定是否中斷JavaScript繼續執行。如果客戶端返回true,JavaScript中斷執行。如果客戶端返回false,則執行繼續。注意:如果繼續執行,重置JavaScript超時計時器。如果Js下一次檢查點仍沒有結束,則再次提示。 */ onJsTimeout() /** *當停止播放,Video顯示為一張圖片。默認圖片可以通過HTML的Video的poster屬性標簽來指定。如果poster屬性不存在,則使用默認的poster。該方法允許ChromeClient提供默認圖片。 */ getDefaultVideoPoster() /** * 當用戶重放視頻,在渲染第一幀前需要花費時間去緩沖足夠的數據。在緩沖期間,ChromeClient可以提供一個顯示的View。如:可以顯示一個加載動畫。 */ getVideoLoadingProgressView() /** * 獲取訪問歷史Item,用于鏈接顏色。 */ getVisitedHistory(ValueCallback callback) /** * 通知客戶端顯示文件選擇器。用來處理file類型的HTML標簽,響應用戶點擊選擇文件的按鈕操作。調用filePathCallback.onReceiveValue(null)并返回true取消請求操作。 * FileChooserParams參數的枚舉列表: MODE_OPEN 打開 MODE_OPEN_MULTIPLE 選中多個文件打開 MODE_OPEN_FOLDER 打開文件夾(暫不支持) MODE_SAVE 保存 */ onShowFileChooser(WebView webView, ValueCallback filePathCallback,FileChooserParams fileChooserParams) /** * 解析文件選擇Activity返回的結果。需要和createIntent一起使用。 */ parseResult(int resultCode, Intent data) /** * 創建Intent對象來啟動文件選擇器。Intent支持可訪問的簡單類型文件資源。不支持高級文件資源如live media capture媒體快照。如果需要訪問這些資源或其他高級文件類型資源可以自己創建Intent對象。 */ createIntent() /** * 返回文件選擇模式 */ getMode() /** * 返回可訪問MIME類型數組,如audio/*,如果沒有指定可訪問類型,數組返回為null */ getAcceptTypes() /** * 返回優先的媒體快照類型值如Camera、Microphone。true:允許快照。false,禁止快照。使用getAcceptTypes方法確定合適的capture設備。 */ isCaptureEnabled() /** * 返回文件選擇器的標題。如果為null,使用默認名稱。 */ getTitle() /** *指定默認選中的文件名或為null */ getFilenameHint() 6.1 對話框 我們主要介紹一下通過webviewChromeClient處理一些webview的對話框: 常見的有三種類型的對話框:Alert、Confirm、Prompt對話框。 在這里我們只說一個alert對話框,剩余的兩個實現方法是一樣的。這三個函數的返回值類型都是boolean類型,默認情況下返回的是super()也就是父類的函數為false.返回類型為false是調用的是webview系統的對話框,表示我們沒有攔截系統調用對話框的方法,如果返回值類型為true,表示我們攔截系統彈出的對話框,這個時候我們要注意調用jsResult.confirm()確認或者調用jsResult.cancle()來取消,注意如果我們不調用這兩個方法中的一個,再次點擊按鈕的時候會導致點擊按鈕沒有反應。 我們看一下實現的代碼: html代碼 <!DOCTYPE html> <html lang="en"> <head> ??? <meta charset="UTF-8"> ??? <title>Title</title> </head> <body> <button οnclick="confirm('是否刪除?')">confirm</button> <button οnclick="alert('??警告!系統即將爆炸,立即撤離!')">alert</button> <button οnclick="prompt('請輸入內容')">prompt</button> </body> </html> java調用代碼 package com.sheca.mystudydemo2; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; public class DialogWebView extends AppCompatActivity { ??? private WebView mDialogWebView; ??? @Override ??? protected void onCreate(Bundle savedInstanceState) { ??????? super.onCreate(savedInstanceState); ??????? setContentView(R.layout.activity_dialog_web_view); ??????? initView(); ??? } ??? private void initView() { ??????? mDialogWebView=(WebView)findViewById(R.id.webview_dialog); ??????? WebSettings settings = mDialogWebView.getSettings(); ??????? settings.setJavaScriptEnabled(true); ??????? mDialogWebView.setWebViewClient(new WebViewClient()); ??????? mDialogWebView.setWebChromeClient(new WebChromeClient(){ ??????????? @Override ??????????? public boolean onJsAlert(WebView view, String url, String message, JsResult result) { //??????????????? return super.onJsAlert(view, url, message, result); ??????????????? Toast.makeText(DialogWebView.this,"url"+url+"msg"+message,Toast.LENGTH_SHORT).show(); ??????????????? result.confirm(); ??????????????? return true; ??????????? } ??????????? @Override ??????????? public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { ??????????????? return super.onJsPrompt(view, url, message, defaultValue, result); ??????????? } ??????????? @Override ??????????? public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { ??????????????? return super.onJsConfirm(view, url, message, result); ??????????? } ??????? }); ??????? mDialogWebView.loadUrl("file:///android_asset/dialog.html"); ??? } } 6.2webview的優化 這部分的知識點比較多。 可以從緩存、性能等方面進行優化 可以參考以下博文: 美團技術團隊: https://tech.meituan.com/2017/06/09/webviewperf.html 任玉剛: https://juejin.im/post/5b94ca52e51d450e7d097f38 今日頭條: https://www.jianshu.com/p/85e4f982cbdf 6.3webivew調試: 手機端和PC端都要安裝Chrome瀏覽器,手機端的瀏覽器版本要比PC端的版本低。在Android4.4版本以上調用setWebContentsDebuggingEnabled啟用webView調試,設置代碼如下: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { ????WebView.setWebContentsDebuggingEnabled(true); } 在瀏覽器中輸入:Chrome://inspect進入調試頁面,點擊inspect即可進行調試了。 關于Webview的用到的知識點先介紹到這里。總結
以上是生活随笔為你收集整理的Android开发之路之 webview的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库的增、删、改、查例子
- 下一篇: Visual Studio中的Andro