簡介:
WebView是一個基於webkit引擎、展現web頁麵的控件。
Android的Webview在低版本和高版本采用了不同的webkit版本內核,4.4後直接使用了Chrome。
作用:
1、 顯示和渲染Web頁麵
2、 直接使用html文件(網絡上或本地assets中)作布局
3、 可和JavaScript交互調用
使用介紹:
一般來說Webview可單獨使用,可聯合其子類一起使用:
1、 Webview自身的常見方法;
2、 Webview的最常用的子類(WebSettings類、WebViewClient類、WebChromeClient類)
3、 Android和Js的交互
WebView常用方法:
1. WebView的狀態
協同安卓生命周期,做激活銷毀等
//激活WebView為活躍狀態,能正常執行網頁的響應
webView.onResume() ;
//當頁麵被失去焦點被切換到後台不可見狀態,需要執行onPause
//通過onPause動作通知內核暫停所有的動作,比如DOM的解析、plugin的執行、JavaScript執行。
webView.onPause();
//當應用程序(存在webview)被切換到後台時,這個方法不僅僅針對當前的webview而是全局的全應用程序的webview
//它會暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
webView.pauseTimers()
//恢複pauseTimers狀態
webView.resumeTimers();
//銷毀Webview
//在關閉了Activity時,如果Webview的音樂或視頻,還在播放。就必須銷毀Webview
//但是注意:webview調用destory時,webview仍綁定在Activity上
//這是由於自定義webview構建時傳入了該Activity的context對象
//因此需要先從父容器中移除webview,然後再銷毀webview:
rootLayout.removeView(webView);
webView.destroy();
根據場景做一些清除緩存數據
//清除網頁訪問留下的緩存
//由於內核緩存是全局的因此這個方法不僅僅針對webview而是針對整個應用程序.
Webview.clearCache(true);
//清除當前webview訪問的曆史記錄
//隻會webview訪問曆史記錄裏的所有記錄除了當前訪問記錄
Webview.clearHistory();
//這個api僅僅清除自動完成填充的表單數據,並不會清除WebView存儲到本地的數據
Webview.clearFormData();
2.WebView的行為
前進與後退
//是否可以後退
Webview.canGoBack()
//後退網頁
Webview.goBack()
//是否可以前進
Webview.canGoForward()
//前進網頁
Webview.goForward()
//以當前的index為起始點前進或者後退到曆史記錄中指定的steps
//如果steps為負數則為後退,正數則為前進
Webview.goBackOrForward(intsteps)
Back鍵控製網頁後退
問題:在不做任何處理前提下 ,瀏覽網頁時點擊係統的“Back”鍵,整個 Browser 會調用 finish()而結束自身
目標:點擊返回後,是網頁回退而不是退出瀏覽器
解決方案:在當前Activity中處理並消費掉該 Back 事件
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
1
2
3
4
5
6
7
3.WebView常用類
一` WebSettings類
1.作用:對WebView進行配置和管理
2.配置步驟 & 常見方法:
步驟一:添加訪問網絡權限(AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET"/>
1
步驟二:配置步驟2:生成一個WebView組件(有兩種方式)
//方式1:直接在在Activity中生成
WebView webView = new WebView(this)
//方法2:在Activity的layout文件裏添加webview控件:
WebView webview = (WebView) findViewById(R.id.webView);
1
2
3
4
配置步驟3:進行配置-利用WebSettings子類(常見方法 看情況使用)
//聲明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.setAllowFileAccess(true); //設置可以訪問文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通過JS打開新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自動加載圖片
webSettings.setDefaultTextEncodingName("utf-8");//設置編碼格式
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);//設置混合內容模式(需要判斷版本號)
webSettings.setTextZoom(100);//設置文字大小 100為正常 120為120%
//結合使用(離線加載)
webSettings.getSettings().setDomStorageEnabled(true);//啟用Dom存儲
if (NetStatusUtil.isConnected(getApplicationContext())) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根據cache-control決定是否從網絡上取數據。
} else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//沒網,則從本地獲取,即離線加載
}
webSettings.setDomStorageEnabled(true); // 開啟 DOM storage API 功能
webSettings.setDatabaseEnabled(true); //開啟 database storage API 功能
webSettings.setAppCacheEnabled(true);//開啟 Application Caches 功能
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath); //設置 Application Caches 緩存目錄
//優先使用緩存:
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//緩存模式如下:
//LOAD_CACHE_ONLY: 不使用網絡,隻讀取本地緩存數據
//LOAD_DEFAULT: (默認)根據cache-control決定是否從網絡上取數據。
//LOAD_NO_CACHE: 不使用緩存,隻從網絡獲取數據.
//LOAD_CACHE_ELSE_NETWORK,隻要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。
//不使用緩存:
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
二` WebViewClient類
1.作用:處理各種通知 & 請求事件
2. 常見方法:
方法一:shouldOverrideUrlLoading()
作用:打開網頁時不調用係統瀏覽器, 而是在本WebView中顯示;在網頁上的所有加載都經過這個方法,這個函數我們可以做很多操作。
//步驟1. 定義Webview組件
Webview webview = (WebView) findViewById(R.id.webView1);
//步驟2.websettings的各種配置
WebSettings webSettings = webView.getSettings();//webSettings.setxxx();
//步驟3. 選擇加載方式
//方式1. 加載一個網頁:
webView.loadUrl("http://www.google.com/");
//方式2:加載apk包中的html頁麵
webView.loadUrl("file:///android_asset/test.html");
//方式3:加載手機本地的html頁麵
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
//步驟4. 複寫shouldOverrideUrlLoading()方法,使得打開網頁時不調用係統瀏覽器, 而是在本WebView中顯示
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
方法二:onPageStarted()
作用:開始載入頁麵調用的,我們可以設定一個loading的頁麵,告訴用戶程序在等待網絡響應。
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//設定加載開始的操作
}
});
1
2
3
4
5
6
方法三:onPageFinished()
作用:在頁麵加載結束時調用。我們可以關閉loading 條,切換程序動作。
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
//設定加載結束的操作
}
});
1
2
3
4
5
6
方法四:onLoadResource()
作用: 在加載頁麵資源時會調用,每一個資源(比如圖片)的加載都會調用一次。
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean onLoadResource(WebView view, String url) {
//設定加載資源的操作
}
});
1
2
3
4
5
6
方法五:onReceivedError()
作用:加載頁麵的服務器出現錯誤時(如404)調用。 App裏麵使用webview控件的時候遇到了諸如404這類的錯誤的時候,若也顯示瀏覽器裏麵的那種錯誤提示頁麵就顯得很醜陋了,那麼這個時候我們的app就需要加載一個本地的錯誤提示頁麵,即webview如何加載一個本地的頁麵
//步驟1:寫一個html文件(error_handle.html),用於出錯時展示給用戶看的提示頁麵
//步驟2:將該html文件放置到代碼根目錄的assets文件夾下
//步驟3:複寫WebViewClient的onRecievedError方法
//該方法傳回了錯誤碼,根據錯誤類型可以進行不同的錯誤分類處理
webView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
// 自定義錯誤提示頁麵
String errorHtml = "<html><body style='background-color:#e5e5e5;text-align: center;padding-top:80px;font-size:30px;'><h1>網絡繁忙!</h1></body></html>";
view.loadData(errorHtml, "text/html", "UTF-8");
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
方法六:onReceivedSslError()
作用:處理https請求
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); //表示等待證書響應
// handler.cancel(); //表示掛起連接,為默認方式
// handler.handleMessage(null); //可做其他處理
}
});
1
2
3
4
5
6
7
8
三` WebViewClient類
1.作用:輔助 WebView 處理 Javascript 的對話框,網站圖標,網站標題等等。
2.常見使用:
方法一:onProgressChanged()
作用:獲得網頁的加載進度並顯示。
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress < 100) {
String progress = newProgress + "%";
progress.setText(progress);
} else {
}
});
1
2
3
4
5
6
7
8
9
方法二:onReceivedTitle()
作用:獲取Web頁中的標題
每個網頁的頁麵都有一個標題,比如www.baidu.com這個頁麵的標題即“百度一下,你就知道”,那麼如何知道當前webview正在加載的頁麵的title並進行設置呢?
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title) {
titleview.setText(title);
}
1
2
3
4
5
4.WebView與JS的交互
借張思維導圖:
Android與JS通過WebView互相調用方法,實際上是:
Android去調用JS的代碼
JS去調用Android的代碼
Android調用JS代碼的方法有2種:
(1) 通過WebView的loadUrl()
(2) 通過WebView的evaluateJavascript()
對於JS調用Android代碼的方法有3種:
(1) 通過WebView的addJavascriptInterface()進行對象映射
(2) 通過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url
(3) 通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息
4.如何避免WebView內存泄露
不在xml中定義 Webview ,而是在需要的時候在Activity中創建,並且Context使用 getApplicationgContext()
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWebView = new WebView(getApplicationContext());
mWebView.setLayoutParams(params);
mLayout.addView(mWebView);
1
2
3
4
在 Activity 銷毀( WebView )的時候,先讓 WebView 加載null內容,然後移除 WebView,再銷毀 WebView,最後置空。
@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
交互
加載頁麵
//加載assets文件夾下的test.html頁麵,文件截圖如圖1*
mWebView.loadUrl("file:///android_asset/test.html");
//加載網頁*
mWebView.loadUrl("http://www.baidu.com");
1
2
3
4
Android調用JS方法
WebSettings webSettings = mWebView.getSettings();
//設置為可調用js方法*
webSettings.setJavaScriptEnabled(true);
//調用JS中無參的show方法
mWebView.loadUrl("JavaScript:show()");
//Android調用H5中帶返回值的方法()該方法隻在安卓4.4以上版本適用
mWebView.evaluateJavascript("sum(1,2)",new ValueCallback() {
@Override
public void on ReceiveValue(String value) {
Log.e(TAG,"onReceiveValue value=" + value);
}
});
//當調用H5中帶參數的方法時,勢必要傳入一個字符串,當傳入固定字符串時,用單引號括起來即可;當傳入變量名時,需要用到轉義符
mWebView.loadUrl("javascript:alertMessage('哈哈')");
mWebView.loadUrl( "javascript:alertMessage(\" " +content+ "\")");//String content="9880";*
JS調用Android方法
H5調用Android裏的方法,相對複雜一些,雙方具體操作如下:
Android需要做什麼呢?????
說白了就是新建一個類,裏麵寫提供給H5操作的方法,並規定別名。這裏我新建的class為JsInteration,方法為back(),規定的別名為android。先貼截圖,後貼代碼。*
在安卓4.2以上可以直接使用@JavascriptInterface注解來聲明,下麵是在一個本地Java方法
public class JsInteration {
@JavascriptInterface
public String back() {
return "hello world";
}
}
//定義完這個方法後再調用mWebView.addJavascriptInterface()方法:
mWebView.addJavascriptInterface(newJsInteration(),"android");
在H5中怎麼來調用呢?
調用格式為 window.別名.android中的方法名(parameter Values) ,此示例中我們用的別名為android,方法名為back()。
下圖:
代碼:
function s() {
var result=window.android.back();
document.getElementById("p").innerHTML=result;
}
完整代碼:
activity:
package com.e_valmont.javaandjsinteractivedemo;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private WebView mWebView;
@SuppressLint("JavascriptInterface")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("file:///android_asset/js_java_interaction.html");//加載本地asset下麵的js_java_interaction.html文件
//mWebView.loadUrl("https://www.baidu.com/");//加載本地assets下麵的js_java_interaction.html文件
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);//打開js支持
/**
* 打開js接口給H5調用,參數1為本地類名,參數2為別名;h5用window.別名.類名裏的方法名才能調用方法裏麵的內容,例如:window.android.back();
* */
mWebView.addJavascriptInterface(new JsInteration(), "android");
mWebView.setWebViewClient(new WebViewClient());
mWebView.setWebChromeClient(new WebChromeClient());
}
/**
* 自己寫一個類,裏麵是提供給H5訪問的方法
* */
public class JsInteration {
@JavascriptInterface//一定要寫,不然H5調不到這個方法
public String back() {
return "我是java裏的方法返回值";
}
}
//點擊按鈕,訪問H5裏帶返回值的方法
@TargetApi(Build.VERSION_CODES.KITKAT)
public void onClick(View v) {
Log.e("TAG", "onClick: ");
// mWebView.loadUrl("JavaScript:show()");//直接訪問H5裏不帶返回值的方法,show()為H5裏的方法
//傳固定字符串可以直接用單引號括起來
mWebView.loadUrl("javascript:alertMessage('哈哈')");//訪問H5裏帶參數的方法,alertMessage(message)為H5裏的方法
//當出入變量名時,需要用轉義符隔開
String content="9880";
mWebView.loadUrl("javascript:alertMessage(\"" +content+ "\")" );
//Android調用有返回值js方法,安卓4.4以上才能用這個方法
mWebView.evaluateJavascript("sum(1,2)", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.d(TAG, "js返回的結果為=" + value);
Toast.makeText(MainActivity.this,"js返回的結果為=" + value,Toast.LENGTH_LONG).show();
}
});
}
}
js:
<html>
<head>
<!--從assert中加載的中文網頁會出現亂碼,解決辦法就是給html指定編碼-->
<meta http-equiv="content-type" content="text/html;charset=gb2312">
<title>
</title>
</head>
<body>
這是html頁麵 <br/>
<button onclick="s()">點擊調用本地方法</button>
<a href="file:///android_asset/js_java_interaction.html">點擊跳轉到原生頁麵</a>
<p id="p"></p>
<script type="text/javascript">
//有參有返回值的方法
function sum(a,b) {
<!--gygguuuiu-->
return a+b;
}
//有參無返回值的方法
function alertMessage(message) {
alert(message);
}
//無參無返回值的方法
function show(){
//顯示hello world
document.getElementById("p").innerHTML="hello world";
}
function s() {
//調用原生的方法,android為約定的別名;back()為原生的方法
var result=window.android.back();
//將返回結果顯示在id為p的控件上
document.getElementById("p").innerHTML=result;
}
</script>
</body>
</html>
注意事項
(1)當自己寫html文件時,可能會出現顯示亂碼,我們需要指定格式
(2)當H5調用我們的方法時,我們需要把規定的別名傳給H5(切記一定不能錯),而且我們要在自己的方法裏執行H5想要的操作
(3)給H5調用的方法一定要加@JavascriptInterface,不然H5調不到我們的方法
(4) 調用js有參數有返回值的函數時,隻有安卓4.4以上才能用webView.evaluateJavascript方法直接拿到返回值;當版本低於4.4的時候,常用的思路是 java調用js方法,js方法執行完畢,再次調用java代碼將值返回
①.Java調用JS代碼
String call = "javascript:sumToJava(1,2)";
webView.loadUrl(call);
1
2
②.js函數處理,並將結果通過調用java方法返回
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)}
1
2
③.Java在回調方法中獲取js函數返回值
@JavascriptInterface
public void onSumResult(int result) {
Log.i(LOGTAG, "onSumResult result=" + result);}