您的位置:首页 > 移动开发

【转】浅谈WebView的使用

2014-02-27 17:34 393 查看
原文:http://blog.csdn.net/liuhe688/article/details/6549263

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的代码:

[java] view
plaincopy

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方法除了能加载远程页面,还能加载本地的文件:

[java] view
plaincopy

//加载assets中的html文件

webView.loadUrl("file:///android_asset/index.html");

//加载sdcard中的html文件

webView.loadUrl("file:///mnt/sdcard/index.html");

这些都会在后边的示例中使用到。

CaptureActivity:

与之对应的布局文件为capture.xml,也比较简单,它的演示效果如下:





记得在AndroidManifest.xml中加入对sdcard的写权限:

[xhtml] view
plaincopy

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

截图成功后,在/mnt/sdcard目录下会生成一个当前网页的截图,如图:



我们导出一下,看看是不是当前的网页界面:



整个过程操作已经完成了,让我们来看一下CaptureActivity.java的代码:

[java] view
plaincopy

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代码如下:

[java] view
plaincopy

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目录下,然后用以下方式加载也能达到相同的效果:

[java] view
plaincopy

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代码如下:

[java] view
plaincopy

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的代码:

[c-sharp] view
plaincopy

/**

* 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线程,定义如下:

[c-sharp] view
plaincopy

/* Wake up the WebCore thread. */

protected final void wakeUp() {

if (mReady) {

synchronized (mProxy) {

mProxy.notify();

}

} else {

mTriedToNotifyBeforeReady = true;

}

}

所以朋友们如果要重写这几个方法时要切记处理JsResult这个对象实例。

我们在处理onJsPrompt时,使用了自定义的界面,加载的是/res/layout/prompt.xml,定义如下:

[xhtml] view
plaincopy

<?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代码,如下:

[xhtml] view
plaincopy

<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>

WebView的优点还不止这些,希望在今后的时间里,再和大家分享WebView的相关技术,也希望这篇文章能够对初识WebView的朋友们带来帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: