Android WebView

????????Android?WebView

????????一、簡介

????????WebView在Android平臺上是一個特殊的View, 基于webkit引擎、展現web頁面的控件,這個類可以被用來在你的app中僅僅顯示一張在線的網頁,還可以用來開發瀏覽器。WebView內部實現是采用渲染引擎來展示view的內容,提供網頁前進后退,網頁放大,縮小,搜索。Android的Webview在低版本和高版本采用了不同的webkit版本內核,4.4后直接使用了Chrome內核。

????????現在很多APP都內置了Web網頁,比如說很多電商平臺,淘寶、京東、聚劃算等等。WebView比較靈活,不需要升級客戶端,只需要修改網頁代碼即可。一些經常變化的頁面可以用WebView這種方式去加載網頁。例如中秋節跟國慶節打開的頁面不一樣,如果是用WebView顯示的話,只修改修改html頁面就行,而不需要升級客戶端。

????????二、基本使用

????????1、添加網絡權限

<uses-permission android:name="android.permission.INTERNET"/>

????????2、添加布局

<WebView

????android:id="@+id/wv_webview"

????android:layout_width="match_parent"

????android:layout_height="match_parent"/>

????????3、基本代碼運用

webView = (WebView) findViewById(R.id.wv_webview);

// webView.loadUrl("file:///android_asset/test.html");//加載asset文件夾下html

webView.loadUrl("http://139.196.35.30:8080/OkHttpTest/apppackage/test.html");//加載url

webView.addJavascriptInterface(this,"android");//添加js監聽 這樣html就能調用客戶端

webView.setWebChromeClient(webChromeClient);//輔助WebView處理Javascript的對話框,網站圖標,網站title,加載進度條webView.setWebViewClient(webViewClient); //幫助WebView處理各種通知、請求事件

WebSettings webSettings=webView.getSettings();//對WebView進行配置和管理

webSettings.setJavaScriptEnabled(true);//允許使用js

LOAD_CACHE_ONLY: 不使用網絡,只讀取本地緩存數據

LOAD_DEFAULT: (默認)根據cache-control決定是否從網絡上取數據。

LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據. ?

LOAD_CACHE_ELSE_NETWORK,只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。

webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);//不使用緩存,只從網絡獲取數據.

//支持屏幕縮放

webSettings.setSupportZoom(true);

webSettings.setBuiltInZoomControls(true);

????????三、常用方法

????????1、WebView常用方法

wvWebview.loadUrl(String url);// 加載網絡鏈接 url

wvWebview.canGoBack();// 判斷 WebView 當前是否可以返回上一頁

wvWebview.goBack();// 回退到上一頁

wvWebview.onResume();// 在調用onPause()后,可以調用該方法來恢復WebView 的運行

wvWebview.resumeTimers();// 恢復pauseTimers時的所有操作

wvWebview.onPause();// 類似 Activity 生命周期,頁面進入后臺不可見狀態

wvWebview.pauseTimers();// 該方法面向全局整個應用程序的webview,它會暫停所有webview的layout,parsing,JavaScript Timer。當程序進入后臺時,該方法的調用可以降低CPU功耗。

wvWebview.destroy();// 銷毀 WebView

wvWebview.clearHistory();// 清空歷史

wvWebview.clearCache(true);// 包括硬盤

wvWebview.reload();// 重新加載當前請求

wvWebview.removeAllViews();// 清除子view。

wvWebview.clearSslPreferences();// 清除ssl信息。

wvWebview.clearMatches();// 清除網頁查找的高亮匹配字符。

wvWebview.removeJavascriptInterface(String interfaceName);// 刪除interfaceName對應的注入對象

wvWebview.addJavascriptInterface(Object object,String interfaceName);//注入 java 對象。

wvWebview.setVerticalScrollBarEnabled(true);// 設置垂直方向滾動條。

wvWebview.setHorizontalScrollBarEnabled(true);// 設置橫向滾動條。

wvWebview.loadUrl(String url, Map additionalHttpHeaders);// 加載制定url并攜帶http header數據。。

wvWebview.stopLoading();// 停止 WebView 當前加載。

wvWebview.freeMemory();// 釋放內存,不過貌似不好用。

wvWebview.clearFormData();// 清除自動完成填充的表單數據。需要注意的是,該方法僅僅清除當前表單域自動完成填充的表單數據,并不會清除WebView存儲到本地的數據。

