Android WebView应用详解
来源:互联网 发布:ubuntu配置jdk1.8 编辑:程序博客网 时间:2024/06/11 08:45
蛙扑安卓:
WebView是Android中一个非常实用的组件,它和Safai、Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面。使用WebView开发软件有一下几个优点:
1.可以打开远程URL页面,也可以加载本地HTML数据;
2.可以无缝的在java和javascript之间进行交互操作;
3.高度的定制性,可根据开发者的需要进行多样性定制。
下面就通过例子来介绍一下WebView的使用方法。
我们先建一个webview项目,项目结构如左图:
在这个项目中,我们会先进入MainActivity这个导航界面(上边右图),通过点击不同按钮转向不同的Activity,下面分别简单介绍一下这几个Activity的所要演示的功能:
LoadActivity:主要演示加载网络页面和WebView的一些基本设置;
CaptureActivity:主要演示WebView的截图的功能;
FileActivity:主要演示访问本地文件的功能;
JSActivity:主要演示WebView对JS的支持以及JS和Java之间的互相调用;
接下来,我们会逐一分析各个Activity的相关信息:
LoadActivity:
与之对应的布局文件为load.xml,演示效果如下:
我们在文本框中输入URL,然后点击“load”按钮,然后由WebView加载相应的页面,在加载过程中,根据加载进度更新窗口的进度条。由于布局相对简单,我们主要来看一下LoadActivity.java的代码:
package
com.scott.webview;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.KeyEvent;
import
android.view.View;
import
android.view.Window;
import
android.webkit.WebChromeClient;
import
android.webkit.WebSettings;
import
android.webkit.WebView;
import
android.webkit.WebViewClient;
import
android.widget.Button;
import
android.widget.EditText;
public
class
LoadActivity
extends
Activity {
private
WebView webView;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
//设置窗口风格为进度条
getWindow().requestFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.load);
webView = (WebView) findViewById(R.id.webView);
WebSettings settings = webView.getSettings();
settings.setSupportZoom(
true
);
//支持缩放
settings.setBuiltInZoomControls(
true
);
//启用内置缩放装置
settings.setJavaScriptEnabled(
true
);
//启用JS脚本
webView.setWebViewClient(
new
WebViewClient() {
//当点击链接时,希望覆盖而不是打开新窗口
@Override
public
boolean
shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
//加载新的url
return
true
;
//返回true,代表事件已处理,事件流到此终止
}
});
//点击后退按钮,让WebView后退一页(也可以覆写Activity的onKeyDown方法)
webView.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 && webView.canGoBack()) {
webView.goBack();
//后退
return
true
;
//已处理
}
}
return
false
;
}
});
webView.setWebChromeClient(
new
WebChromeClient() {
//当WebView进度改变时更新窗口进度
@Override
public
void
onProgressChanged(WebView view,
int
newProgress) {
//Activity的进度范围在0到10000之间,所以这里要乘以100
LoadActivity.
this
.setProgress(newProgress *
100
);
}
});
final
EditText url = (EditText) findViewById(R.id.url);
Button loadURL = (Button) findViewById(R.id.loadURL);
loadURL.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
webView.loadUrl(url.getText().toString());
//加载url
webView.requestFocus();
//获取焦点
}
});
}
}
可以看到,我们使用loadUrl方法加载一个url页面,然后重写WebChromeClient的onProgressChanged方法更新进度条。loadUrl方法除了能加载远程页面,还能加载本地的文件:
//加载assets中的html文件
webView.loadUrl(
"file:///android_asset/index.html"
);
//加载sdcard中的html文件
webView.loadUrl(
"file:///mnt/sdcard/index.html"
);
这些都会在后边的示例中使用到。
CaptureActivity:
与之对应的布局文件为capture.xml,也比较简单,它的演示效果如下:
记得在AndroidManifest.xml中加入对sdcard的写权限:
<uses-permission android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
截图成功后,在/mnt/sdcard目录下会生成一个当前网页的截图,如图:
我们导出一下,看看是不是当前的网页界面:
整个过程操作已经完成了,让我们来看一下CaptureActivity.java的代码:
package
com.scott.webview;
import
java.io.FileOutputStream;
import
android.app.Activity;
import
android.graphics.Bitmap;
import
android.graphics.Canvas;
import
android.graphics.Picture;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.View;
import
android.webkit.WebView;
import
android.widget.Button;
import
android.widget.Toast;
public
class
CaptureActivity
extends
Activity {
private
static
final
String TAG =
"CAPTURE"
;
private
WebView webView;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.capture);
webView = (WebView) findViewById(R.id.webView);
webView.loadUrl(
"http://www.baidu.com"
);
Button capture = (Button) findViewById(R.id.capture);
capture.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
//取得android.graphics.Picture实例
Picture picture = webView.capturePicture();
int
width = picture.getWidth();
int
height = picture.getHeight();
if
(width >
0
&& height >
0
) {
//创建指定高宽的Bitmap对象
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//创建Canvas,并以bitmap为绘制目标
Canvas canvas =
new
Canvas(bitmap);
//将WebView影像绘制在Canvas上
picture.draw(canvas);
try
{
String fileName =
"/sdcard/webview_capture.jpg"
;
FileOutputStream fos =
new
FileOutputStream(fileName);
//压缩bitmap到输出流中
bitmap.compress(Bitmap.CompressFormat.PNG,
90
, fos);
fos.close();
Toast.makeText(CaptureActivity.
this
,
"CAPTURE SUCCESS"
, Toast.LENGTH_LONG).show();
}
catch
(Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
});
}
}
FileActivity:
这个界面没有布局文件,在代码中完成,它将演示如何加载一段html代码,并应用刚才生成的网页截图,效果如下图:
在这个过程中,我们加载了截图,并给图加上了红色的边框,CaptureActivity.java代码如下:
package
com.scott.webview;
import
android.app.Activity;
import
android.os.Bundle;
import
android.webkit.WebView;
public
class
FileActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
WebView webView =
new
WebView(
this
);
webView.getSettings().setAllowFileAccess(
true
);
//默认就是启用的,这里只是强调一下
String baseURL =
"file:///mnt/sdcard/"
; //根URL
String html =
"<html><body>"
+
"<h3>image from sdcard:<h3><br/>"
+
"<img src='webview_capture.jpg' style='border:2px solid #FF0000;'/>"
+
"</body></html>"
;
//加载相对于根URL下的数据,historyUrl设为null即可
webView.loadDataWithBaseURL(baseURL, html,
"text/html"
,
"utf-8"
,
null
);
setContentView(webView);
}
}
如果将html文本保存成.html文件,放于/mnt/sdcard目录下,然后用以下方式加载也能达到相同的效果:
webView.loadUrl(
"file:///mnt/sdcard/index.html"
);
接下来是最后一个示例:JSActivity,也是最精彩的示例,演示如何在JS和Java之间通信,我们来看一下演示过程,如图:
然后谈谈我们的执行过程,我们需要在Java代码中设置WebView的一些事件的响应,比如alert、confirm以及prompt这些JS事件,让它们按照我们的要求呈现给用户,然后我们需要定义一个Java和JS之间的接口对象,当我们加载完一个html文档后,根据这个对象的接口名称就可以在文档的JS代码中轻松的调用这个接口对象的方法,执行Java代码,我们也可以在Java端执行html文档中的JS代码。下面我们将通过代码来证实这一过程:
JSActivity.java代码如下:
package
com.scott.webview;
import
java.util.ArrayList;
import
java.util.List;
import
android.app.Activity;
import
android.app.AlertDialog;
import
android.content.DialogInterface;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.util.Log;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.Window;
import
android.webkit.JsPromptResult;
import
android.webkit.JsResult;
import
android.webkit.WebChromeClient;
import
android.webkit.WebView;
import
android.widget.EditText;
import
android.widget.Toast;
public
class
JSActivity
extends
Activity {
private
static
final
String TAG =
"JSActivity"
;
private
WebView webView;
private
Handler handler =
new
Handler() {
public
void
handleMessage(android.os.Message msg) {
int
index = msg.arg1;
JSActivity.
this
.setProgress(index *
1000
);
};
};
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_PROGRESS);
webView =
new
WebView(
this
);
webView.getSettings().setJavaScriptEnabled(
true
);
webView.addJavascriptInterface(
new
Object() {
@SuppressWarnings
(
"unused"
)
public
List<String> getList() {
List<String> list =
new
ArrayList<String>();
for
(
int
i =
0
; i <=
10
; i++) {
try
{
Thread.sleep(
200
);
}
catch
(InterruptedException e) {
Log.e(TAG,
"error:"
+ e.getMessage());
}
list.add(
"current index is: "
+ i);
//不能在此直接调用Activity.setProgress,否则会报以下错误
//Only the original thread that created a view hierarchy can touch its views.
Message msg = handler.obtainMessage();
msg.arg1 = i;
handler.sendMessage(msg);
}
success();
return
list;
}
public
void
success() {
//由Java代码调用JS函数
webView.loadUrl(
"javascript:success('congratulations')"
);
}
},
"bridge"
);
webView.setWebChromeClient(
new
WebChromeClient() {
@Override
public
boolean
onJsAlert(WebView view, String url, String message,
final
JsResult result) {
new
AlertDialog.Builder(JSActivity.
this
)
.setTitle(
"alert"
)
.setMessage(message)
.setPositiveButton(
"YES"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
//处理结果为确定状态 同时唤醒WebCore线程
result.confirm();
}
}).create().show();
return
true
;
//已处理
}
@Override
public
boolean
onJsConfirm(WebView view, String url, String message,
final
JsResult result) {
new
AlertDialog.Builder(JSActivity.
this
)
.setTitle(
"confirm"
)
.setMessage(message)
.setPositiveButton(
"YES"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
Toast.makeText(JSActivity.
this
,
"you clicked yes"
,
0
).show();
result.confirm();
}
})
.setNegativeButton(
"NO"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
//处理结果为取消状态 同时唤醒WebCore线程
result.cancel();
}
}).create().show();
return
true
;
}
@Override
public
boolean
onJsPrompt(WebView view, String url, String message, String defaultValue,
final
JsPromptResult result) {
LayoutInflater inflater = getLayoutInflater();
View prompt = inflater.inflate(R.layout.prompt,
null
);
final
EditText text = (EditText) prompt.findViewById(R.id.prompt_input);
text.setHint(defaultValue);
new
AlertDialog.Builder(JSActivity.
this
)
.setTitle(
"prompt"
)
.setView(prompt)
.setPositiveButton(
"YES"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
//记录结果
result.confirm(text.getText().toString());
}
})
.setNegativeButton(
"NO"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
result.cancel();
}
}).create().show();
return
true
;
}
});
//加载assets中的html文件
webView.loadUrl(
"file:///android_asset/index.html"
);
setContentView(webView);
}
}
需要注意的是,在重写onJsAlert、onJsConfirm、onJsPrompt这几个方法中,不要忘了用JsResult.confirm()或JsResult.cancel()处理结果,否则页面就不能再响应接下的事件了,关于这一点,我们可以看一下JsResult的代码:
/**
* Handle a confirmation response from the user.
*/
public
final
void
confirm() {
mResult =
true
;
wakeUp();
}
/**
* Handle the result if the user cancelled the dialog.
*/
public
final
void
cancel() {
mResult =
false
;
wakeUp();
}
可以看到confirm和cancel方法都涉及到了一个wakeUp方法,这个方法主要作用是唤醒WebCore线程,定义如下:
/* Wake up the WebCore thread. */
protected
final
void
wakeUp() {
if
(mReady) {
synchronized
(mProxy) {
mProxy.notify();
}
}
else
{
mTriedToNotifyBeforeReady =
true
;
}
}
所以朋友们如果要重写这几个方法时要切记处理JsResult这个对象实例。
我们在处理onJsPrompt时,使用了自定义的界面,加载的是/res/layout/prompt.xml,定义如下:
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
>
<EditText
android:id=
"@+id/prompt_input"
android:layout_width=
"fill_parent"
android:layout_height=
"wrap_content"
/>
</LinearLayout>
在JSActivity.java代码中,我们注意到WebView组件加载了assets中的index.html,它包含与Java交互的JS代码,如下:
<html>
<head>
<script type=
"text/javascript"
>
function doAlert() {
alert(
"hello!"
);
}
function doConfirm() {
confirm(
"are you sure?"
);
}
function doPrompt() {
var val = prompt(
"what's your name?"
);
if
(val) {
alert(
"your name is:"
+ val);
}
}
function getList() {
//使用java和javascript的接口bridge的方法获取集合
var list = window.bridge.getList();
var result = document.getElementById(
"result"
);
for
(var i =
0
; i < list.size(); i++) {
var div = document.createElement(
"div"
);
div.innerHTML = list.get(i).toString();
result.appendChild(div);
}
}
function success(msg) {
alert(msg);
}
</script>
</head>
<body background=
"black"
>
<input type=
"button"
value=
"alert"
onclick=
"doAlert()"
/><br/>
<input type=
"button"
value=
"confirm"
onclick=
"doConfirm()"
/><br/>
<input type=
"button"
value=
"prompt"
onclick=
"doPrompt()"
/><br/>
<input type=
"button"
value=
"getList"
onclick=
"getList()"
/><br/>
<div id=
"result"
></div>
</body>
</html>
- Android WebView应用详解
- Android WebView应用详解
- Android WebView应用详解
- Android WebView应用详解
- Android 中 Webview基本应用详解
- Android WebView(一) WebView详解
- android应用开发详解(十)------------------WebView视图
- android webview应用
- android之WebView应用
- Android WebView简单应用
- android webview 简单应用
- Android WebView应用
- android webview 初步应用
- Android WebView应用
- Android中WebView详解
- Android WebView 详解
- android之WebView详解
- Android中WebView详解
- 容易忽略的meta标签
- iOS中9.0与8.0两个版本通讯录操作(兼容版)
- 个人笔记--img、文件流
- C#的Timer
- leetcode - Create Maximum Number
- Android WebView应用详解
- iOS dispatch队列
- 一个有意思的例子
- 把数据填到EXcel里
- Java动态代理(JDKProxy与CGlibProxy)
- java中String byte HexString的转换
- Software-Building-HOWTO_2
- Ext.grid.CheckboxSelectionModel()勾选不上
- Java提高篇-----Java集合细节(一):请为集合指定初始容量