WebView和JS相互通信
WebView調用JS函數
通用方式,不能獲取JS函數的返回值:
webView.loadUrl("javascript:alert('hello world');");
Android 4.4.及以上系統的WebView專用方式,可以獲取JS函數的返回值:
webView.evaluateJavascript("javascript:add(2,3)", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { Log.i("tag",value); } });
JS調用Native函數
首先,需要通過WebView提供的函數註冊JS對象
public class AndroidJSInterface { @JavascriptInterface //注意,所有可被JS調用的函數,一定要加上@JavascriptInterface,否則JS無法調用 public String handler(String action, String value){ return ""; } }
webView.addJavascriptInterface(new AndroidJSInterface(),"Android");
JS調用Native提供的handler函數的代碼示例如下:
window.Android.handler("sayHello","hello world");
其中Android對象就是我們通過addJavascriptInterface()函數註冊的JS對象
JS調用Native對象,支持有返回值的函數和沒有返回值的函數
JS調用Native函數的時候,建議通過JSON數據來傳值,不然的話,可能會出現調用失敗的情況
比如:
window.Android.handler("sayHello",JSON.stringify(obj));
當JS不再使用Native對象時,可以把Native對象註銷掉
webView.removeJavascriptInterface("Android");
WebView加載URL和HTML字符串的方法
WebView加載指定的url
不帶http header
webView.loadUrl(mUrl);
帶http header
Map<String,String> httpHeaders=new LinkedHashMap<>(); httpHeaders.put("userName","kgdwbb"); webView.loadUrl(mUrl,httpHeaders);
WebView加載html片段
webView.loadData("<h1>title</h1>","text/html; charset=utf-8", null);
這裏有一個問題,就是當webView.loadData()函數第三個參數傳入頁面的字符編碼的時候,不起作用,可能是這個函數本身的問題
我的解決方法就是在第二個參數裏面傳入頁面的字符編碼,比如charset=utf-8,如果不顯示指定頁面的字符編碼,在顯示中文的時候可能會出現亂碼的情況
WebView 發送POST請求
代碼示例:
webView.loadUrl(mUrl); byte[]data="hello world".getBytes(); webView.postUrl(mUrl,data);
WebView Cookie設置
WebView cookie設置一定要在LoadUrl函數之前調用,也就是說在WebView發送網絡請求之前設置。
Android通過CookieManager類來設置Cookie,通過CookieSyncManager類把CookieManager類設置的Cookie數據保存到應用程序/data/data/databases/目錄下的webviewCookiesChromium.db數據庫的cookies表中,這個數據庫屬於全局公共數據庫,對這個數據庫的操作會影響所有WebView,所以在使用完這個數據庫之後,一定要記得清除設置的Cookie數據,以免對其它使用WebView的APP造成影響。
下面是設置WebViewCookie的代碼示例:
public static void
synCookies(Context context, String url,Stringcookie) {
CookieManager cookieManager =CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setCookie(url, cookie);
CookieSyncManager.getInstance().sync();
}
其中cookie是鍵值對類型的字符串,比如cookie="userName=kgdwbb"
下面是清除WebViewCookie的代碼示例:
public static void removeCookie() { CookieManager cookieManager = CookieManager.getInstance(); cookieManager.removeAllCookie(); CookieSyncManager.getInstance().sync(); }
WebView緩存設置
設置WebView緩存的代碼示例如下:
WebSettings webSettings=webView.getSettings(); webSettings.setAppCacheEnabled(true); webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
清除WebView緩存的代碼如下:
webView.clearCache(true);
WebView歷史堆棧
代碼示例如下:
後退
if(webView.canGoBack()){ webView.goBack(); return; }
前進
if(webView.canGoForward()){ webView.goForward(); }
前進或後退
int steps=2; if(webView.canGoBackOrForward(steps)){ webView.goBackOrForward(steps); }
對WebView的堆棧列表進行操作
int backForwardListSize= webView.copyBackForwardList().getSize(); for(int i=0;i<backForwardListSize;i++){ WebHistoryItem item=webView.copyBackForwardList().getItemAtIndex(i); Log.i("tag",item.getUrl()); }
清除WebView歷史堆棧
webView.clearHistory();
WebView啓用文件下載功能
示例代碼如下:
webView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType,long contentLength) { //在這裏寫真正的文件下載的代碼,WebView是不會自動下載文件的 } });
onDownloadStart函數參數說明:
url:就是服務器上文件的url地址或者文件流的地址
userAgent:就是用戶瀏覽器的默認userAgent頭
contentDisposition:url對應的文件類型,當url是服務器上的一個真實文件時,這個值爲空,當url是服務器上可以訪問的文件流時,這個值就會包涵這個文件流的一些基本信息,比如文件名等
mimeType:文件或文件流的類型,比如二進制文件流的mimeType是application/octet-stream
當WebView需要下載網頁裏面的文件時,會調用這個文件下載接口,我們只需要處理這個接口,就可以實現文件下載功能。文件下載功能需要我們自己來實現,WebView默認是不提供文件下載功能的。
讓WebView支持文件選擇
WebView默認不支持表單的file標籤,如果想讓WebView支持表單的file標籤,我們可以這樣做:
webView.setWebChromeClient(new WebChromeClient(){ //當WebView需要顯示文件選擇器時,回調這個函數,我們可以重寫這個函數,加載我們自定義的文件選擇器 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { return super.onShowFileChooser(webView, filePathCallback, fileChooserParams); } });
自定義WebView的錯誤頁面
當WebView在加載網頁的時候如果出現網絡錯誤或者指定的網頁不存在的時候,就會顯示默認的錯誤頁面,如果我們想重寫這個默認的錯誤頁面,可以用下面的方法:
webView.setWebViewClient(new WebViewClient(){ //當WebView發生任何請求錯誤的時候,都會回調這個函數 @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error);
view.loadUrl("file:///android_asset/error.html");//加載自定義的錯誤頁面,前提是這個錯碼頁面一定要存在assets文件夾下面 } });
忽略WebView的SSL證書錯誤
當WebView在加載https網頁的時候,如果網頁存在SSL證書錯誤,比如12306網站的證書錯誤,我們可以忽略網頁的錯誤證書,繼續執行下面的網頁,我們可以這樣做:
webView.setWebViewClient(new WebViewClient(){ //當接收到服務器返回的SSL錯誤時,回調這個函數 @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { super.onReceivedSslError(view, handler, error); handler.proceed();//忽略SSL證書錯誤,繼續執行 } });
攔截WebView的所有網絡請求
要攔截WebView的網絡請求,我們可以這樣做:
webView.setWebViewClient(new WebViewClient(){ //當WebView需要進行任何網絡請求時,都會調用這個函數,我們可以攔截這個函數,做相應的處理 //比如加載緩存的圖片等,這個函數已經被Android 4.4以上的系統廢棄,建議在Android 4.4.及以上的系統使用新的函數 @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { return super.shouldInterceptRequest(view, url); } //當WebView需要進行任何網絡請求時,都會調用這個函數,我們可以攔截這個函數,做相應的處理 //比如加載緩存的圖片等,這個函數屬於Android 4.4及以上的WebView提供的新的函數 @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { WebResourceResponse response=super.shouldInterceptRequest(view,request); return response; } });
重寫WebView H5 video標籤的默認屬性
要想讓WebView裏面的所有H5 video標籤都顯示默認的加載進度和視頻的默認圖片,我們可以這樣做:
webView.setWebChromeClient(new WebChromeClient(){ //獲取video加載時默認顯示的第一張圖片 @Override public Bitmap getDefaultVideoPoster() { return super.getDefaultVideoPoster(); } //獲取視頻加載進度View,所以我們可以在這裏重寫默認的video加載進度 @Override public View getVideoLoadingProgressView() { return super.getVideoLoadingProgressView(); } });
捕捉WebView網頁輸出的所有日誌
要監控網頁輸出的日誌,我們可以這樣做:
webView.setWebChromeClient(new WebChromeClient(){ //當JS輸出日誌時,回調這個函數 @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { return super.onConsoleMessage(consoleMessage); } });
WebView JS計時器設置
默認情況下,WebView的計時器在APP進入後臺的時候還是會執行的。如果想讓APP進入後臺的時候暫時WebView的計時器,在APP進入前臺的時候恢復WebView的計時器,代碼如下:
@Override protected void onPause() { super.onPause(); //當Activity頁面進入後臺的時候,暫停WebView的計時器,這樣WebView頁面的JS計時器就會被暫停 if(webView!=null) webView.pauseTimers(); } @Override protected void onResume() { super.onResume(); //當Activity頁面進入前臺的時候,恢復WebView的計時器,這樣WebView頁面的JS計時器就會被恢復執行 if(webView!=null) webView.resumeTimers(); }
WebView資源釋放
默認情況下,在Activity銷燬的時候,WebView是不會自動釋放它佔用的系統資源的,我們需要手動進行釋放,否則會造成嚴重的內存泄露,
下面是釋放WebView佔用內存的代碼:
@Override protected void onDestroy() { //釋放WebView資源,否則會造成內存泄露 if(webView!=null){ webView.destroy(); webView=null; } super.onDestroy(); }
WebView常用設置功能彙總
WebView啓用JS支持
WebSettingswebSettings=webView.getSettings();
webSettings.setJavaScriptEnabled(true);
WebView啓用雙指縮放功能
webSettings.setDisplayZoomControls(true);//true顯示縮放控件,false隱藏縮放控件
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
WebView啓用https支持
在android 5.0之前,WebView是可以在http環境中直接訪問https資源和服務的,但是在android 5.0及以後,要想在http環境訪問https資源和服務,就需求在WebView中開啓對https的支持,代碼如下:
WebSettingswebSettings=webView.getSettings();
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
WebView啓用本地存儲功能
默認情況下,是無法使用JS的localStorage,sessionStorage對象訪問本地存儲的,下面是開啓WebView本地存儲功能的代碼:
WebSettings webSettings=webView.getSettings();
webSettings.setDomStorageEnabled(true);
WebView啓用LBS定位功能
WebSettings webSettings=webView.getSettings();
webSettings.setGeolocationEnabled(true);
WebView調試設置
這個API只支持Android 4.4及以上的系統,Android 4.4以下的系統默認開啓了WebView的調用功能。
代碼如下:
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.KITKAT){ webView.setWebContentsDebuggingEnabled(true); }
我們可以藉助Chrome瀏覽器來對WebView進行調試
WebSettings類解析
WebSettings webSettings=webView.getSettings(); //開啓WebView對JS腳本的支持 webSettings.setJavaScriptEnabled(true); //設置允許在http環境中訪問https資源和服務 if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){ webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } //設置默認的網頁編碼 webSettings.setDefaultTextEncodingName("utf-8"); //設置JS是否可以打開WebView新窗口 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //設置WebView是否支持多窗口,爲true,需要重寫WebChromeClient#onCreateWindow函數 webSettings.setSupportMultipleWindows(true); //禁止WebView加載網絡圖片 webSettings.setLoadsImagesAutomatically(false); webSettings.setBlockNetworkImage(true); //顯示WebView提供的縮放控件 webSettings.setDisplayZoomControls(true);//true顯示縮放控件,false隱藏縮放控件 webSettings.setBuiltInZoomControls(true); webSettings.setSupportZoom(true); //開啓WebView對數據庫的支持 webSettings.setDatabaseEnabled(true); //開啓WebView的Storage功能,這樣JS的localStorage,sessionStorage對象纔可以使用 webSettings.setDomStorageEnabled(true); //打開WebView的LBS功能,這樣JS的geolocation對象纔可以使用 webSettings.setGeolocationEnabled(true); //設置WebView是否自動保存表單數據 webSettings.setSaveFormData(true); //設置WebView的默認userAgent字符串 webSettings.setUserAgentString(""); //設置是否打開WebView的桌面模式,true是桌面模式,false是移動模式 webSettings.setUseWideViewPort(false); //設置WebView的默認字體,可以通過這個函數,改變WebView的默認字體 webSettings.setStandardFontFamily(""); //設置WebView默認字體的大小 webSettings.setDefaultFontSize(20); //設置WebView支持的最小字體大小 webSettings.setMinimumFontSize(12); //設置頁面的文本縮放倍數 webSettings.setTextZoom(2);
WebViewClient類解析
webView.setWebViewClient(new WebViewClient(){ //當WebView需要加載新的url的時候會調用這個函數,在這個函數裏面我們不能調用任何WebView的LoadUrl函數, //否則,會出現頁面被多次加載,造成JS location.replace函數失效,還有看起來像302問題導致的WebView需要 //多次點擊才能返回的BUG @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return super.shouldOverrideUrlLoading(view, url); } //WebView頁面已經開始加載指定的url @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } //WebView加載完指定的url @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); Log.i("hello",url); view.loadUrl("javascript:window.android.handler('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');"); } //當WebView需要進行任何網絡請求時,都會調用這個函數,我們可以攔截這個函數,做相應的處理 //比如加載緩存的圖片等,這個函數已經被Android 4.4以上的系統廢棄,建議在Android 4.4.及以上的系統使用新的函數 @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { return super.shouldInterceptRequest(view, url); } //當WebView需要進行任何網絡請求時,都會調用這個函數,我們可以攔截這個函數,做相應的處理 //比如加載緩存的圖片等,這個函數屬於Android 4.4及以上的WebView提供的新的函數 @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { WebResourceResponse response=super.shouldInterceptRequest(view,request); return response; } //當WebView發生任何請求錯誤的時候,都會回調這個函數 @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); view.loadUrl("file:///android_asset/error.html");//加載自定義的錯誤頁面 } //當WebView接收到服務器錯誤時,回調這個函數 @Override public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { super.onReceivedHttpError(view, request, errorResponse); } //當WebView表單重新提交時,回調這個函數 @Override public void onFormResubmission(WebView view, Message dontResend, Message resend) { super.onFormResubmission(view, dontResend, resend); } //當WebView需要更新它的url訪問數據庫的時候,回調這個函數 @Override public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { super.doUpdateVisitedHistory(view, url, isReload); } //當接收到服務器返回的SSL錯誤時,回調這個函數 @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { super.onReceivedSslError(view, handler, error); handler.proceed();//忽略SSL證書錯誤,繼續執行 } //當WebView訪問https服務器時,需要客戶端提供對應的SSL證書時,回調這個函數 @Override public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) { super.onReceivedClientCertRequest(view, request); } //當WebView接收到服務器的授權請求時,回調這個函數 @Override public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { super.onReceivedHttpAuthRequest(view, handler, host, realm); } //當發生鍵盤事件時,回調這個函數 @Override public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) { return super.shouldOverrideKeyEvent(view, event); } //當WebView的縮放值發生改變的時候,回調這個函數 @Override public void onScaleChanged(WebView view, float oldScale, float newScale) { super.onScaleChanged(view, oldScale, newScale); } });
WebChromeClient類解析
webView.setWebChromeClient(new WebChromeClient(){ //當WebView加載進度改變時,回調這個函數 @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); } //當通過JS改變html文檔的標題時,回調這個函數 @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); } //當WebView開啓多窗口模式時,需要處理這個函數,這位JS纔可以打開多個WebView窗口 @Override public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg); } //當JS關閉指定的WebView窗口時,回調這個函數 @Override public void onCloseWindow(WebView window) { super.onCloseWindow(window); } //當JS調用alert函數時,回調這個函數 @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { return super.onJsAlert(view, url, message, result); } //當JS調用confirm函數時,回調這個函數 @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { return super.onJsConfirm(view, url, message, result); } //當JS調用prompt函數時,回調這個函數 @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { return super.onJsPrompt(view, url, message, defaultValue, result); } //當JS使用geolocation API訪問當前位置時,回調這個函數 @Override public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { super.onGeolocationPermissionsShowPrompt(origin, callback); } //當JS取消geolocation API訪問的時候 @Override public void onGeolocationPermissionsHidePrompt() { super.onGeolocationPermissionsHidePrompt(); } //當JS輸出日誌時,回調這個函數 @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { return super.onConsoleMessage(consoleMessage); } //獲取video加載時默認顯示的第一張圖片 @Override public Bitmap getDefaultVideoPoster() { return super.getDefaultVideoPoster(); } //獲取視頻加載進度View,所以我們可以在這裏重寫默認的video加載進度 @Override public View getVideoLoadingProgressView() { return super.getVideoLoadingProgressView(); } //當JS獲取訪問歷史記錄時,回調這個函數 @Override public void getVisitedHistory(ValueCallback<String[]> callback) { super.getVisitedHistory(callback); } //當WebView需要顯示文件選擇器時,回調這個函數,我們可以重寫這個函數,加載我們自定義的文件選擇器 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { return super.onShowFileChooser(webView, filePathCallback, fileChooserParams); } });
WebView常用問題彙總
Android 7.0及以上系統WebView長按崩潰的解決方法
/**
* Android 7.0 WebView長按會崩潰,解決長按崩潰的辦法,就是屏蔽掉Android7.0 WebView的長按事件
*/
privatevoid
setWebViewLongClickListener(){
webView.setOnLongClickListener(new
View.OnLongClickListener() {
@Override
public boolean
onLongClick(View v) {
if(Build.VERSION.SDK_INT>
Build.VERSION_CODES.N){//android
7.0 Nougat
return true;
}
return false;
}
});
}