Android开发使用WebView实战技巧

转载请注明出处:http://blog.csdn.net/allen315410/article/details/44619181      

        前段时间做项目的时候,在项目中用了WebView组件,遇到了一些问题,所以特地找来了一些资料,学习怎么解决,现在将学习的内容整理成一篇博客记录在这里,方便以后再次遇到时可以快速查看并且解决问题。我们知道,Android中WebView是一个大型的组件,其实WebView是集成了著名的浏览器引擎webkit的一个框架,主要是用来在Android应用中加载渲染网页的。好了,这篇学习笔记之前,我也学习了Google的官方文档,介绍WebView的基本用法,并且翻译好了,地址是:http://blog.csdn.net/allen315410/article/details/44647171,请还没用过WebView的同学,先查看一下这篇文章后,再看我下面的内容。


获取网页的Title信息

我们在打开某些应用的时候,例如今日头条新闻客户端等,有些页面是使用WebView加载的,然而经常在界面的顶端会有标题栏,而且标题栏的内容不是我们自己在程序中写死的,而是动态从网页中获取的,那么我们怎么获取呢?大家都知道,在Html中,一个完整的网页中必然会包含<title></title>标签,标签之间就是标题的内容,so我们只需要将Html中的title标签中的内容获取到就可以了。要获取Title内容就必须设置WebView的setWebChromeClient(WebChromeClient client)方法,传递一个WebChromeClient 对象并且重写其下的shouldOverrideUrlLoading(WebView view, String url)方法,该方法中回调了title就是<title></title>标签间内容。例如:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. ...  
  2. mWebView = (WebView) findViewById(R.id.webview);  
  3. //开启JavaScript支持  
  4. mWebView.getSettings().setJavaScriptEnabled(true);  
  5. //加载网页  
  6. mWebView.loadUrl("http://www.baidu.com");  
  7. //强制在webview打开网页,防止使用系统默认的浏览器打开网页  
  8. mWebView.setWebViewClient(new WebViewClient() {  
  9.   
  10.     @Override  
  11.     public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  12.         view.loadUrl(url);  
  13.         return super.shouldOverrideUrlLoading(view, url);  
  14.     }  
  15.   
  16. });  
  17. mWebView.setWebChromeClient(new WebChromeClient() {  
  18.   
  19.     @Override  
  20.     public void onReceivedTitle(WebView view, String title) {  
  21.         //onReceivedTitle可以回调网页的title  
  22.         tv_title.setText(title);  
  23.         super.onReceivedTitle(view, title);  
  24.     }  
  25.   
  26. });  
  27. ...  

如上图所示,webview中打开了网页,并且将title现在在了TextView标题上。

用WebView下载文件

