最近做的项目中,遇到个很棘手的问题:
客户给我的数据是有限制的,因此,在返回某条具体页面内容的时候,他只能给我一个html片段,里面包含
文字,图片以及附件的下载地址。如果网页模版规范的爱比较好说,但是他给我的数据中,不确定的因素很多:
比如 可能没有图片,图片和文字穿插在一起,最为重要的是html便签他的嵌套层次和标签个数都是不确定的。
如果我采用解析html提取内容出来的话,估计就掉进坑里了.......
但实际情况中,打算服务器先将客户代码的标签属性删除,只剩骨头,但结果还是不尽人意,因为将所有原本的标签属性删除后,显示还是会有问题........。。。
因此,我看了一下网易新闻等感觉都是采用webview进行展示的,关键是如何封装并处理好数据了。
学走路,还是从模仿开始。这里借鉴了大牛们的博客,经验,再次一并谢过:
http://blog.csdn.net/zi413293813/article/details/18144055
http://blog.csdn.net/kavensu/article/details/7931480
http://blog.csdn.net/wangtingshuai/article/details/8635787
http://blog.csdn.net/chenshijun0101/article/details/7045394
我的需求:下载图片;下载附件、
采用思路:将内容用html展示,并且实现java和js的交互,响应用户点击图片的动作。
这里我写了一个demo,按照上面别人的例子简单封装了一下,当然,这里只是提供一种思路,具体怎么封装怎么去实现更好好还是的要具体问题具体分析了。
别忘了:添加写文件权限和网络权限
demo使用测试页面:http://www.cnbeta.com/articles/292267.htm
这里,因为他的内容太多,所以我直接去了主要内容部分,也就是有我文字和图片混搭的部分。
接口:主要用于回调,当然为了扩展的话,还可以添加更多方法。
package com.example.androidwebviewdemo;
/**
* <p>
* </p>
* 下午8:04:06
*
* @auther xiangxm
*/
public interface IOnWebViewCallBack {
/**
* <p>
* 页面加载进度
* </p>
*
* @param progress
* void
*/
void onProgressChanged(int progress);
}
设置webview控件的相关属性:
private void initView() {
progressbar = (ProgressBar) findViewById(R.id.progressbar);
progressbar.setVisibility(View.INVISIBLE);
mWebView = (WebView) findViewById(R.id.webview_ui);
WebSettings settings = mWebView.getSettings();
// 设置webview的相关属性
settings.setJavaScriptEnabled(true);// 允许执行js代码
settings.setBlockNetworkImage(true);
settings.setSupportZoom(false);// 不支持缩放
settings.setBuiltInZoomControls(false);// 内置缩放
settings.setPluginsEnabled(true);
settings.setDefaultTextEncodingName("UTF-8");// 设置默认编码
mWebView.getSettings()
.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);// 禁止由于内容过宽,导致横屏滚动。
mWebView.addJavascriptInterface(new JavaScriptInterface(),
HtmlParser.Js2JavaInterfaceName);
HtmlParser htmlParser = new HtmlParser(mWebView,
"http://www.cnbeta.com/articles/292267.htm", this, this);
htmlParser.execute();
}
HtmlParser:根据别人的代码改变的,我主要把其他的操作都放进来了。感觉这样做会牵扯的太多了,不好扩展,但这里仅仅是个demo而已。
直接上代码:HtmlParser
package com.example.androidwebviewdemo;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/**
* <p>
* html处理的相关类:给图片添加onClick属性。,过滤a标签,添加属性等。、
* </p>
* 下午6:40:37
*
* @auther xiangxm
*/
public class HtmlParser extends AsyncTask<Void, Void, String> {
public static String Js2JavaInterfaceName = "JsUseJava";
private WebView mWebView;
/** 网页地址 **/
private String htmlUrl = "";
private Context mContext;
/** 存储img标签图片地址。 **/
private List<String> imageUrlList = new ArrayList<String>();
public List<String> getImagerUrlList() {
return imageUrlList;
}
public HtmlParser(WebView wevView, String url, Context context,
IOnWebViewCallBack onWebViewCallBack) {
this.mWebView = wevView;
htmlUrl = url;
mContext = context;
this.onWebViewCallBack = onWebViewCallBack;
configWebView();
}
/**
* <p>
* 配置WebView的相关信息
* </p>
* void
*/
private void configWebView() {
//
mWebView.setWebViewClient(new MyWebClient());
mWebView.setWebChromeClient(new MyWebChrome());
}
class MyWebClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mWebView.getSettings().setBlockNetworkImage(false);// 关闭图片阻塞
// 页面加载完成之后,更换图片显示,异步更换图片显示。
DownloadWebImgTask downloadTask = new DownloadWebImgTask(mWebView);
List<String> urlStrs = imageUrlList;
String urlStrArray[] = new String[urlStrs.size() + 1];
urlStrs.toArray(urlStrArray);
downloadTask.execute(urlStrArray);
if (null != onWebViewCallBack) {
onWebViewCallBack.onProgressChanged(View.INVISIBLE);
}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 当连接被点击的时候希望覆盖而不是打开新的窗口
// view.loadUrl(url);
return true;
}
}
class MyWebChrome extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
// 加载的时候显示进度可以在这里添加
if (null != onWebViewCallBack) {
// 加载显示进度的时候
// onWebViewCallBack.onProgressChanged(newProgress);
}
}
}
private IOnWebViewCallBack onWebViewCallBack;
public void setOnWebViewCallBack(IOnWebViewCallBack onWebViewCallBack) {
this.onWebViewCallBack = onWebViewCallBack;
}
/**
* <p>
* 注入js代码,添加Onclick事件
* </p>
*
* @param doc
* void
*/
public void handleImageClickEvent(Document doc) {
Elements es = doc.getElementsByTag("img");
for (Element e : es) {
String imgUrl = e.attr("src");
imageUrlList.add(imgUrl);
String imgName;
File file = new File(imgUrl);
imgName = file.getName();
if (imgName.endsWith(".gif")) {
e.remove();
} else {
String filePath = "file:///mnt/sdcard/test/" + imgName;
e.attr("src", "file:///android_asset/ic_launcher.png");
e.attr("src_link", filePath);
e.attr("ori_link", imgUrl);
String str = "window." + Js2JavaInterfaceName + ".setImgSrc('"
+ filePath + "')";
e.attr("onclick", str);
}
}
}
/**
* <p>
* 与java交互 将a超链接标签,点击后提供下载
* </p>
*
* @param doc
* void
*/
private void handleHyperlinks(Document doc) {
Elements hrefs = doc.getElementsByTag("a");
for (Element href : hrefs) {
String str = "window." + Js2JavaInterfaceName + ".onClick_Tag_A('"
+ href.attr("href") + "')";
href.attr("onclick", str);
}
}
@Override
protected String doInBackground(Void... params) {
if (null != onWebViewCallBack) {
onWebViewCallBack.onProgressChanged(View.VISIBLE);
}
Document doc = null;
imageUrlList.clear();
try {
doc = Jsoup.parse(new URL(htmlUrl), 15000);
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
if (doc == null)
return null;
Elements es = doc.select("script");
if (es != null) {
es.remove();
}
Document docNew = Jsoup.parse(doc.getElementsByClass("article_content")
.html());
handleImageClickEvent(docNew);
handleHyperlinks(docNew);
Log.i("-------->html内容", docNew.toString());
return docNew.toString();
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
mWebView.loadDataWithBaseURL(null, result, "text/html", "utf-8", null);// 这样展示可以有效放置中文乱码
super.onPostExecute(result);
}
}
当点击了图片之后:通常情况下会跳转到浏览器新页面覆盖。这里实现需求是,点击图片不跳转,直接将WebViewClient的shouldOverrideUrlLoading return true;将事件消费掉就OK。
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 当连接被点击的时候希望覆盖而不是打开新的窗口
// view.loadUrl(url);
return true;
}
运行效果图:
demo显示内容的时候有点慢。