这段代码的作用就是加载搜狐主页,并执行js,寻找网页源码里带h3标签的字符串,如果没有h3标签,则直接返回空字符串并取消网页上悬浮按钮的展示。那段js代码参考自这里
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String data2 = (String) msg.obj;
if (TextUtils.isEmpty(data2)) {
button.setVisibility(View.GONE);
} else {
button.setVisibility(View.VISIBLE);
}
}
};
mWebView.loadUrl("http://www.sohu.com/");//举个例子
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebChromeClient(new WebChromeClient() {
});
mWebView.addJavascriptInterface(new MyJavaScriptInterface(), "handler");
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:var name;if(document.getElementsByTagName('h3')[0] != null){name=document.getElementsByTagName('h3')[0].innerHTML; }else{name = \"\";}window.handler.show(name);");
super.onPageFinished(view, url);
}
});
自定义的javainterface
class MyJavaScriptInterface {
@JavascriptInterface
public void show(String data) {
Message msg = Message.obtain();
msg.obj = data;
mHandler.sendMessage(msg);
}
}
mWebView.loadData(previewUrl, "text/html", "UTF-8");
mWebView.loadData(previewUrl, "text/html; charset=UTF-8", "UTF-8");
一个在线的网页,解析得到它的源码,作为字符串,然后根据一定的规则(正则表达式)来获取相应的内容,举两个简单例子
获取我的博客中博文列表,http://blog.csdn.net/diyangxia,如图所示:
主要代码其实就是一段正则,直接在onCreate中调用如下方法即可,该方法会返回一个list集合,放在recyclerview或者listview中显示即可
类似这样
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
getCsdnNetData();
}
}).start();
private List<Map<String, Object>> getCsdnNetData() {
String CSDNURL = "http://blog.csdn.net/diyangxia";
List<Map<String, Object>> data= new ArrayList<Map<String, Object>>();
String csdnString = http_get(CSDNURL);
Log.i("TAG", "csdnString==>" + csdnString);
// (?s) 加在表达式前面可以匹配空格换行等字符
Pattern p = Pattern
.compile("(?s)(.*?)");
Matcher m = p.matcher(csdnString);
while (m.find()) {
MatchResult mr = m.toMatchResult();
Map<String, Object> map = new HashMap<String, Object>();
map.put("url", "http://blog.csdn.net" + mr.group(1));
map.put("title", mr.group(2).replace("\n", "").replace("\r", ""));
data.add(map);
}
Log.i("TAG", "data==>" + data);
return data;
}
这里面的http_get方法,是借了网上一位博友的,就是获取一个网址的源码字符串
/**
* get请求URL,失败时尝试三次
*
* @param url
* 请求网址
* @return 网页内容的字符串
* @author Lai Huan
* @created 2013-6-20
*/
private String http_get(String url) {
final int RETRY_TIME = 3;
HttpClient httpClient = null;
HttpGet httpGet = null;
String responseBody = "";
int time = 0;
do {
try {
httpClient = getHttpClient();
httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
// 用utf-8编码转化为字符串
byte[] bResult = EntityUtils.toByteArray(response
.getEntity());
if (bResult != null) {
responseBody = new String(bResult, "utf-8");
}
}
break;
} catch (IOException e) {
time++;
if (time < RETRY_TIME) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
continue;
}
e.printStackTrace();
} finally {
httpClient = null;
}
} while (time < RETRY_TIME);
return responseBody;
}
private HttpClient getHttpClient() {
HttpParams httpParams = new BasicHttpParams();
// 设定连接超时和读取超时时间
HttpConnectionParams.setConnectionTimeout(httpParams, 6000);
HttpConnectionParams.setSoTimeout(httpParams, 30000);
return new DefaultHttpClient(httpParams);
}
B站 http://www.bilibili.com/newlist.html ,每天应该都会不一样的
与上面最大的区别在于正则匹配,由于对正则的不太熟悉,所以只能写成下面这样冗余的表达式了
Pattern p = Pattern
.compile("\"l1\">([\\w\\W]*?)\"(.*?)\"([\\w\\W]*?)\"(.*?)\">([\\w\\W]*?)vid=\".*\">(.*?)([\\w\\W]*?)\"date\" title=\"日期\">(.*?)([\\w\\W]*?)\"up\" target=\"_blank\">(.*?)([\\w\\W]*?)\"info\">(.*?)([\\w\\W]*?) ");
然后再通过一个for循环把得到的list转成自定义的list
for(int i = 0;i<data.size();i++){
Map<String, Object> map = data.get(i);
VideoListData vData = new VideoListData();
vData.setAuthor((String)map.get("author"));
vData.setDate((String)map.get("date"));
vData.setImage((String)map.get("image"));
vData.setUrl((String)map.get("url"));
vData.setInfo((String)map.get("info"));
vData.setTitle((String)map.get("title"));
mListData.add(vData);
}
<html>
<head>
<meta charset="utf-8">
<title>UI Edittitle>
head>
<body>
<br/>
<span style="font-size:16px">你来自哪里?span>
<a href="diyangxia://title" >
<div id="coordiv" style="width:150px;height:23px;border:1px dashed #c3c3c3">
<span style="font-size:16px" id="title">江苏苏州span>
div>
a>
<p style="font-size:12px;color:grey">温馨提示:虚线框中内容可以编辑p>
body>
html>
为了方便修改html内容,我们把这段html代码直接作为一个字符串变量引用,需要重写webviewclient的shouldOverrideUrlLoading方法,在里面根据超链接的地址(diyangxia://title)去匹配,如果有的话,再根据id的值(title)去取值,取完值后把值和值之前以及值之后的字符串都传给第二个界面,在第二个界面修改完成后拼接完全回传过来再在webview中显示即可
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i("TAG", "url==>" + url);
if (url.equals("diyangxia://title")) {
String idStr = url.substring(10);
String subStr = "id=\"" + idStr + "\">";
int firstIndex = inputStr.indexOf(subStr);
String firstStr = inputStr.substring(0, firstIndex + subStr.length());
Log.i("TAG", "firstStr==>" + firstStr);
String otherStr = inputStr.substring(firstIndex + subStr.length());
Log.i("TAG", "otherStr==>" + otherStr);
int middleIndex = otherStr.indexOf("<");
String middleStr = otherStr.substring(0, middleIndex);
Log.i("TAG", "middleStr==>" + middleStr);
String lastStr = otherStr.substring(middleIndex);
Log.i("TAG", "lastStr==>" + lastStr);
startActivityForResult(new Intent(HtmlActivity.this, EditContentActivity.class).putExtra("title", middleStr).putExtra("first", firstStr).putExtra("last", lastStr), REQUEST_CODE_EDIT);
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
这里以播放视频为例,在html代码的head区添加一个js脚本用来控制video视频的自动且循环播放,因为据测试,直接在video标签中添加autoplay以及loop属性是没有效果的
<script type="text/javascript">
function myFunction()
{
var videos = document.getElementById('videoTag');
videos.loop = 'loop';
videos.play();
}
script>
然后在java代码中要做的是重写webviewclient的onPageFinished方法,这个方法里用webview的loadurl加载js方法
public class MyWebviewCient extends WebViewClient {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
WebResourceResponse response = null;
response = super.shouldInterceptRequest(view, url);
return response;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
webview.loadUrl("javascript:myFunction()");
}
}
<html>
<head>
<meta charset="utf-8">
<title>video fullscreentitle>
head>
<body>
<video id="videoTag" src="http://video-js.zencoder.com/oceans-clip.mp4" controls="controls" height="210px" width="250px">
您的浏览器不支持 video 标签video>
body>
html>
要让html中video标签中的视频能够全屏播放,需要对webview中的WebChromeClient类,重写它的两个方法webview.setWebChromeClient(new MyWebChromeClient());
private class MyWebChromeClient extends WebChromeClient{
// 播放网络视频时会被调用
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if(myView != null){
callback.onCustomViewHidden();
return;
}
frameLayout.removeView(wb);
frameLayout.addView(view);
myView = view;
myCallback = callback;
}
// 视频播放完成会被调用
@Override
public void onHideCustomView() {
if(myView == null){
return;
}
frameLayout.removeView(myView);
myView = null;
frameLayout.addView(wb);
myCallback.onCustomViewHidden();
}
}
退出全屏的功能直接控制系统返回键即可,这里的framelayout就是包裹在webview外层的FrameLayout布局,chromeClient就是上面类的实例
@Override
public void onBackPressed() {
if(myView == null){
super.onBackPressed();
}
else{
chromeClient.onHideCustomView();
}
}
PhoneGap是一个用基于HTML,CSS和JavaScript的,创建移动跨平台移动应用程序的快速开发平台。它使开发者能够利用iPhone,Android,Palm,Symbian,WP7,WP8,Bada和Blackberry智能手机的核心功能——包括地理定位,加速器,联系人,声音和振动等,此外PhoneGap拥有丰富的插件,可以调用。(参见PhoneGap的百度百科)
此外还可以去它的官方网站了解一下详细信息,当然这需要一定的英语功底,不过对于程序猿来说应该不会有阅读障碍的
测试环境下我使用的是Eclipse + Android SDK + JDK,也算是标准的Android开发环境,然后需要从官网下载资源文件,最新版2.9.1,由于最新版下载下来后看不到封装好的jar包,只有一个framework的源码,我想官方是建议开发者把这个framework作为类库引用的,不顾我还是喜欢使用jar包的方式,于是我就下载了2.8.1版本
下载完成后把android文件夹下的xml文件夹复制到我们自己的Android Project下的res目录下,然后在assets目录下新建www目录,把cordova.js文件复制进来,到此为止,基本工作算是已经完成
第一步,在www目录下新建一个myIndex.html文件,具体内容为
<html>
<head>
<meta charset="utf-8">
<title>
test phonegap
title>
<script type="text/javascript" charset="utf-8" src="cordova.js">script>
head>
this is html to test phonegap
html>
可以看到在这个html文件中我们引用了cordova.js文件
第二步,新建一个类,继承自DroidGap,这个是PhoneGap封装好的一个类
package com.xmliu.imsample.ui;
import org.apache.cordova.DroidGap;
import android.os.Bundle;
public class TestPhonegap extends DroidGap{
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/myIndex.html");
}
}
第三步,效果图,其实没什么效果,就是一个单纯的页面,毕竟html代码很少,无法测试更多的功能
第四步,http://m.blog.csdn.net/,为了测试更多的功能,我们另存下这个网址的全部源文件,改掉中文名后放到www目录下,并且修改它的主页文件名为csdn.html,在head区添加引用cordova.js,同时查找替换掉原有的文件目录中文名,最后工程结构如图所示
然后改一下loadurl指向的html文件
super.loadUrl("file:///android_asset/www/csdn.html");
为了对比出PhoneGap和Android自带的webview控件有什么区别,我们把上面的代码简单调整下,如下:
package com.xmliu.imsample.ui;
import android.os.Bundle;
import android.webkit.WebView;
import com.xmliu.imsample.BaseActivity;
import com.xmliu.imsample.R;
public class TestPhonegap extends BaseActivity{
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// super.loadUrl("file:///android_asset/www/csdn.html");
setContentView(R.layout.a_test_webview);
WebView wb = (WebView) findViewById(R.id.webview);
wb.loadUrl("file:///android_asset/www/csdn.html");
}
}
从上面两张gif图对比可以看出PhoneGap和Webview明显的区别,其实PhoneGap要去对比的并不是webview,而是native app,即本地化app,比如用android sdk开发的android app,用Objective-c开发的ios app,用c#开发的wp app等,相对于这些平台而言,它们能做的PhoneGap大部分都能做到,包括一些硬件的调用等。
虽然现在市面上用的不多(估计是由于它还不完善,不成熟,硬件支持跟不上等),但可以看出这样一种跨平台开发的开源编程框架无疑是未来的发展方向,真正做到WORA(write once run anywhere)。