同样的,当我们在使用浏览器的时候,很多时候会需要下载文件,浏览器是个功能十分强大的应用,可以帮助我们下载网上的文件,那么如果我们的应用中集成了WebView组件,其中渲染的网页也有文件可供下载时,我们该怎么去做下载功能呢?同样,既然浏览器功能那么强大,我们的WebView组件也不差。下面我们看看WebView是怎样下载文件的。

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public class DownloadActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  9.         setContentView(R.layout.activity_download);  
  10.         mWebView = (WebView) findViewById(R.id.webview);  
  11.         // 开启JavaScript支持  
  12.         mWebView.getSettings().setJavaScriptEnabled(true);  
  13.         mWebView.loadUrl("http://img.mukewang.com/down/54eec5f10001b17600000000.zip");  
  14.         mWebView.setWebViewClient(new WebViewClient() {  
  15.             @Override  
  16.             public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  17.                 view.loadUrl(url);  
  18.                 return super.shouldOverrideUrlLoading(view, url);  
  19.             }  
  20.         });  
  21.         // 监听下载  
  22.         mWebView.setDownloadListener(new DownloadListener() {  
  23.   
  24.             @Override  
  25.             public void onDownloadStart(String url, String userAgent,   
  26.                     String contentDisposition, String mimetype, long contentLength) {  
  27.                 System.out.println("url:" + url);  
  28.                 if (url.endsWith(".zip")) {  
  29.                     // 如果传进来url包含.zip文件,那么就开启下载线程  
  30.                     System.out.println("download start...");  
  31.                     new DownloadThread(url).start();  
  32.                 }  
  33.             }  
  34.         });  
  35.     }  
  36.   
  37.     /** 
  38.      * 执行下载的线程 
  39.      */  
  40.     class DownloadThread extends Thread {  
  41.         private String mUrl;  
  42.   
  43.         public DownloadThread(String url) {  
  44.             this.mUrl = url;  
  45.         }  
  46.   
  47.         @Override  
  48.         public void run() {  
  49.             try {  
  50.                 URL httpUrl = new URL(mUrl);  
  51.                 HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();  
  52.                 conn.setDoInput(true);  
  53.                 conn.setDoOutput(true);  
  54.                 conn.setConnectTimeout(5000);  
  55.                 conn.setReadTimeout(5000);  
  56.   
  57.                 InputStream in = conn.getInputStream();  
  58.                 FileOutputStream out = null;  
  59.                 // 获取下载路径  
  60.                 File downloadFile;  
  61.                 File sdFile;  
  62.                 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
  63.                     downloadFile = Environment.getExternalStorageDirectory();  
  64.                     sdFile = new File(downloadFile, "download.zip");  
  65.                     out = new FileOutputStream(sdFile);  
  66.                 }  
  67.                 byte[] b = new byte[8 * 1024];  
  68.                 int len;  
  69.                 while ((len = in.read(b)) != -1) {  
  70.                     if (out != null) {  
  71.                         out.write(b, 0, len);  
  72.                     }  
  73.                 }  
  74.                 if (out != null) {  
  75.                     out.close();  
  76.                 }  
  77.                 if (in != null) {  
  78.                     in.close();  
  79.                 }  
  80.                 System.out.println("download success...");  
  81.             } catch (MalformedURLException e) {  
  82.                 e.printStackTrace();  
  83.             } catch (IOException e) {  
  84.                 e.printStackTrace();  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89. }  

其实特别简单,WebView中已经给我们提供好一个实现下载的接口以及回调方法,这个接口就是android.webkit.DownloadListener,我们首先调用WebView的setDownloadListener(DownloadListener listener)方法,在方法参数中传入DownloadListener对象,重写其中的onDownloadStart方法,在这个方法中开启下载功能的线程,让线程帮助我们去服务器下载文件。


WebView错误码的处理

WebView错误码处理是什么意思呢?我们在使用Android设备的时候,可能某些时候网络不好或者没有网络,这时候设备就访问不到服务器了,加载不了Html页面。一般情况下,当我们的设备无网络情况下加载一个Html时,会自行弹出Android默认的错误页面,如下图:


好了,这就是Android系统中给我们默认的页面了,是不是值得我们吐槽一下呢?同样将这个页面呈现给用户也会被骂死的,那么我们该怎么处理这样的情况呢?方式也很简单,主要有2种方式实现,一是加载一个本地的Html页面,告知网络异常,二是通过布局的方式自定义一个错误提示界面,加载到主界面。好了,上面的两种实现方式都不是重点,我们不讨论怎么制作一个好看的Html Error页面或者一个好看的XML布局。

监听WebView加载出错是在setWebViewClient()的传递WebViewClient对象下的onReceivedError()方法中完成处理的,下面是一个简单的处理方式:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. mWebView.setWebViewClient(new WebViewClient() {  
  2.     ...   
  3.     @Override  
  4.     public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {  
  5.         //网络异常,WebView加载我们自定义的页面  
  6.         super.onReceivedError(view, errorCode, description, failingUrl);  
  7.         view.loadUrl("file:///android_asset/error.html");  
  8.     }  
  9.               
  10. });  
好了,上面代码中做了简单处理:重新加载本地的assets目录的html静态页面。


WebView同步cookie

cookie是什么呢?这里需要一些Java服务器上面的知识了,简单来说Cookie算是服务器上一种缓存机制了,例如我们在登录的时候第一次输入了登录的用户名和密码,并且保存了密码,那么下次我们再次打开这个网页的时候就会自动读取cookie完成自动登录了。如果这个含有cookie的页面使用WebView加载的话,该怎样也能实现相同的功能呢?我们只有设置WebView与Cookie同步即可。

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public class CookieTestActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.   
  5.     private Handler mHandler = new Handler() {  
  6.         public void handleMessage(Message msg) {  
  7.             // 同步Cookie  
  8.             CookieSyncManager.createInstance(CookieTestActivity.this);  
  9.             CookieManager cookieManager = CookieManager.getInstance();  
  10.             cookieManager.setAcceptCookie(true);  
  11.             cookieManager.setCookie("http://192.168.1.105:8080/webs", msg.obj.toString());  
  12.             CookieSyncManager.getInstance().sync();  
  13.             mWebView.loadUrl("http://192.168.1.105:8080/webs/index.jsp");  
  14.         };  
  15.     };  
  16.   
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  21.         setContentView(R.layout.activity_download);  
  22.         mWebView = (WebView) findViewById(R.id.webview);  
  23.         // 开启JavaScript支持  
  24.         mWebView.getSettings().setJavaScriptEnabled(true);  
  25.         String url = "http://192.168.1.105:8080/webs/login.jsp";  
  26.         new HttpCookie(mHandler, url).start();  
  27.     }  
  28.   
  29.     /** 
  30.      * 访问服务器,读取Cookie信息 
  31.      */  
  32.     class HttpCookie extends Thread {  
  33.         private Handler handler;  
  34.         private String url;  
  35.   
  36.         public HttpCookie(Handler handler, String url) {  
  37.             this.handler = handler;  
  38.             this.url = url;  
  39.         }  
  40.   
  41.         @Override  
  42.         public void run() {  
  43.             //使用httpClient向服务器发送POST请求  
  44.             HttpClient client = new DefaultHttpClient();  
  45.             HttpPost post = new HttpPost(url);  
  46.             List<NameValuePair> list = new ArrayList<NameValuePair>();  
  47.             list.add(new BasicNameValuePair("name""zhangsan"));  
  48.             list.add(new BasicNameValuePair("age""22"));  
  49.             try {  
  50.                 post.setEntity(new UrlEncodedFormEntity(list));  
  51.                 HttpResponse response = client.execute(post);  
  52.                 if (response.getStatusLine().getStatusCode() == 200) {  
  53.                     //访问服务器成功,从服务器读取Cookie信息  
  54.                     AbstractHttpClient absClient = (AbstractHttpClient) client;  
  55.                     List<Cookie> cookies = absClient.getCookieStore().getCookies();  
  56.                     for (Cookie cookie : cookies) {  
  57.                         // 将Cookie发送到UI线程  
  58.                         Log.d("TAG""name=" + cookie.getName() + ",age=" + cookie.getValue());  
  59.                         Message message = Message.obtain();  
  60.                         message.obj = cookie;  
  61.                         handler.sendMessage(message);  
  62.                         return;  
  63.                     }  
  64.                 }  
  65.             } catch (UnsupportedEncodingException e) {  
  66.                 e.printStackTrace();  
  67.             } catch (ClientProtocolException e) {  
  68.                 e.printStackTrace();  
  69.             } catch (IOException e) {  
  70.                 e.printStackTrace();  
  71.             }  
  72.         }  
  73.     }  
  74. }  

