浅谈WebView的使用

news/2024/7/5 6:54:46

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 plain copy print ?
  1. package com.scott.webview;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.KeyEvent;  
  6. import android.view.View;  
  7. import android.view.Window;  
  8. import android.webkit.WebChromeClient;  
  9. import android.webkit.WebSettings;  
  10. import android.webkit.WebView;  
  11. import android.webkit.WebViewClient;  
  12. import android.widget.Button;  
  13. import android.widget.EditText;  
  14.   
  15. public class LoadActivity extends Activity {  
  16.       
  17.     private WebView webView;  
  18.       
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.           
  23.         //设置窗口风格为进度条   
  24.         getWindow().requestFeature(Window.FEATURE_PROGRESS);  
  25.           
  26.         setContentView(R.layout.load);  
  27.           
  28.         webView = (WebView) findViewById(R.id.webView);  
  29.           
  30.         WebSettings settings = webView.getSettings();  
  31.         settings.setSupportZoom(true);          //支持缩放   
  32.         settings.setBuiltInZoomControls(true);  //启用内置缩放装置   
  33.         settings.setJavaScriptEnabled(true);    //启用JS脚本   
  34.           
  35.         webView.setWebViewClient(new WebViewClient() {  
  36.             //当点击链接时,希望覆盖而不是打开新窗口   
  37.             @Override  
  38.             public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  39.                 view.loadUrl(url);  //加载新的url   
  40.                 return true;    //返回true,代表事件已处理,事件流到此终止   
  41.             }  
  42.         });  
  43.           
  44.         //点击后退按钮,让WebView后退一页(也可以覆写Activity的onKeyDown方法)   
  45.         webView.setOnKeyListener(new View.OnKeyListener() {  
  46.             @Override  
  47.             public boolean onKey(View v, int keyCode, KeyEvent event) {  
  48.                 if (event.getAction() == KeyEvent.ACTION_DOWN) {  
  49.                     if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {  
  50.                         webView.goBack();   //后退   
  51.                         return true;    //已处理   
  52.                     }  
  53.                 }  
  54.                 return false;  
  55.             }  
  56.         });  
  57.           
  58.         webView.setWebChromeClient(new WebChromeClient() {  
  59.             //当WebView进度改变时更新窗口进度   
  60.             @Override  
  61.             public void onProgressChanged(WebView view, int newProgress) {  
  62.                 //Activity的进度范围在0到10000之间,所以这里要乘以100   
  63.                 LoadActivity.this.setProgress(newProgress * 100);  
  64.             }  
  65.         });  
  66.           
  67.         final EditText url = (EditText) findViewById(R.id.url);  
  68.           
  69.         Button loadURL = (Button) findViewById(R.id.loadURL);  
  70.         loadURL.setOnClickListener(new View.OnClickListener() {  
  71.             @Override  
  72.             public void onClick(View v) {  
  73.                 webView.loadUrl(url.getText().toString());  //加载url   
  74.                 webView.requestFocus(); //获取焦点   
  75.             }  
  76.         });  
  77.     }  
  78. }  

可以看到,我们使用loadUrl方法加载一个url页面,然后重写WebChromeClient的onProgressChanged方法更新进度条。loadUrl方法除了能加载远程页面,还能加载本地的文件:

[java] view plain copy print ?
  1. //加载assets中的html文件   
  2. webView.loadUrl("file:///android_asset/index.html");  
  3. //加载sdcard中的html文件   
  4. webView.loadUrl("file:///mnt/sdcard/index.html");  

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

CaptureActivity:

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

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

[xhtml] view plain copy print ?
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  

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

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

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