????????2、WebSettings(對WebView進行配置和管理) 常用方法

finalString filesDir = getContext().getFilesDir().getPath();

finalString databaseDir = filesDir.substring(0, filesDir.lastIndexOf("/")) + DATABASES_SUB_FOLDER;

WebSettings webSettings = wvWebview.getSettings();

if(webSettings ==null)return;

webSettings.setJavaScriptEnabled(true);// 支持 Js 使用

webSettings.setDomStorageEnabled(true);// 開啟DOM緩存

webSettings.setDatabaseEnabled(true);// 開啟數據庫緩存

webSettings.setLoadsImagesAutomatically(true);// 支持自動加載圖片

webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);// 設置 WebView 的緩存模式

webSettings.setAppCacheEnabled(true);// 支持啟用緩存模式

// Android 私有緩存存儲,如果你不調用setAppCachePath方法,WebView將不會產生這個目錄

webSettings.setAppCachePath(getCacheDir().getAbsolutePath());

if(Build.VERSION.SDK_INT <19) {// 數據庫路徑

? ? webSettings.setDatabasePath(databaseDir);

}

webSettings.setSupportZoom(true);// 支持縮放

webSettings.setUserAgentString("");// 設置 UserAgent 屬性

webSettings.setAllowFileAccess(true);// 允許加載本地 html 文件/false

// 允許通過 file url 加載的 Javascript 讀取其他的本地文件,Android 4.1 之前默認是true,在 Android 4.1 及以后默認是false,也就是禁止

webSettings.setAllowFileAccessFromFileURLs(false);

// 允許通過 file url 加載的 Javascript 可以訪問其他的源,包括其他的文件和 http,https 等其他的源,

// Android 4.1 之前默認是true,在 Android 4.1 及以后默認是false,也就是禁止

// 如果此設置是允許,則 setAllowFileAccessFromFileURLs 不起做用

webSettings.setAllowUniversalAccessFromFileURLs(false);

webSettings.setDefaultTextEncodingName("utf-8");//設置編碼格式

????????3、WebChromeClient(輔助WebView處理Javascript的對話框,網站圖標,網站title,加載進度條)常用方法

wvWebview.setWebChromeClient(newMyWebChromeClient());

publicclassMyWebChromeClientextendsWebChromeClient{

/**輸出 Web 端日志 */

@Override

publicbooleanonConsoleMessage(ConsoleMessage consoleMessage){

returnsuper.onConsoleMessage(consoleMessage);

? ? ? ? }

/** * 當前 WebView 加載網頁進度 */

@Override

publicvoidonProgressChanged(WebView view,intnewProgress){

super.onProgressChanged(view, newProgress);

? ? ? ? }

/*** Js 中調用 alert() 函數,產生的對話框*/

@Override

publicbooleanonJsAlert(WebView view, String url, String message, JsResult result){

returnsuper.onJsAlert(view, url, message, result);

? ? ? ? }

/** * 處理 Js 中的 Confirm 對話框*/

@Override

publicbooleanonJsConfirm(WebView view, String url, String message, JsResult result){

returnsuper.onJsConfirm(view, url, message, result);

? ? ? ? }

/** * 處理 JS 中的 Prompt對話框 */

@Override

publicbooleanonJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result){

returnsuper.onJsPrompt(view, url, message, defaultValue, result);

? ? ? ? }

/*** 接收web頁面的icon*/

@Override

publicvoidonReceivedIcon(WebView view, Bitmap icon){

super.onReceivedIcon(view, icon);

? ? ? ? }

/** * 接收web頁面的 Title */

@Override

publicvoidonReceivedTitle(WebView view, String title){

super.onReceivedTitle(view, title);

? ? ? ? }

? ? }

????????4、WebViewClient(幫助WebView處理各種通知、請求事件)常用方法

wvWebview.setWebViewClient(newMyWebViewClient());