好,通过上面的示例代码,我们很快就知道怎么设置Cookie同步了,主要代码是在Handler中的。


WebView与JS调用混淆问题

这个问题会经常遇到,当我们在Java中写好了调用JS的代码后,测试的时候完全正常的,然而我们在发布程序的时候,需要混淆打包,混淆打包之后的生存了我们的.apk文件,将apk安装到设备上后,再次调用JS的时候,会发现调用方法失效了,这是一件让人恼火的时候。这时候为了解决这个问题,我们需要对JS调用的相关代码做一些保护,保护措施也非常简单,只需要在混淆文件中将JS调用的Java层代码忽略掉就可以了。

这是Activity:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public class MainActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.activity_main);  
  9.         mWebView = (WebView) findViewById(R.id.webview);  
  10.         mWebView.loadUrl("file:///android_asset/index.html");  
  11.         mWebView.setWebViewClient(new WebViewClient() {  
  12.             @Override  
  13.             public boolean shouldOverrideUrlLoading(WebView view, String url) {  
  14.                 view.loadUrl("file:///android_asset/index.html");  
  15.                 return true;  
  16.             }  
  17.         });  
  18.         mWebView.getSettings().setJavaScriptEnabled(true);  
  19.         mWebView.addJavascriptInterface(new WebHost(this), "js");  
  20.     }  
  21. }  
然后我们还要写一个调用JS类:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public class WebHost {  
  2.         private Context mContext;  
  3.   
  4.         public WebHost(Context context) {  
  5.             this.mContext = context;  
  6.         }  
  7.   
  8.         public void callJS() {  
  9.             Toast.makeText(mContext, "call from js", Toast.LENGTH_SHORT).show();  
  10.         }  
  11.     }  
JS代码如下:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <html>  
  2.   <title>  
  3.     <head>Java与JS回调</head>  
  4.   </title>  
  5.   <body>  
  6.     <p>  
  7.     callJava:<input type="button" value="call from js" onclick="call()"/>  
  8.    </p>  
  9.    <script type="text/javascript">  
  10.     function call(){  
  11.         js.callJS();  
  12.     }  
  13.   </script>  
  14.   </body>  
  15. </html>  
此时写的代码在测试阶段没有问题,然后当混淆打包之后,会出现调用JS失效的可能,解决办法:在混淆配置文件proguard.cfg中忽略WebHost里面的方法

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. -keep public class com.e
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值