WebView加载本地html、js,以及两者通信

有这么一个需求:提高二维码的扫描速度(二维码自产自销)。方向有很多,比如从设备解码能力方面考虑(这是废话貌似);从二维码的复杂度方面考虑,即在数据量确定的情况下,如何有效地降低二维码复杂度,以提高设备扫码速度;从所使用的SDK方面考虑,zxing、zbar、qrcod,其实现方式不同,比如zxing是c++写的,zbar是c写的,而且,还可以考虑到它们扫描算法的不同。

在android上,似乎google的zxing用的比较多,所以我选用了zxing。对于这个需求,我是从降低二维码复杂度的方面考虑的,也就是说,降低或者直接去除二维码的容错率。由于我这边的需求,二维码的生成扫描都是在设备上进行的,不存在二位码损坏的情况。zxing的查了下,其容错率,似乎只能设置到最低级别L,并不能完全去除,要不就去改源码。我使用的studio,gradle依赖的方式,改源码似乎不太理想。

最后,剑走偏锋,决定使用网页端的Jquery二维码插件,因为我发现,这个工具可以设置correctLevel为0。这个方式,就需要使用WebView,去加载本地html及js,然后两者通信了。好的,废话不多说,下面开始。

一、WebView加载本地html、js

步骤如下:
1.建立assets文件夹,并放入html,js文件。
WebView加载本地html、js,以及两者通信_第1张图片

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;
    }

二、Activity与html通信

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()了。

你可能感兴趣的:(Android)