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>标签间内容。比如:
...
mWebView = (WebView) findViewById(R.id.webview);
//开启JavaScript支持
mWebView.getSettings().setJavaScriptEnabled(true);
//载入网页
mWebView.loadUrl("http://www.baidu.com");
//强制在webview打开网页,防止使用系统默认的浏览器打开网页
mWebView.setWebViewClient(new WebViewClient() { @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return super.shouldOverrideUrlLoading(view, url);
} });
mWebView.setWebChromeClient(new WebChromeClient() { @Override
public void onReceivedTitle(WebView view, String title) {
//onReceivedTitle能够回调网页的title
tv_title.setText(title);
super.onReceivedTitle(view, title);
} });
...
如上图所看到的。webview中打开了网页。而且将title如今在了TextView标题上。
用WebView下载文件
相同的,当我们在使用浏览器的时候,非常多时候会须要下载文件。浏览器是个功能十分强大的应用。能够帮助我们下载网上的文件,那么假设我们的应用中集成了WebView组件,当中渲染的网页也有文件可供下载时,我们该怎么去做下载功能呢?相同,既然浏览器功能那么强大,我们的WebView组件也不差。以下我们看看WebView是如何下载文件的。
public class DownloadActivity extends Activity { private WebView mWebView; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_download);
mWebView = (WebView) findViewById(R.id.webview);
// 开启JavaScript支持
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadUrl("http://img.mukewang.com/down/54eec5f10001b17600000000.zip");
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return super.shouldOverrideUrlLoading(view, url);
}
});
// 监听下载
mWebView.setDownloadListener(new DownloadListener() { @Override
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype, long contentLength) {
System.out.println("url:" + url);
if (url.endsWith(".zip")) {
// 假设传进来url包括.zip文件,那么就开启下载线程
System.out.println("download start...");
new DownloadThread(url).start();
}
}
});
} /**
* 运行下载的线程
*/
class DownloadThread extends Thread {
private String mUrl; public DownloadThread(String url) {
this.mUrl = url;
} @Override
public void run() {
try {
URL httpUrl = new URL(mUrl);
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000); InputStream in = conn.getInputStream();
FileOutputStream out = null;
// 获取下载路径
File downloadFile;
File sdFile;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
downloadFile = Environment.getExternalStorageDirectory();
sdFile = new File(downloadFile, "download.zip");
out = new FileOutputStream(sdFile);
}
byte[] b = new byte[8 * 1024];
int len;
while ((len = in.read(b)) != -1) {
if (out != null) {
out.write(b, 0, len);
}
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
System.out.println("download success...");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
事实上特别简单,WebView中已经给我们提供好一个实现下载的接口以及回调方法,这个接口就是android.webkit.DownloadListener,我们首先调用WebView的setDownloadListener(DownloadListener listener)方法,在方法參数中传入DownloadListener对象,重写当中的onDownloadStart方法,在这种方法中开启下载功能的线程。让线程帮助我们去server下载文件。
WebView错误码的处理
WebView错误码处理是什么意思呢?我们在使用Android设备的时候,可能某些时候网络不好或者没有网络。这时候设备就訪问不到server了,载入不了Html页面。普通情况下,当我们的设备无网络情况下载入一个Html时,会自行弹出Android默认的错误页面,例如以下图:
好了,这就是Android系统中给我们默认的页面了。是不是值得我们吐槽一下呢?相同将这个页面呈现给用户也会被骂死的,那么我们该怎么处理这种情况呢?方式也非常easy。主要有2种方式实现,一是载入一个本地的Html页面,告知网络异常。二是通过布局的方式自己定义一个错误提示界面。载入到主界面。
好了。上面的两种实现方式都不是重点。我们不讨论怎么制作一个好看的Html Error页面或者一个好看的XML布局。
监听WebView载入出错是在setWebViewClient()的传递WebViewClient对象下的onReceivedError()方法中完毕处理的,以下是一个简单的处理方式:
mWebView.setWebViewClient(new WebViewClient() {
...
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//网络异常,WebView载入我们自己定义的页面
super.onReceivedError(view, errorCode, description, failingUrl);
view.loadUrl("file:///android_asset/error.html");
} });
好了,上面代码中做了简单处理:又一次载入本地的assets文件夹的html静态页面。
WebView同步cookie
cookie是什么呢?这里须要一些Javaserver上面的知识了,简单来说Cookie算是server上一种缓存机制了,比如我们在登录的时候第一次输入了登录的username和password。而且保存了password,那么下次我们再次打开这个网页的时候就会自己主动读取cookie完毕自己主动登录了。假设这个含有cookie的页面使用WebView载入的话,该如何也能实现同样的功能呢?我们仅仅有设置WebView与Cookie同步就可以。
public class CookieTestActivity extends Activity { private WebView mWebView; private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
// 同步Cookie
CookieSyncManager.createInstance(CookieTestActivity.this);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setCookie("http://192.168.1.105:8080/webs", msg.obj.toString());
CookieSyncManager.getInstance().sync();
mWebView.loadUrl("http://192.168.1.105:8080/webs/index.jsp");
};
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_download);
mWebView = (WebView) findViewById(R.id.webview);
// 开启JavaScript支持
mWebView.getSettings().setJavaScriptEnabled(true);
String url = "http://192.168.1.105:8080/webs/login.jsp";
new HttpCookie(mHandler, url).start();
} /**
* 訪问server。读取Cookie信息
*/
class HttpCookie extends Thread {
private Handler handler;
private String url; public HttpCookie(Handler handler, String url) {
this.handler = handler;
this.url = url;
} @Override
public void run() {
//使用httpClient向server发送POST请求
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
List<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("name", "zhangsan"));
list.add(new BasicNameValuePair("age", "22"));
try {
post.setEntity(new UrlEncodedFormEntity(list));
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == 200) {
//訪问server成功。从server读取Cookie信息
AbstractHttpClient absClient = (AbstractHttpClient) client;
List<Cookie> cookies = absClient.getCookieStore().getCookies();
for (Cookie cookie : cookies) {
// 将Cookie发送到UI线程
Log.d("TAG", "name=" + cookie.getName() + ",age=" + cookie.getValue());
Message message = Message.obtain();
message.obj = cookie;
handler.sendMessage(message);
return;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
好,通过上面的演示样例代码。我们非常快就知道怎么设置Cookie同步了,主要代码是在Handler中的。
WebView与JS调用混淆问题
这个问题会常常遇到,当我们在Java中写好了调用JS的代码后。測试的时候全然正常的,然而我们在公布程序的时候。须要混淆打包。混淆打包之后的生存了我们的.apk文件。将apk安装到设备上后。再次调用JS的时候。会发现调用方法失效了,这是一件让人恼火的时候。这时候为了解决问题,我们须要对JS调用的相关代码做一些保护,保护措施也很easy。仅仅须要在混淆文件里将JS调用的Java层代码忽略掉就能够了。
这是Activity:
public class MainActivity extends Activity { private WebView mWebView; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("file:///android_asset/index.html");
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl("file:///android_asset/index.html");
return true;
}
});
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new WebHost(this), "js");
}
}
然后我们还要写一个调用JS类:
public class WebHost {
private Context mContext; public WebHost(Context context) {
this.mContext = context;
} public void callJS() {
Toast.makeText(mContext, "call from js", Toast.LENGTH_SHORT).show();
}
}
JS代码例如以下:
<html>
<title>
<head>Java与JS回调</head>
</title>
<body>
<p>
callJava:<input type="button" value="call from js" onclick="call()"/>
</p>
<script type="text/javascript">
function call(){
js.callJS();
}
</script>
</body>
</html>
此时写的代码在測试阶段没有问题。然后当混淆打包之后,会出现调用JS失效的可能,解决的方法:在混淆配置文件proguard.cfg中忽略WebHost里面的方法
-keep public class com.example.webview_02.WebHost{
public <methods>
}
版权声明:本文博客原创文章。博客,未经同意,不得转载。
Android使用开发WebView战斗技能的更多相关文章
- Android应用开发 WebView与服务器端的Js交互
最近公司再添加功能的时候,有一部分功能是用的html,在一个浏览器或webview中展示出html即可.当然在这里我们当然用webview控件喽 WebApp的好处: 在应用里嵌套web的好处有这么几 ...
- Android 浏览器开发WebView setBlockNetworkImage本末
含义本身防止网络数据图片 webSettings.setBlockNetworkImage(true); 停止发布数据 webSettings.setBlockNetworkImage(false); ...
- Android应用开发中webview上传文件的几种思路
1. 常规方法,重写WebChromeClient 的 openFileChooser 方法 private class MyWebChromeClient extends WebChromeClie ...
- 安卓开发学习笔记(五):史上最简单且华丽地实现Android Stutio当中Webview控件https/http协议的方法
一.我们先在XML当中自定义一个webview(Second_layout.xml) 代码如下: <?xml version="1.0" encoding="utf ...
- Android开发之WebView的开发使用(源码分享)
假设我们想提供一个web应用程序(或仅仅是一个网页)作为client应用程序的一部分,我们能够使用WebView.WebView类是Android的视图类的扩展,它同意您显示web页面的一部分活动布局 ...
- Android开发----WebView&Activity生命周期
WebView webview是一个再应用中设置好位置和大小的浏览器,而且不会放置任何花哨的UI. 在大多数情况下,除非你调用了原生API,否则不必在webview中专门测试web应用. 首先为Web ...
- Android:让WebView支持<input type=”file”…>元素
最近在做一个活动页面:用户上传一张图片进行缩放.旋转后点击下一步填写内容后生成图片! 做好后经过各种测试是没有问题的,基本没有什么明显BUG,流程都能走通,但是嵌入到APP后,问题就来了! 在IOS上 ...
- Android安全开发之安全使用HTTPS
Android安全开发之安全使用HTTPS 1.HTTPS简介 阿里聚安全的应用漏洞扫描器中有证书弱校验.主机名弱校验.webview未校验证书的检测项,这些检测项是针对APP采用HTTPS通信时容易 ...
- android 浏览器开发实例
android app需要通过手机显示网页信息还是比较常用的,比如我最近业余开发的 抢商铺游戏,需要对游戏规则做说明,规则会比较多,而且要经常变动,就想到用网页来展示,更新起来方便,不像应用,一旦发布 ...
随机推荐
- HTML学习笔记之中的一个(input文件选择框的封装)
方式一:直接透明隐藏 .file_button_container,.file_button_container input {background: transparent url(./img/BT ...
- 使用 SQLNET.EXPIRE_TIME 清除僵死连接
数据库连接的客户端异常断开后,其占有的相应并没有被释放,如从v$session视图中依旧可以看到对应的session处于inactive,且对应的服务器进程也没有释放,导致资源长时间地被占用,对于这种 ...
- Spring MVC中一般 普通类调用service
在Spring MVC中,Controller中使用service只需使用注解@Resource就行,但是一般类(即不使用@Controller注解的类)要用到service时,可用如下方法: 1.S ...
- SWT的CheckBoxTreeView
其实CheckBoxTreeView和TreeView基本上是一样的,他们共同的方法有: TreeViewer 类封装了tree控件.树查看器按照父子关系来显示分等级的对象列表.此查看器需要设置标签供 ...
- 本科非cs菜鸟计算机面试实录
两年制小硕,本硕期间差不多都打酱油的.本科非cs专业,硕士cs,编程基础一般,专业基础尚可.研究生期间分析分析了pgsql数据库的源码:同时实验室一些杂项目:自己业余为了应试读了些计算机书.自己当时q ...
- Redhat 6.3中syslog信息丢失
我们採用Linux的syslog来记录产品的debug log. 调用当中的一个可运行文件.运行完命令之后,查看debug log的信息,竟然从某一条log之后的log都丢失了.多次尝试后,发现每次都 ...
- The example program of C on point
计划一: #include<stdio.h> #define N_VALUES 5 int main( void ) { float values[N_VALUES]; float *vp ...
- Coco2dx-3.0中怎样调用LUA
一个用3.0的工具导出类到lua,自己主动生成代码的方法. 曾经要导出c++类到lua.就得手动维护pkg文件,那简直就是噩梦.3.0以后就会感觉生活非常轻松了. 以下我就在说下详细做法. 1.安装必 ...
- Oracle 阅读器-刚看完表空间回复的详细解释
(一) 当使用一个控制文件的备份恢复,例如下面的附图.使用备份控制文件恢复位置 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVtb25zb24=/fo ...
- IOS设计模式学习(21)享元
1 前言 在面向对象软件设计中,利用公共对象不仅能节省资源还能提高性能.共享的对象只能提供某些内在的信息,而不能用来识别对象.专门用于设计可共享对象的一种设计模式叫做享元模式(Flyweight pa ...