[java] view plain copy print ?
  1. package com.scott.webview;  
  2.   
  3. import java.io.FileOutputStream;  
  4.   
  5. import android.app.Activity;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Picture;  
  9. import android.os.Bundle;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.webkit.WebView;  
  13. import android.widget.Button;  
  14. import android.widget.Toast;  
  15.   
  16. public class CaptureActivity extends Activity {  
  17.       
  18.     private static final String TAG = "CAPTURE";  
  19.       
  20.     private WebView webView;  
  21.       
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.           
  26.         setContentView(R.layout.capture);  
  27.           
  28.         webView = (WebView) findViewById(R.id.webView);  
  29.         webView.loadUrl("http://www.baidu.com");  
  30.           
  31.         Button capture = (Button) findViewById(R.id.capture);  
  32.         capture.setOnClickListener(new View.OnClickListener() {  
  33.             @Override  
  34.             public void onClick(View v) {  
  35.                 //取得android.graphics.Picture实例   
  36.                 Picture picture = webView.capturePicture();  
  37.                 int width = picture.getWidth();  
  38.                 int height = picture.getHeight();  
  39.                 if (width > 0 && height > 0) {  
  40.                     //创建指定高宽的Bitmap对象   
  41.                     Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);  
  42.                     //创建Canvas,并以bitmap为绘制目标   
  43.                     Canvas canvas = new Canvas(bitmap);  
  44.                     //将WebView影像绘制在Canvas上   
  45.                     picture.draw(canvas);  
  46.                     try {  
  47.                         String fileName = "/sdcard/webview_capture.jpg";  
  48.                         FileOutputStream fos = new FileOutputStream(fileName);  
  49.                         //压缩bitmap到输出流中   
  50.                         bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);  
  51.                         fos.close();  
  52.                         Toast.makeText(CaptureActivity.this"CAPTURE SUCCESS", Toast.LENGTH_LONG).show();  
  53.                     } catch (Exception e) {  
  54.                         Log.e(TAG, e.getMessage());  
  55.                     }  
  56.                 }  
  57.             }  
  58.         });  
  59.     }  
  60. }  

FileActivity:

这个界面没有布局文件,在代码中完成,它将演示如何加载一段html代码,并应用刚才生成的网页截图,效果如下图:

在这个过程中,我们加载了截图,并给图加上了红色的边框,CaptureActivity.java代码如下:

[java] view plain copy print ?
  1. package com.scott.webview;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.webkit.WebView;  
  6.   
  7. public class FileActivity extends Activity {  
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         WebView webView = new WebView(this);  
  12.         webView.getSettings().setAllowFileAccess(true); //默认就是启用的,这里只是强调一下   
  13.         String baseURL = "file:///mnt/sdcard/";         //根URL  
  14.         String html = "<html><body>"  
  15.                     + "<h3>image from sdcard:<h3><br/>"  
  16.                     + "<img src='webview_capture.jpg' style='border:2px solid #FF0000;'/>"   
  17.                     + "</body></html>";  
  18.         //加载相对于根URL下的数据,historyUrl设为null即可   
  19.         webView.loadDataWithBaseURL(baseURL, html, "text/html""utf-8"null);  
  20.           
  21.         setContentView(webView);  
  22.     }  
  23. }  

 如果将html文本保存成.html文件,放于/mnt/sdcard目录下,然后用以下方式加载也能达到相同的效果:

[java] view plain copy print ?
  1. 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 plain copy print ?
  1. package com.scott.webview;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.app.AlertDialog;  
  8. import android.content.DialogInterface;  
  9. import android.os.Bundle;  
  10. import android.os.Handler;  
  11. import android.os.Message;  
  12. import android.util.Log;  
  13. import android.view.LayoutInflater;  
  14. import android.view.View;  
  15. import android.view.Window;  
  16. import android.webkit.JsPromptResult;  
  17. import android.webkit.JsResult;  
  18. import android.webkit.WebChromeClient;  
  19. import android.webkit.WebView;  
  20. import android.widget.EditText;  
  21. import android.widget.Toast;  
  22.   
  23. public class JSActivity extends Activity {  
  24.       
  25.     private static final String TAG = "JSActivity";  
  26.       
  27.     private  WebView webView;  
  28.       
  29.     private Handler handler = new Handler() {  
  30.         public void handleMessage(android.os.Message msg) {  
  31.             int index = msg.arg1;  
  32.             JSActivity.this.setProgress(index * 1000);  
  33.         };  
  34.     };  
  35.       
  36.     @Override  
  37.     public void onCreate(Bundle savedInstanceState) {  
  38.         super.onCreate(savedInstanceState);  
  39.           
  40.         getWindow().requestFeature(Window.FEATURE_PROGRESS);  
  41.           
  42.         webView = new WebView(this);  
  43.           
  44.         webView.getSettings().setJavaScriptEnabled(true);  
  45.           
  46.         webView.addJavascriptInterface(new Object() {  
  47.             @SuppressWarnings("unused")  
  48.             public List<String> getList() {  
  49.                 List<String> list = new ArrayList<String>();  
  50.                 for (int i = 0; i <= 10; i++) {  
  51.                     try {  
  52.                         Thread.sleep(200);  
  53.                     } catch (InterruptedException e) {  
  54.                         Log.e(TAG, "error:" + e.getMessage());  
  55.                     }  
  56.                     list.add("current index is: " + i);  
  57.                       
  58.                     //不能在此直接调用Activity.setProgress,否则会报以下错误   
  59.                     //Only the original thread that created a view hierarchy can touch its views.   
  60.                     Message msg = handler.obtainMessage();  
  61.                     msg.arg1 = i;  
  62.                     handler.sendMessage(msg);  
  63.                 }  
  64.                 success();  
  65.                 return list;  
  66.             }  
  67.               
  68.             public void success() {  
  69.                 //由Java代码调用JS函数   
  70.                 webView.loadUrl("javascript:success('congratulations')");  
  71.             }  
  72.         }, "bridge");  
  73.           
  74.         webView.setWebChromeClient(new WebChromeClient() {  
  75.             @Override  
  76.             public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {  
  77.                 new AlertDialog.Builder(JSActivity.this)  
  78.                         .setTitle("alert")  
  79.                         .setMessage(message)  
  80.                         .setPositiveButton("YES"new DialogInterface.OnClickListener() {  
  81.                             @Override  
  82.                             public void onClick(DialogInterface dialog, int which) {  
  83.                                 //处理结果为确定状态 同时唤醒WebCore线程   
  84.                                 result.confirm();  
  85.                             }  
  86.                         }).create().show();  
  87.                 return true;    //已处理   
  88.             }  
  89.   
  90.             @Override  
  91.             public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {  
  92.                 new AlertDialog.Builder(JSActivity.this)  
  93.                         .setTitle("confirm")  
  94.                         .setMessage(message)  
  95.                         .setPositiveButton("YES"new DialogInterface.OnClickListener() {  
  96.                             @Override  
  97.                             public void onClick(DialogInterface dialog, int which) {  
  98.                                 Toast.makeText(JSActivity.this"you clicked yes"0).show();  
  99.                                 result.confirm();  
  100.                             }  
  101.                         })  
  102.                         .setNegativeButton("NO"new DialogInterface.OnClickListener() {  
  103.                             @Override  
  104.                             public void onClick(DialogInterface dialog, int which) {  
  105.                                 //处理结果为取消状态 同时唤醒WebCore线程   
  106.                                 result.cancel();  
  107.                             }  
  108.                         }).create().show();  
  109.                 return true;  
  110.             }  
  111.               
  112.             @Override  
  113.             public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,  
  114.                     final JsPromptResult result) {  
  115.                 LayoutInflater inflater = getLayoutInflater();  
  116.                 View prompt = inflater.inflate(R.layout.prompt, null);  
  117.                 final EditText text = (EditText) prompt.findViewById(R.id.prompt_input);  
  118.                 text.setHint(defaultValue);  
  119.                   
  120.                 new AlertDialog.Builder(JSActivity.this)  
  121.                         .setTitle("prompt")  
  122.                         .setView(prompt)  
  123.                         .setPositiveButton("YES"new DialogInterface.OnClickListener() {  
  124.                             @Override  
  125.                             public void onClick(DialogInterface dialog, int which) {  
  126.                                 //记录结果   
  127.                                 result.confirm(text.getText().toString());  
  128.                             }  
  129.                         })  
  130.                         .setNegativeButton("NO"new DialogInterface.OnClickListener() {  
  131.                             @Override  
  132.                             public void onClick(DialogInterface dialog, int which) {  
  133.                                 result.cancel();  
  134.                             }  
  135.                         }).create().show();  
  136.                 return true;  
  137.             }  
  138.         });  
  139.   
  140.         //加载assets中的html文件   
  141.         webView.loadUrl("file:///android_asset/index.html");  
  142.           
  143.         setContentView(webView);  
  144.     }  
  145. }  

需要注意的是,在重写onJsAlert、onJsConfirm、onJsPrompt这几个方法中,不要忘了用JsResult.confirm()或JsResult.cancel()处理结果,否则页面就不能再响应接下的事件了,关于这一点,我们可以看一下JsResult的代码:

[c-sharp] view plain copy print ?
  1. /** 
  2.      * Handle a confirmation response from the user. 
  3.      */  
  4.     public final void confirm() {  
  5.         mResult = true;  
  6.         wakeUp();  
  7.     }  
  8.   
  9. /** 
  10.      * Handle the result if the user cancelled the dialog. 
  11.      */  
  12.     public final void cancel() {  
  13.         mResult = false;  
  14.         wakeUp();  
  15.     }  

可以看到confirm和cancel方法都涉及到了一个wakeUp方法,这个方法主要作用是唤醒WebCore线程,定义如下:

[c-sharp] view plain copy print ?
  1. /* Wake up the WebCore thread. */  
  2.     protected final void wakeUp() {  
  3.         if (mReady) {  
  4.             synchronized (mProxy) {  
  5.                 mProxy.notify();  
  6.             }  
  7.         } else {  
  8.             mTriedToNotifyBeforeReady = true;  
  9.         }  
  10.     }  

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

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

