有这么一个需求:提高二维码的扫描速度(二维码自产自销)。方向有很多,比如从设备解码能力方面考虑(这是废话貌似);从二维码的复杂度方面考虑,即在数据量确定的情况下,如何有效地降低二维码复杂度,以提高设备扫码速度;从所使用的SDK方面考虑,zxing、zbar、qrcod,其实现方式不同,比如zxing是c++写的,zbar是c写的,而且,还可以考虑到它们扫描算法的不同。
在android上,似乎google的zxing用的比较多,所以我选用了zxing。对于这个需求,我是从降低二维码复杂度的方面考虑的,也就是说,降低或者直接去除二维码的容错率。由于我这边的需求,二维码的生成扫描都是在设备上进行的,不存在二位码损坏的情况。zxing的查了下,其容错率,似乎只能设置到最低级别L,并不能完全去除,要不就去改源码。我使用的studio,gradle依赖的方式,改源码似乎不太理想。
最后,剑走偏锋,决定使用网页端的Jquery二维码插件,因为我发现,这个工具可以设置correctLevel为0。这个方式,就需要使用WebView,去加载本地html及js,然后两者通信了。好的,废话不多说,下面开始。
步骤如下:
1.建立assets文件夹,并放入html,js文件。
2.webview所在activity中:
webView.loadUrl("file:///android_asset/code.html");
// WebView允许js执行
webView.getSettings().setJavaScriptEnabled(true);
3.code.html中如何引用js,代码不多,整个贴出来好了,也可以顺便看下js是如何创建二维码的:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table align="center" style="margin-top:20px">
<tr>
<td>
<div id="qrcode"></div>
</td>
</tr>
</table>
</body>
<script type="text/javascript" src="file:///android_asset/js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="file:///android_asset/js/jquery.qrcode.min.js"></script>
<script>
jQuery(function(){
// 数据是调用activity中的方法获取到的,注意这里的 Native,下文中用到
var data = window.Native.getData();
jQuery("#qrcode").qrcode({
width:300,
height:300,
text:data,
correctLevel:0
});
})
</script>
</html>
备注:
我用的是android7.0的扫码设备,以上代码可以良好运行。但是网上有说,低版本js会不执行的,搜了下解决办法,加载网页可更改如下:
String local = "file:///android_asset";
String data = getFromAssets("code.html");
webView.loadDataWithBaseURL(local, data, "text/html", "utf-8", null);
public String getFromAssets(String fileName) {
String result = "";
try {
InputStream in = getResources().getAssets().open(fileName);
// 获取文件的字节数
int lenght = in.available();
// 创建byte数组
byte[] buffer = new byte[lenght];
// 将文件中的数据读到byte数组中
in.read(buffer);
// 注意gradle中加入依赖 compile 'org.apache.httpcomponents:httpcore:4.4.4'
result = EncodingUtils.getString(buffer, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
webview的方法addJavascriptInterface,可以向html注入一个java对象,这样,在js中就可以调用java方法了,具体使用如下:
1.首先需要一个java对象,
public class JSCallManager {
private String data;
public JSCallManager(String data) {
this.data = data;
}
@JavascriptInterface
public String getData() {
return data;
}
}
这里说明一下,@JavascriptInterface注解,在Android <=4.1.2 (API 16),WebView使用WebKit浏览器引擎,并未正确限制addJavascriptInterface的使用方法,在应用权限范围内,攻击者可以通过Java反射机制实现任意命令执行。在Android >=4.2 (API 17),WebView使用Chromium浏览器引擎,并且限制了Javascript对Java对象方法的调用权限,只有声明了@JavascriptInterace注解的方法才能被Web页面调用。(引用自https://www.jianshu.com/p/6309d243e4c0)。
2.webview中如何使用
webView.addJavascriptInterface(new JSCallManager(jsonData), "Native");
webView.setWebChromeClient(new WebChromeClient());
3.在js中方法如何调用
var data = window.Native.getData();
知道了如何使用了,那我这边就可以直接将json数据传给html,然后jquery插件根据json创建二维码了.这部分代码就不贴了,都一样。
注意:
这里的Native,需要与上一步骤中的addJavascriptInterface方法中传入的第二个参数相匹配。
android4.2下,有一个安全漏洞,解决方法,可以看此链接https://blog.csdn.net/zhouyongyang621/article/details/47000041
另,如何在java中调用js代码,步骤如下:
1.在js中
//在android代码中调用此方法
function showInfoFromJava(msg){
alert("来自客户端的信息:"+msg);
}
2.在activity中
//在java中调用js代码
public void sendInfoToJs() {
String msg = "999";
//调用js中的函数:showInfoFromJava(msg)
webView.loadUrl("javascript:showInfoFromJava('" + msg + "')");
}
以上,参考自:https://blog.csdn.net/maiwc/article/details/54915134
OK,到这里就完事儿了。现在来捋一下:
1.webview加载本地html、js。几个关键点,先是文件的位置,然后是html中怎样加载javascript,最后是webview如何加载html(加载html这里感觉会有坑,虽然我没遇到,小伙伴们注意了~)。
2.activity与html的相互通信。2个方面,一是如何向html中注入java对象,js中怎样调用该对象昂的方法;二是activity中如何调用js。
两者如何通信掌握了,有些东西就很好办了。比如现在要实现一个功能,点击网页中的一个返回按钮,如何关闭当前activity?很好办,注入java对象时,顺便把context传进来,这样js调用该对象方法,在方法中就可以直接context.finish()了。