一、加載Html的幾種方法
-
直接在Activity中實(shí)例化WebView
WebView webview =new WebView(this);
webview.loadUrl(......); 在XML中生命webview
WebView webView = (WebView) findViewById(R.id.webview);-
載入工程內(nèi)部頁(yè)面 page.html存儲(chǔ)在工程文件的assets根目錄下
webView = (WebView) findViewById(R.id.webview); webView.loadUrl("file:///file:///android_asset/page.html");
二徊件、加載頁(yè)面時(shí)幾種簡(jiǎn)單API使用
-
設(shè)置縮放
mWebView.getSettings().setBuiltInZoomControls(true);
-
在webview添加對(duì)js的支持
setting.setJavaScriptEnabled(true);//支持js
-
添加對(duì)中文支持
setting.setDefaultTextEncodingName("GBK");//設(shè)置字符編碼
-
設(shè)置頁(yè)面滾動(dòng)條風(fēng)格
webView.setScrollBarStyle(0);//滾動(dòng)條風(fēng)格芍锦,為0指滾動(dòng)條不占用空間芒率,直接覆蓋在網(wǎng)頁(yè)上 取消滾動(dòng)條 this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);
-
listview,webview中滾動(dòng)拖動(dòng)到頂部或者底部時(shí)的陰影(滑動(dòng)到項(xiàng)部或底部不固定)
WebView.setOverScrollMode(View.OVER_SCROLL_NEVER);
三症副、瀏覽器優(yōu)化操作處理:
-
WebView默認(rèn)用系統(tǒng)自帶瀏覽器處理頁(yè)面跳轉(zhuǎn)启泣。為了讓頁(yè)面跳轉(zhuǎn)在當(dāng)前WebView中進(jìn)行,
重寫WebViewClient
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);//使用當(dāng)前WebView處理跳轉(zhuǎn)
return true;//true表示此事件在此處被處理亿蒸,不需要再?gòu)V播
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//有頁(yè)面跳轉(zhuǎn)時(shí)被回調(diào)
}
@Override
public void onPageFinished(WebView view, String url) {
//頁(yè)面跳轉(zhuǎn)結(jié)束后被回調(diào)
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(WebViewDemo.this, "Oh no! " + description, Toast.LENGTH_SHORT).show();
}
});
-
當(dāng)WebView內(nèi)容影響UI時(shí)調(diào)用WebChromeClient的方法
mWebView.setWebChromeClient(new WebChromeClient() { /** * 處理JavaScript Alert事件 */ @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { //用Android組件替換 new AlertDialog.Builder(WebViewDemo.this) .setTitle("JS提示") .setMessage(message) .setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setCancelable(false) .create().show(); return true; } });
-
按BACK鍵時(shí)凑兰,不會(huì)返回跳轉(zhuǎn)前的頁(yè)面,而是退出本Activity边锁,重寫onKeyDown()方法來(lái)解決此問(wèn)題
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { //處理WebView跳轉(zhuǎn)返回 if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); } private class JsToJava { public void jsMethod(String paramFromJS) { Log.i("CDH", paramFromJS); } }
四姑食、WebView與JS交互
-
總綱
/* 綁定Java對(duì)象到WebView,這樣可以讓JS與Java通信(JS訪問(wèn)Java方法) 第一個(gè)參數(shù)是自定義類對(duì)象茅坛,映射成JS對(duì)象 第二個(gè)參數(shù)是第一個(gè)參數(shù)的JS別名 調(diào)用示例: mWebView.loadUrl("javascript:window.stub.jsMethod('param')"); */ mWebView.addJavascriptInterface(new JsToJava(), "stub"); final EditText mEditText = (EditText)findViewById(R.id.web_view_text); findViewById(R.id.web_view_search).setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { String url = mEditText.getText().toString(); if (url == null || "".equals(url)) { Toast.makeText(WebViewDemo.this, "請(qǐng)輸入U(xiǎn)RL", Toast.LENGTH_SHORT).show(); } else { if (!url.startsWith("http:") && !url.startsWith("file:")) { url = "http://" + url; } mWebView.loadUrl(url); } } }); //默認(rèn)頁(yè)面 mWebView.loadUrl("file:///android_asset/js_interact_demo.html"); }
-
撲捉加載頁(yè)面JS的過(guò)程
注意到webview提供的兩個(gè)方法:
setWebChromeClient方法正是可以處理progress的加載音半,此外,還可以處理js對(duì)話框贡蓖,在webview中顯示icon圖標(biāo)等祟剔。
對(duì)于setWebViewClient方法,一般用來(lái)處理html的加載(需要重載onPageStarted(WebView view, String url, Bitmap favicon))摩梧、關(guān)閉(需要重載onPageFinished(WebViewview, String url)方法)。
webView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {// 載入進(jìn)度改變而觸發(fā)
if (progress == 100) {
handler.sendEmptyMessage(1);// 如果全部載入,隱藏進(jìn)度對(duì)話框
}
super.onProgressChanged(view, progress);
}
});
-
獲取java中的數(shù)據(jù):?jiǎn)为?dú)構(gòu)建一個(gè)接口宣旱,作為處理js與java的數(shù)據(jù)交互的橋梁
封裝的代碼AndroidToastForJs.java public class AndroidToastForJs { private Context mContext; public AndroidToastForJs(Context context){ this.mContext = context; } //webview中調(diào)用toast原生組件 public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } //webview中求和 public int sum(int a,int b){ return a+b; } //以json實(shí)現(xiàn)webview與js之間的數(shù)據(jù)交互 public String jsontohtml(){ JSONObject map; JSONArray array = new JSONArray(); try { map = new JSONObject(); map.put("name","aaron"); map.put("age", 25); map.put("address", "中國(guó)上海"); array.put(map); map = new JSONObject(); map.put("name","jacky"); map.put("age", 22); map.put("address", "中國(guó)北京"); array.put(map); map = new JSONObject(); map.put("name","vans"); map.put("age", 26); map.put("address", "中國(guó)深圳"); map.put("phone","13888888888"); array.put(map); } catch (JSONException e) { e.printStackTrace(); } return array.toString(); } }
Webview提供的傳入js的方法:
webView.addJavascriptInterface(new AndroidToastForJs(mContext), "JavaScriptInterface");
Html頁(yè)面jsonData.html設(shè)計(jì)的部分代碼如下
<script type="text/javascript">
var result = JavaScriptInterface.jsontohtml();
var obj = eval("("+result+")");//解析json字符串
function showAndroidToast(toast)
{
JavaScriptInterface.showToast(toast);
}
function getjsonData(){
var result = JavaScriptInterface.jsontohtml();
var obj = eval("("+result+")");//解析json字符串
for(i=0;i<obj.length;i++){
var user=obj[i];
document.write("<p>姓名:"+user.name+"</p>");
document.write("<p>年齡:"+user.age+"</p>");
document.write("<p>地址:"+user.address+"</p>");
if(user.phone!=null){
document.write("<p>手機(jī)號(hào)碼:"+user.address+"</p>");
}
}
}
function list(){
document.write("<div data-role='header'><p>another</p></div>");
}
</script>
</head>
<body>
<div data-role="page" >
<div data-role="header" data-theme="c">
<h1>Android via Interface</h1>
</div><!-- /header -->
<div data-role="content">
<button value="say hello" onclick="showAndroidToast('Hello,Android!')" data-theme="e"></button>
<button value="get json data" onclick="getjsonData()" data-theme="e"></button>
</div><!-- /content -->
<div data-role="collapsible" data-theme="c" data-content-theme="f">
<h3>I'm <script>document.write(obj[0].name);</script>,click to see my info</h3>
<p><script>document.write("<p>姓名:"+obj[0].name+"</p>");</script></p>
<p><script>document.write("<p>年齡:"+obj[0].age+"</p>");</script></p>
<p><script>document.write("<p>地址:"+obj[0].address+"</p>");</script></p>
</div>
<div data-role="footer" data-theme="c">
<h4>Page Footer</h4>
</div><!-- /footer -->
</div><!-- /page -->
</body>
問(wèn)題解決:
-
多圖片網(wǎng)頁(yè)手機(jī)加載數(shù)度慢
1. 建議先用 webView.getSettings().setBlockNetworkImage(true); 將圖片下載阻塞 2. 在瀏覽器的OnPageFinished事件中設(shè)置 webView.getSettings().setBlockNetworkImage(false); 通過(guò)圖片的延遲載入仅父,讓網(wǎng)頁(yè)能更快地顯示
HTML5交互:
HTML5本地存儲(chǔ)在Android中的應(yīng)用
-
HTML5提供了2種客戶端存儲(chǔ)數(shù)據(jù)新方法:
localStorage 沒(méi)有時(shí)間限制
-
sessionStorage 針對(duì)一個(gè)Session的數(shù)據(jù)存儲(chǔ)
<script type="text/javascript"> localStorage.lastname="Smith"; document.write(localStorage.lastname); </script> <script type="text/javascript"> sessionStorage.lastname="Smith"; document.write(sessionStorage.lastname); </script>
WebStorage的API:
//清空storage
localStorage.clear();
//設(shè)置一個(gè)鍵值
localStorage.setItem(“yarin”,“yangfegnsheng”);
//獲取一個(gè)鍵值
localStorage.getItem(“yarin”);
//獲取指定下標(biāo)的鍵的名稱(如同Array)
localStorage.key(0);
//return “fresh” //刪除一個(gè)鍵值
localStorage.removeItem(“yarin”);
注意一定要在設(shè)置中開啟哦
setDomStorageEnabled(true)
在Android中進(jìn)行操作:
//啟用數(shù)據(jù)庫(kù)
webSettings.setDatabaseEnabled(true);
String dir = this.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
//設(shè)置數(shù)據(jù)庫(kù)路徑
webSettings.setDatabasePath(dir);
//使用localStorage則必須打開
webSettings.setDomStorageEnabled(true);
//擴(kuò)充數(shù)據(jù)庫(kù)的容量(在WebChromeClinet中實(shí)現(xiàn))
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota,
long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(estimatedSize * 2);
}
在JS中按常規(guī)進(jìn)行數(shù)據(jù)庫(kù)操作:
tHandler, errorHandler);
}
);
}
function dataSelectHandler(transaction, results){
// Handle the results
for (var i=0; i<results.rows.length; i++) {
var row = results.rows.item(i);
var newFeature = new Object();
newFeature.name = row['name'];
newFeature.decs = row['desc'];
document.getElementById("name").innerHTML="name:"+newFeature.name;
document.getElementById("desc").innerHTML="desc:"+newFeature.decs;
}
}
function updateData(){
YARINDB.transaction(
function (transaction) {
var data = ['fengsheng yang','I am fengsheng'];
transaction.executeSql("UPDATE yarin SET name=?, desc=? WHERE id = 1", [data[0], data[1]]);
}
);
selectAll();
}
function ddeleteTables(){
YARINDB.transaction(
function (transaction) {
transaction.executeSql("DROP TABLE yarin;", [], nullDataHandler, errorHandler);
}
);
console.log("Table 'page_settings' has been dropped.");
}
注意onLoad中的初始化工作
function initLocalStorage(){
if (window.localStorage) {
textarea.addEventListener("keyup", function() {
window.localStorage["value"] = this.value;
window.localStorage["time"] = new Date().getTime();
}, false);
} else {
alert("LocalStorage are not supported in this browser.");
}
}
window.onload = function() {
initDatabase();
initLocalStorage();
}
HTML5地理位置服務(wù)在Android中的應(yīng)用:
Android中:
//啟用地理定位
webSettings.setGeolocationEnabled(true);
//設(shè)置定位的數(shù)據(jù)庫(kù)路徑
webSettings.setGeolocationDatabasePath(dir);
//配置權(quán)限(同樣在WebChromeClient中實(shí)現(xiàn))
public void onGeolocationPermissionsShowPrompt(String origin,
GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
在Manifest中添加權(quán)限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
HTML5中 通過(guò)navigator.geolocation對(duì)象獲取地理位置信息:
常用的navigator.geolocation對(duì)象有以下三種方法:
-
//獲取當(dāng)前地理位置
navigator.geolocation.getCurrentPosition(success_callback_function, error_callback_function, position_options)
-
//持續(xù)獲取地理位置
navigator.geolocation.watchPosition(success_callback_function, error_callback_function, position_options)
-
清除持續(xù)獲取地理位置事件
navigator.geolocation.clearWatch(watch_position_id)
----其中success_callback_function為成功之后處理的函數(shù),error_callback_function為失敗之后返回的處理函數(shù),參數(shù)position_options是配置項(xiàng)
在JS中的代碼:
//定位
function get_location() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(show_map,handle_error,{enableHighAccuracy:false,maximumAge:1000,timeout:15000});
} else {
alert("Your browser does not support HTML5 geoLocation");
}
}
function show_map(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var city = position.coords.city;
//telnet localhost 5554
//geo fix -82.411629 28.054553
//geo fix -121.45356 46.51119 4392
//geo nmea $GPGGA,001431.092,0118.2653,N,10351.1359,E,0,00,,-19.6,M,4.1,M,,0000*5B
document.getElementById("Latitude").innerHTML="latitude:"+latitude;
document.getElementById("Longitude").innerHTML="longitude:"+longitude;
document.getElementById("City").innerHTML="city:"+city;
}
function handle_error(err) {
switch (err.code) {
case 1:
alert("permission denied");
break;
case 2:
alert("the network is down or the position satellites can't be contacted");
break;
case 3:
alert("time out");
break;
default:
alert("unknown error");
break;
}
}
----其中position對(duì)象包含很多數(shù)據(jù) error代碼及選項(xiàng) 可以查看文檔
構(gòu)建HTML5離線應(yīng)用:
需要提供一個(gè)cache manifest文件笙纤,理出所有需要在離線狀態(tài)下使用的資源
例如:
CACHE MANIFEST
#這是注釋
images/sound-icon.png
images/background.png
clock.html
clock.css
clock.js
NETWORK:
test.cgi
CACHE:
style/default.css
FALLBACK:
/files/projects /projects
在html標(biāo)簽中聲明 <html manifest="clock.manifest">?
HTML5離線應(yīng)用更新緩存機(jī)制
分為手動(dòng)更新和自動(dòng)更新2種
自動(dòng)更新:
在cache manifest文件本身發(fā)生變化時(shí)更新緩存 資源文件發(fā)生變化不會(huì)觸發(fā)更新
手動(dòng)更新:
使用window.applicationCache
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.update();
}
在線狀態(tài)檢測(cè)
HTML5 提供了兩種檢測(cè)是否在線的方式:navigator.online(true/false) 和 online/offline事件耗溜。
在Android中構(gòu)建離線應(yīng)用:
//開啟應(yīng)用程序緩存
webSettingssetAppCacheEnabled(true);
String dir = this.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath();
//設(shè)置應(yīng)用緩存的路徑
webSettings.setAppCachePath(dir);
//設(shè)置緩存的模式
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
//設(shè)置應(yīng)用緩存的最大尺寸
webSettings.setAppCacheMaxSize(1024*1024*8);
//擴(kuò)充緩存的容量
public void onReachedMaxAppCacheSize(long spaceNeeded,
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(spaceNeeded * 2);
}
Android與JS之間的互相調(diào)用
在JS中調(diào)用Android的函數(shù)方法
final class InJavaScript {
public void runOnAndroidJavaScript(final String str) {
handler.post(new Runnable() {
public void run() {
TextView show = (TextView) findViewById(R.id.textview);
show.setText(str);
}
});
}
}
//把本類的一個(gè)實(shí)例添加到j(luò)s的全局對(duì)象window中,
//這樣就可以使用window.injs來(lái)調(diào)用它的方法
webView.addJavascriptInterface(new InJavaScript(), "injs");
在JavaScript中調(diào)用:
function sendToAndroid(){
var str = "Cookie call the Android method from js";
window.injs.runOnAndroidJavaScript(str);//調(diào)用android的函數(shù)
}
在Android中調(diào)用JS的方法:
在JS中的方法:
function getFromAndroid(str){
document.getElementById("android").innerHTML=str;
}
在Android調(diào)用該方法:
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
//調(diào)用javascript中的方法
webView.loadUrl("javascript:getFromAndroid('Cookie call the js function from Android')");
}
});
Android中處理JS的警告省容,對(duì)話框等
在Android中處理JS的警告抖拴,對(duì)話框等需要對(duì)WebView設(shè)置WebChromeClient對(duì)象:
//設(shè)置WebChromeClient
webView.setWebChromeClient(new WebChromeClient(){
//處理javascript中的alert
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
//構(gòu)建一個(gè)Builder來(lái)顯示網(wǎng)頁(yè)中的對(duì)話框
Builder builder = new Builder(MainActivity.this);
builder.setTitle("Alert");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
};
//處理javascript中的confirm
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
Builder builder = new Builder(MainActivity.this);
builder.setTitle("confirm");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
};
@Override
//設(shè)置網(wǎng)頁(yè)加載的進(jìn)度條
public void onProgressChanged(WebView view, int newProgress) {
MainActivity.this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress * 100);
super.onProgressChanged(view, newProgress);
}
//設(shè)置應(yīng)用程序的標(biāo)題title
public void onReceivedTitle(WebView view, String title) {
MainActivity.this.setTitle(title);
super.onReceivedTitle(view, title);
}
});
Android中的調(diào)試:
通過(guò)JS代碼輸出log信息:
Js代碼: console.log("Hello World");
Log信息: Console: Hello World http://www.example.com/hello.html :82
在WebChromeClient中實(shí)現(xiàn)onConsoleMesaage()回調(diào)方法,讓其在LogCat中打印信息:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebChromeClient(new WebChromeClient() {
public void onConsoleMessage(String message, int lineNumber, String sourceID) {
Log.d("MyApplication", message + " -- From line "
+ lineNumber + " of "
+ sourceID);
}
});
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebChromeClient(new WebChromeClient() {
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d("MyApplication", cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
});
---ConsoleMessage 還包括一個(gè) MessageLevel 表示控制臺(tái)傳遞信息類型腥椒。
您可以用messageLevel()查詢信息級(jí)別阿宅,以確定信息的嚴(yán)重程度,然后使用適當(dāng)?shù)腖og方法或采取其他適當(dāng)?shù)拇胧?/code>
后面的內(nèi)容在下篇中繼續(xù)