publicclassMyWebViewClientextendsWebViewClient{

/*** 當WebView得頁面Scale值發生改變時回調 */

@Override

publicvoidonScaleChanged(WebView view,floatoldScale,floatnewScale){

super.onScaleChanged(view, oldScale, newScale);

? ? ? ? }

/** * 是否在 WebView 內加載頁面 */

@Override

publicbooleanshouldOverrideUrlLoading(WebView view, String url){

? ? ? ? ? ? view.loadUrl(url);

returnsuper.shouldOverrideUrlLoading(view, url);

? ? ? ? }

/** * WebView 開始加載頁面時回調,一次Frame加載對應一次回調 */

@Override

publicvoidonPageStarted(WebView view, String url, Bitmap favicon){

super.onPageStarted(view, url, favicon);

? ? ? ? }

/** * WebView 完成加載頁面時回調,一次Frame加載對應一次回調 */

@Override

publicvoidonPageFinished(WebView view, String url){

super.onPageFinished(view, url);

? ? ? ? }

/*** WebView 加載頁面資源時會回調,每一個資源產生的一次網絡加載,除非本地有當前 url 對應有緩存,否則就會加載。 */

@Override

publicvoidonLoadResource(WebView view, String url){

super.onLoadResource(view, url);

? ? ? ? }

/** * WebView 可以攔截某一次的 request 來返回我們自己加載的數據,這個方法在后面緩存會有很大作用。*/

@Override

publicWebResourceResponseshouldInterceptRequest(WebView view, WebResourceRequest request){

returnsuper.shouldInterceptRequest(view, request);

? ? ? ? }

/** * WebView 訪問 url 出錯 */

@Override

publicvoidonReceivedError(WebView view, WebResourceRequest request, WebResourceError error){

super.onReceivedError(view, request, error);

? ? ? ? }

/*** WebView ssl 訪問證書出錯,handler.cancel()取消加載,handler.proceed()對然錯誤也繼續加載*/

@Override

publicvoidonReceivedSslError(WebView view, SslErrorHandler handler, SslError error){

super.onReceivedSslError(view, handler, error);

? ? ? ? }

? ? }

????????三、與JS交互

????????1、Android調用js方法:2種方式

????js方法:

functioncallJS(){?

?? ? ? alert("Android調用了JS的callJS方法");

?}

????????(1)第一種方法:loadUrl

wvWebview.loadUrl("javascript:callJS()");

????????(2)第二種方法:evaluateJavascript

