前言#
WebView我們都使用過(guò),但是怎么說(shuō)呢,大部分人應(yīng)該都是趕鴨子上架,例如像我這樣的,需要用的時(shí)候就去查一下相關(guān)api,畢竟做原生app開(kāi)發(fā),webView用的確實(shí)不多,今天突然發(fā)現(xiàn)了這一點(diǎn),覺(jué)得應(yīng)該彌補(bǔ)一下這方面的不足,在網(wǎng)上看了一位博主分享之前分享的WebView介紹,非常細(xì)節(jié),非常棒,必須要讓更多的人看到。
復(fù)制過(guò)來(lái)的排版可能有些問(wèn)題,可以直接去看原文。
正文#
轉(zhuǎn)載請(qǐng)注明出處 http://blog.csdn.net/typename/article/details/39030091 powered by meichal zhao
概覽:
Android WebView在Android平臺(tái)上是一個(gè)特殊的View, 他能用來(lái)顯示網(wǎng)頁(yè),這個(gè)類(lèi)可以被用來(lái)在你的app中僅僅顯示一張?jiān)诰€的網(wǎng)頁(yè),還可以用來(lái)開(kāi)發(fā)瀏覽器。WebView內(nèi)部實(shí)現(xiàn)是采用渲染引擎來(lái)展示view的內(nèi)容,提供網(wǎng)頁(yè)前進(jìn)后退,網(wǎng)頁(yè)放大,縮小,搜索,前端開(kāi)發(fā)者可以使用web inspector(Android 4.4系統(tǒng)支持,4.4一下可以采用http://developer.android.com/guide/webapps/debugging.html)調(diào)試HTML,CSS,JavaScript等等功能。在Android 4.3系統(tǒng)及其一下WebView內(nèi)部采用Webkit渲染引擎,在Android 4.4采用chromium 渲染引擎來(lái)渲染View的內(nèi)容。
1.WebView的基本使用
(1)創(chuàng)建WebView的實(shí)例加入到Activity view tree中
WebView webview = new WebView(this);
setContentView(webview);
(2)在xml中配置WebView
<Webview
android:layout_width="match_parent"
android:layout_height="match_parent" >
</Webview>
(3)訪問(wèn)網(wǎng)頁(yè)
webview.loadUrl("http://developer.android.com/");
2.WebView API使用詳解
1)請(qǐng)求加載網(wǎng)頁(yè)部分
public void loadData (String data, String mimeType, String encoding)
加載指定的data數(shù)據(jù)
參數(shù)說(shuō)明:
data 字符串String形式的數(shù)據(jù) 可以通過(guò)base64編碼而來(lái)
mineType data數(shù)據(jù)的 MIME類(lèi)型, e.g. 'text/html'
encoding data數(shù)據(jù)的編碼格式
Tips:
1.Javascript有同源限制,同源策略限制了一個(gè)源中加載文本或者腳本與來(lái)自其他源中的數(shù)據(jù)交互方式。避免這種限制可以使用loadDataWithBaseURL()方法。
2.encoding參數(shù)制定data參數(shù)是否為base64或者 URL 編碼,如果data是base64編碼那么 encoding必須填寫(xiě) "base64“。
http://developer.android.com/reference/android/webkit/WebView.html
public void loadDataWithBaseURL (String baseUrl, String data, String mimeType, String encoding, String historyUrl)
使用baseUrl加載base URL的網(wǎng)頁(yè)內(nèi)容,baseUrl解決相關(guān)url使用Javascript相同源問(wèn)題。
public void loadUrl (String url)
加載制定url的網(wǎng)頁(yè)內(nèi)容
public void loadUrl (String url, Map<String, String> additionalHttpHeaders)
加載制定url并攜帶http header數(shù)據(jù)。
public void reload ()
重新加載頁(yè)面
Tip(重要)
頁(yè)面所有資源會(huì)重新加載
public void stopLoading ()
-
前進(jìn)后退
public void goBack ()
public void goForward ()
public void goBackOrForward (int steps)
以當(dāng)前的index為起始點(diǎn)前進(jìn)或者后退到歷史記錄中指定的steps, 如果steps為負(fù)數(shù)則為后退,正數(shù)則為前進(jìn)
public boolean canGoForward ()
public boolean canGoBack ()
3)JavaScript操作
public void addJavascriptInterface (Object object, String name)
當(dāng)網(wǎng)頁(yè)需要和App進(jìn)行交互時(shí),可以注入Java對(duì)象提供給JavaScritp調(diào)用. Java對(duì)象提供相應(yīng)的方法供js使用.
Tips(重要)
問(wèn)題:在Android 4.2以下使用這個(gè)api會(huì)涉及到JavaScript安全問(wèn)題, javascript可以通過(guò)反射這個(gè)Java對(duì)象的相關(guān)類(lèi)進(jìn)行攻擊。
解決:可以采用白名單的機(jī)制調(diào)用這個(gè)方法.
在Android4.2極其以上系統(tǒng)需要給提供js調(diào)用的方法前加入一個(gè)注視:@JavaScriptInterface; 在虛擬機(jī)當(dāng)中 Javascript調(diào)用Java方法會(huì)檢測(cè)這個(gè)anotation,如果方法被標(biāo)識(shí)@JavaScriptInterface則Javascript可以成功調(diào)用這個(gè)Java方法,否則調(diào)用不成功。
example:
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
public void evaluateJavascript (String script, ValueCallback<String> resultCallback)
這個(gè)方法在Android 4.4系統(tǒng)引入,因此只能在Android4.4系統(tǒng)中才能使用,提供在當(dāng)前頁(yè)面顯示上下文中異步執(zhí)行javascript代碼
Tips(重要)
這個(gè)方法必須在UI線程調(diào)用,這個(gè)函數(shù)的回調(diào)也會(huì)在UI線程執(zhí)行。
那么在Android4.4一下如何執(zhí)行javascrit代碼呢
可以通過(guò) WebView提供的loadUrl方法:具體格式如下:
webView.loadUrl("javascript:alert(injectedObject.toString())");
其中javascript: 是執(zhí)行javascript代碼的標(biāo)識(shí) , 后面是javascript語(yǔ)句。
public void removeJavascriptInterface (String name)
刪除addJavascripInterface時(shí)對(duì)webview注入的java對(duì)象. 此方法在不同的Android系統(tǒng)WebView會(huì)有問(wèn)題,會(huì)存在失效情況。
4)網(wǎng)頁(yè)查找功能
public int findAll (String find)
這個(gè)API在Android 4.1 就已經(jīng)被去除, 在Android 4.1極其以上系統(tǒng)使用findAllAsync方法
這個(gè)API還存在bug 具體請(qǐng)見(jiàn)我的之前一篇博文Android WebView findAll bug
[java] view plain copy
在CODE上查看代碼片派生到我的代碼片
public void findAllAsync (String find)
異步執(zhí)行查找網(wǎng)頁(yè)內(nèi)包含的字符并設(shè)置高亮,查找結(jié)果會(huì)回調(diào).
public void findNext (boolean forward)
查找下一個(gè)匹配的字符
使用example:
public class TestFindListener implements android.webkit.WebView.FindListener {
private FindListener mFindListener;
public TestFindListener(FindListener findListener) {
mFindListener = findListener;
}
@Override
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
boolean isDoneCounting) {
mFindListener.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
}
}
public void findAllAsync(String searchString) {
if (android.os.Build.VERSION_CODES.JELLY_BEAN <= Build.VERSION.SDK_INT)
mWebView.findAllAsync(searchString);
else {
int number = mWebView.findAll(searchString);
if (mIKFindListener !=null)
mIKFindListener.onFindResultReceived(number);
fixedFindAllHighLight(); // 參見(jiàn)我之前一篇博文Android WebView API findAll bug
}
}
mWebView.findNext(forward);
5)數(shù)據(jù)清除部分
public void clearCache (boolean includeDiskFiles)
清除網(wǎng)頁(yè)訪問(wèn)留下的緩存,由于內(nèi)核緩存是全局的因此這個(gè)方法不僅僅針對(duì)webview而是針對(duì)整個(gè)應(yīng)用程序.
public void clearFormData ()
這個(gè)api僅僅清除自動(dòng)完成填充的表單數(shù)據(jù),并不會(huì)清除WebView存儲(chǔ)到本地的數(shù)據(jù)。
public void clearHistory ()
清除當(dāng)前webview訪問(wèn)的歷史記錄,只會(huì)webview訪問(wèn)歷史記錄里的所有記錄除了當(dāng)前訪問(wèn)記錄.
public void clearMatches ()
清除網(wǎng)頁(yè)查找的高亮匹配字符
public void clearView ()
在Android 4.3及其以上系統(tǒng)這個(gè)api被丟棄了, 并且這個(gè)api大多數(shù)情況下會(huì)有bug,經(jīng)常不能清除掉之前的渲染數(shù)據(jù)。官方建議通過(guò)loadUrl("about:blank")來(lái)實(shí)現(xiàn)這個(gè)功能,陰雨需要重新加載一個(gè)頁(yè)面自然時(shí)間會(huì)收到影響。
6)WebView的狀態(tài)
public void onResume ()
激活WebView為活躍狀態(tài),能正常執(zhí)行網(wǎng)頁(yè)的響應(yīng)
public void onPause ()
當(dāng)頁(yè)面被失去焦點(diǎn)被切換到后臺(tái)不可見(jiàn)狀態(tài),需要執(zhí)行onPause動(dòng)過(guò), onPause動(dòng)作通知內(nèi)核暫停所有的動(dòng)作,比如DOM的解析、plugin的執(zhí)行、JavaScript執(zhí)行。并且可以減少不必要的CPU和網(wǎng)絡(luò)開(kāi)銷(xiāo),可以達(dá)到省電、省流量、省資源的效果。
public void pauseTimers ()
當(dāng)應(yīng)用程序被切換到后臺(tái)我們使用了webview, 這個(gè)方法不僅僅針對(duì)當(dāng)前的webview而是全局的全應(yīng)用程序的webview,它會(huì)暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
public void resumeTimers ()
恢復(fù)pauseTimers時(shí)的動(dòng)作。
public void destroy ()
Tips(重要)
這個(gè)方法必須在webview從view tree中刪除之后才能被執(zhí)行, 這個(gè)方法會(huì)通知native釋放webview占用的所有資源。
-
WebView 事件回調(diào)監(jiān)聽(tīng)
public void setWebChromeClient (WebChromeClient client)
主要通知客戶端app加載當(dāng)前網(wǎng)頁(yè)的 title,F(xiàn)avicon,progress,javascript dialog等事件,通知客戶端處理這些相應(yīng)的事件。
public void setWebViewClient (WebViewClient client)
主要通知客戶端app加載當(dāng)前網(wǎng)頁(yè)時(shí)的各種時(shí)機(jī)狀態(tài),onPageStart,onPageFinish,onReceiveError等事件。
- Android 5.0 Lollipop 新API
public static void enableSlowWholeDocumentDraw ()
Android 5.0 Webview默認(rèn)提供減少內(nèi)存占用支持,并且智能選擇需要繪制的HTML document部門(mén)來(lái)提供性能。 當(dāng)然開(kāi)發(fā)者可以在自己應(yīng)用程序需要時(shí)關(guān)閉這個(gè)選項(xiàng)(enableSlowWholeDocumentDraw)。
-
WebView Demo
package com.example.webviewdemo;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Message;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;public class WebViewBase extends WebView {
private static final String DEFAULT_URL = "http://www.ijinshan.com/";
private Activity mActivity;
public WebViewBase(Context context) {
super(context);
mActivity = (Activity) context;
init(context);
}@SuppressLint("SetJavaScriptEnabled") private void init(Context context) { WebSettings webSettings = this.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setSupportZoom(true); //webSettings.setUseWideViewPort(true); this.setWebViewClient(mWebViewClientBase); this.setWebChromeClient(mWebChromeClientBase); this.loadUrl(DEFAULT_URL); this.onResume(); } private WebViewClientBase mWebViewClientBase = new WebViewClientBase(); private class WebViewClientBase extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // TODO Auto-generated method stub return super.shouldOverrideUrlLoading(view, url); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { // TODO Auto-generated method stub super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { // TODO Auto-generated method stub super.onPageFinished(view, url); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { // TODO Auto-generated method stub super.onReceivedError(view, errorCode, description, failingUrl); } @Override public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { // TODO Auto-generated method stub super.doUpdateVisitedHistory(view, url, isReload); } } private WebChromeClientBase mWebChromeClientBase = new WebChromeClientBase(); private class WebChromeClientBase extends WebChromeClient { @Override public void onProgressChanged(WebView view, int newProgress) { mActivity.setProgress(newProgress * 1000); } @Override public void onReceivedTitle(WebView view, String title) { // TODO Auto-generated method stub super.onReceivedTitle(view, title); } @Override public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) { // TODO Auto-generated method stub super.onReceivedTouchIconUrl(view, url, precomposed); } @Override public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { // TODO Auto-generated method stub return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg); } }}
<uses-permission android:name="android.permission.INTERNET" />