在Android手機中內置了一款高性能webkit內核瀏覽器,在SDK中封裝為一個叫做WebView組件。
什么是webkit
WebKit是Mac OS X v10.3及以上版本所包含的軟件框架(對v10.2.7及以上版本也可通過軟件更新獲取)。 同時,WebKit也是Mac OS X的Safari網頁瀏覽器的基礎。WebKit是一個開源項目,主要由KDE的KHTML修改而來並且包含了一些來自蘋果公司的一些組件。
傳統上,WebKit包含一個網頁引擎WebCore和一個腳本引擎JavaScriptCore,它們分別對應的是KDE的KHTML和KJS。不過, 隨着JavaScript引擎的獨立性越來越強,現在WebKit和WebCore已經基本上混用不分(例如Google Chrome和Maxthon 3采用V8引擎,卻仍然宣稱自己是WebKit內核)。
這里我們初步體驗一下在android是使用webview瀏覽網頁,在SDK的Dev Guide中有一個WebView的簡單例子 。
在開發過程中應該注意幾點:
1.AndroidManifest.xml中必須使用許可"android.permission.INTERNET",否則會出Web page not available錯誤。
2.如果訪問的頁面中有Javascript,則webview必須設置支持Javascript。
webview.getSettings().setJavaScriptEnabled(true);
3.如果頁面中鏈接,如果希望點擊鏈接繼續在當前browser中響應,而不是新開Android的系統browser中響應該鏈接,必須覆蓋 webview的WebViewClient對象。
mWebView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
4.如果不做任何處理,瀏覽網頁,點擊系統“Back”鍵,整個Browser會調用finish()而結束自身,如果希望瀏覽的網 頁回退而不是推出瀏覽器,需要在當前Activity中處理並消費掉該Back事件。
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
下一步讓我們來了解一下android中webview是如何支持javascripte自定義對象的,在w3c標准中js有 window,history,document等標准對象,同樣我們可以在開發瀏覽器時自己定義我們的對象調用手機系統功能來處理,這樣使用js就可以 為所欲為了。
看一個實例:
public class WebViewDemo extends Activity {
private WebView mWebView;
private Handler mHandler = new Handler();
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.webviewdemo);
mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new Object() {
public void clickOnAndroid() {
mHandler.post(new Runnable() {
public void run() {
mWebView.loadUrl("javascript:wave()");
}
});
}
}, "demo");
mWebView.loadUrl("file:///android_asset/demo.html");
}
}
我們看addJavascriptInterface(Object obj,String interfaceName)這個方法,該方法將一個java對象綁定到一個javascript對象中,javascript對象名就是 interfaceName(demo),作用域是Global。這樣初始化webview后,在webview加載的頁面中就可以直接通過 javascript:window.demo訪問到綁定的java對象了。來看看在html中是怎樣調用的。
<html>
<mce:script language="javascript">
<!--
function wave() {
document.getElementById("droid").src="android_waving.png";
}
// --></mce:script>
<body>
<a onClick="window.demo.clickOnAndroid()">
<img id="droid" src="android_normal.png" mce_src="android_normal.png"/><br>
Click me!
</a>
</body>
</html>
這樣在javascript中就可以調用java對象的clickOnAndroid()方法了,同樣我們可以在此對象中定義很多方法(比 如發短信,調用聯系人列表等手機系統功能。),這里wave()方法是java中調用javascript的例子。
這里還有幾個知識點:
1)為了讓WebView從apk文件中加載assets,Android SDK提供了一個schema,前綴為"file:///android_asset/"。WebView遇到這樣的schema,就去當前包中的 assets目錄中找內容。如上面的"file:///android_asset/demo.html"
2)addJavascriptInterface方法中要綁定的Java對象及方法要運行另外的線程中,不能運行在構造他的線程中,這也是使用 Handler的目的。
===========分割的線======================
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class WebviewTestActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final WebView wv = new WebView(this);
// 覆蓋默認后退按鈕的作用,替換成WebView里的查看歷史頁面
wv.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && wv.canGoBack()) {
wv.goBack();
return true;
}
}
return false;
}
});
// 設置支持Javascript
wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
wv.getSettings().setDatabaseEnabled(true);
wv.getSettings().setDatabasePath("/data/data/com.xinze.joke/databases");
// 創建WebViewClient對象
WebViewClient wvc = new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
wv.loadUrl(url);
// 記得消耗掉這個事件。給不知道的朋友再解釋一下,Android中返回True的意思就是到此為止吧,事件就會不會冒泡傳遞了,我們稱之為消耗掉
return true;
}
};
// 設置WebViewClient對象
wv.setWebViewClient(wvc);
// 創建WebViewChromeClient
WebChromeClient wvcc = new WebChromeClient() {
// 處理Alert事件
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
// 構建一個Builder來顯示網頁中的alert對話框
Builder builder = new Builder(WebviewTestActivity.this);
builder.setTitle("笑死不償命");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
}
// 處理Confirm事件
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
Builder builder = new Builder(WebviewTestActivity.this);
builder.setTitle("刪除確認");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setNeutralButton(android.R.string.cancel, new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
}
// 處理提示事件
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
JsPromptResult result) {
// 看看默認的效果
return super.onJsPrompt(view, url, message, defaultValue, result);
}
@Override
public void onExceededDatabaseQuota(String url, String
databaseIdentifier, long currentQuota, long estimatedSize, long
totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(204801);
}
};
// wv.loadUrl("http://mrdoob.com/projects/chromeexperiments/ball_pool/");
// wv.loadUrl("http://www.theshodo.com/Write");
wv.loadUrl("http://192.168.1.107:8888/MBPHtmlClient/");
// 設置setWebChromeClient對象
wv.setWebChromeClient(wvcc);
setContentView(wv);
}
}