wvWebview.evaluateJavascript("javascript:callJS()",newValueCallback() {

@Override

publicvoidonReceiveValue(String value){

//此處為 js 返回的結果

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

????????因為該方法的執行不會使頁面刷新,而第一種方法(loadUrl )的執行則會。Android 4.4 后才可使用

????????所以建議:兩種方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法2

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

wvWebview.evaluateJavascript("javascript:callJS()",newValueCallback() {

@Override

publicvoidonReceiveValue(String value){

//此處為 js 返回的結果

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

}else{//Android 4.4 前使用該方法

wvWebview.loadUrl("javascript:callJS()");

? ? ? ? }

????????2、js調用Android方法:3種方式

????????(1)第一種方法:addJavascriptInterface

????????優點:使用簡單

????????缺點:存在嚴重的漏洞問題

// js調用方式

? ? function callAndroid(){

? ? ? ? test.hello("js調用了android中的hello方法");

? ? }

//通過WebView設置Android類與JS代碼的映射

wvWebview.addJavascriptInterface(new AndroidtoJs(), "test");

// 定義JS需要調用的方法

public class AndroidtoJs extends Object {

? ? ? ? // 被JS調用的方法必須加入@JavascriptInterface注解

? ? ? ? @JavascriptInterface

? ? ? ? public void hello(String msg) {

? ? ? ? ? ? System.out.println("JS調用了Android的hello方法");

? ? ? ? }

}

????????(2)第二種方法:通過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url

//js調用

? ? function callAndroid(){

? ? ? ? document.location="js://webview?arg1=1&arg2=222";

? ? }

// andorid

// 在Android通過WebViewClient復寫shouldOverrideUrlLoading ()

public class MyWebViewClient extends WebViewClient {

? ? ? ? /**

? ? ? ? * 是否在 WebView 內加載頁面

? ? ? ? */

? ? @Override

? ? public boolean shouldOverrideUrlLoading(WebView view, String url) {

? ? ? ? ? ? view.loadUrl(url);

? ? ? ? ? ? // 步驟2:根據協議的參數,判斷是否是所需要的url

? ? ? ? ? ? // 一般根據scheme(協議格式) & authority(協議名)判斷(前兩個參數)

? ? ? ? ? ? //假定傳入進來的 url = "js://webview?arg1=111&arg2=222"(同時也是約定好的需要攔截的)

? ? ? ? ? ? Uri uri = Uri.parse(url);

? ? ? ? ? ? // 如果url的協議 = 預先約定的 js 協議

? ? ? ? ? ? // 就解析往下解析參數

? ? ? ? ? ? if (uri.getScheme().equals("js")) {

? ? ? ? ? ? ? ? // 如果 authority? = 預先約定協議里的 webview,即代表都符合約定的協議

? ? ? ? ? ? ? ? // 所以攔截url,下面JS開始調用Android需要的方法

? ? ? ? ? ? ? ? if (uri.getAuthority().equals("webview")) {

? ? ? ? ? ? ? ? ? ? // 步驟3:

? ? ? ? ? ? ? ? ? ? // 執行JS所需要調用的邏輯

? ? ? ? ? ? ? ? ? ? System.out.println("js調用了Android的方法");

? ? ? ? ? ? ? ? ? ? // 可以在協議上帶有參數并傳遞到Android上

? ? ? ? ? ? ? ? ? ? HashMap params = new HashMap<>();

? ? ? ? ? ? ? ? ? ? Set collection = uri.getQueryParameterNames();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? }

? ? ? ? ? ? return super.shouldOverrideUrlLoading(view, url);

? ? ? ? }

}

????????(3)第三種方法:通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息

//js調用

? ? function clickprompt(){

? ? ? ? var result = prompt("js://demo?arg1=111&arg2=222");

? ? ? ? alert("demo" + result);

? ? }

//android定義

public class MyWebChromeClient extends WebChromeClient {

? ? @Override

? ? public boolean onJsPrompt(WebView view, String url, String message, String? ? ? ? ? ? defaultValue, JsPromptResult result) {

? ? ? ? ? ? // 根據協議的參數,判斷是否是所需要的url(原理同方式2)

? ? ? ? ? ? // 一般根據scheme(協議格式) & authority(協議名)判斷(前兩個參數)

? ? ? ? ? ? //假定傳入進來的 url = "js://webview?arg1=111&arg2=222"(同時也是約定好的需要攔截的)

? ? ? ? ? ? Uri uri = Uri.parse(message);

? ? ? ? ? ? // 如果url的協議 = 預先約定的 js 協議

? ? ? ? ? ? // 就解析往下解析參數

? ? ? ? ? ? if (uri.getScheme().equals("js")) {

? ? ? ? ? ? ? ? // 如果 authority? = 預先約定協議里的 webview,即代表都符合約定的協議

? ? ? ? ? ? ? ? // 所以攔截url,下面JS開始調用Android需要的方法

? ? ? ? ? ? ? ? if (uri.getAuthority().equals("webview")) {

? ? ? ? ? ? ? ? ? ? // 執行JS所需要調用的邏輯

? ? ? ? ? ? ? ? ? ? System.out.println("js調用了Android的方法");

? ? ? ? ? ? ? ? ? ? // 可以在協議上帶有參數并傳遞到Android上

? ? ? ? ? ? ? ? ? ? HashMap params = new HashMap<>();

? ? ? ? ? ? ? ? ? ? Set collection = uri.getQueryParameterNames();

? ? ? ? ? ? ? ? ? ? //參數result:代表消息框的返回值(輸入值)

? ? ? ? ? ? ? ? ? ? result.confirm("js調用了Android的方法成功啦");

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? }

? ? ? ? ? ? return super.onJsPrompt(view, url, message, defaultValue, result);

? ? ? ? }

}

????四、開源庫

因為WebView 本身功能不是很完善而且用起來也是極其麻煩,所以這里推薦2個開源庫:JsBridgeAgentWeb

JSBridge:http://www.lxweimin.com/p/2ec3f06d6087

AgentWebhttp://www.lxweimin.com/p/c80da1c41af7

WebView開源庫地址:

https://github.com/lzyzsd/JsBridge

https://github.com/Justson/AgentWeb

注:參考文章

http://www.lxweimin.com/p/3c94ae673e2aWebview?使用攻略

http://www.lxweimin.com/p/fd61e8f4049eWebview?干貨

http://www.lxweimin.com/p/345f4d8a5cfaAndroid WebView與 JS 的交互方式

http://www.lxweimin.com/p/3a345d27cd42Android WebView 使用漏洞

http://www.lxweimin.com/p/5e7075f4875fWebView 緩存機制

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容