[xhtml] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.   xmlns:android="http://schemas.android.com/apk/res/android"  
  4.   android:layout_width="wrap_content"  
  5.   android:layout_height="wrap_content">  
  6.   <EditText  
  7.         android:id="@+id/prompt_input"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"/>  
  10. </LinearLayout>  

在JSActivity.java代码中,我们注意到WebView组件加载了assets中的index.html,它包含与Java交互的JS代码,如下:

[xhtml] view plain copy print ?
  1. <html>  
  2.     <head>  
  3.         <script type="text/javascript">  
  4.             function doAlert() {  
  5.                 alert("hello!");  
  6.             }  
  7.   
  8.             function doConfirm() {  
  9.                 confirm("are you sure?");  
  10.             }  
  11.   
  12.             function doPrompt() {  
  13.                 var val = prompt("what's your name?");  
  14.                 if (val) {  
  15.                     alert("your name is:" + val);  
  16.                 }  
  17.             }  
  18.   
  19.             function getList() {  
  20.                 //使用java和javascript的接口bridge的方法获取集合  
  21.                 var list = window.bridge.getList();  
  22.                 var result = document.getElementById("result");  
  23.                 for (var i = 0; i < list.size(); i++) {  
  24.                     var div = document.createElement("div");  
  25.                     div.innerHTML = list.get(i).toString();  
  26.                     result.appendChild(div);  
  27.                 }  
  28.             }  
  29.   
  30.             function success(msg) {  
  31.                 alert(msg);  
  32.             }  
  33.         </script>  
  34.     </head>  
  35.     <body background="black">  
  36.         <input type="button" value="alert" onclick="doAlert()"/><br/>  
  37.         <input type="button" value="confirm" onclick="doConfirm()"/><br/>  
  38.         <input type="button" value="prompt" onclick="doPrompt()"/><br/>  
  39.         <input type="button" value="getList" onclick="getList()"/><br/>  
  40.         <div id="result"></div>  
  41.     </body>  
  42. </html>  

WebView的优点还不止这些,希望在今后的时间里,再和大家分享WebView的相关技术,也希望这篇文章能够对初识WebView的朋友们带来帮助。


原网址:http://blog.csdn.net/liuhe688/article/details/6549263




http://www.niftyadmin.cn/n/3649514.html

相关文章

Oracle Database 12C 安装与连接

Oracle Database&#xff0c;又名Oracle RDBMS&#xff0c;或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统&#xff0c;系统可移植性好、使用方便、功能强&#x…

dcoker inspec_如何使用InSpec和Kitchen测试您的Ansible部署

dcoker inspecThe author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program. 作者选择了“技术多元化”基金来接受捐赠&#xff0c;这是Write for DOnations计划的一部分。 介绍 (Introduction) InSpec is an open-sou…

移动端开发:ionic集成toast消息提示插件

新建toast.service文件进行方法封装 1、新建文件命令 ionic g service service/toast 2、toast.service完整代码 import { Injectable } from angular/core; import {ToastController} from "ionic/angular";Injectable({providedIn: root }) export class ToastServ…

[EnterpriseLibrary]为什么拒绝ASPNET对性能数据进行访问

[EntLib]为什么拒绝ASPNET对性能数据进行访问编写者日期关键词郑昀ultrapower2005-6-27”Enterprise Library” ASP.NET PerfLib WMI浏览我们的ASP.NET站点&#xff0c;得到了这样的页面错误提示&#xff1a;拒绝对注册表项的访问。背景&#xff1a;在一台很干净的Windows 2000…

android的widget讲解

一、主要框架 1、AppWidgetProvider &#xff1a;继承自 BroadcastRecevier &#xff0c; 在AppWidget 应用 update、enable、disable 和 delete 时接收通知。其中&#xff0c;onUpdate、onReceive 是最常用到的方法&#xff0c;它们接收更新通知。 bindAppWidgetId(int appWi…

非托管对象 和托管对象_如何使用托管数据库和对象存储设置可扩展的Laravel 6应用程序

非托管对象 和托管对象介绍 (Introduction) When scaling web applications horizontally, the first difficulties you’ll typically face are dealing with file storage and data persistence. This is mainly due to the fact that it is hard to maintain consistency of…

微笑涛声博客正式关联第三方博客平台

第三方博客平台简介 第三方博客指的是不要求自己有域名&#xff0c;空间&#xff0c;服务器&#xff0c;仅在大型门户网址注册就可运行的博客平台。 这类博客有新浪&#xff0c;搜狐&#xff0c;和讯&#xff0c;网易等。第三方博客现在已经成为更多网络爱好者发布自己心情&…