一. 概论
- 现在时代已经走过了移动互联网的超级火爆阶段,
- 市场上移动开发人员已经趋于饱和,
- 显然,
- 只会原生APP的开发已不能满足市场的需求,
- 随着H5的兴起与火爆,
- H5在原生APP中的使用越来越广泛,
- 也就是我们常说的混合开发 (Hybrid APP).最新很火的微信小程序相信大家都是知道的,
- 实际上微信小程序加载的界面就是一个html5的界面,
- HTML5界面在一些电商类的APP中主要承担展示数据的作用,
- 但是他的作用并不仅限于此,
- 最起码js调用原生方法和原生调用js的方法是必须的,
- 我们看到的现在微信小程序中的膜拜单车入口,
- 进入后的扫码功能,
- 就是js调用安卓原生的摄像头进行扫码的,
- 另外分享功能以及点击js中的一个按钮跳转到APP原生界面这些需求都是很常见的,
- 所以js和原生方法的相互调用是必须会的.最近做HTML5相关的地图APP,
- 正好用到了相关的知识,
- 总结下项目中遇到的坑.
二. JS 与 Android 交互
1.Android 如何加载一个 H5 界面到 APP? 目前比较成熟的方案是采用 Android 封装好的中间件 webView.
加载方式
- //创建一个WebView,也可以直接在布局中写WebView控件WebView mWebView =newWebView(mContext);//加载网络上的一个url
- Stringurl ="https://www.baidu.com";
- mWebView.loadUrl(url);//加载本地的一个url,asserts目录下的mWebView.loadUrl("file:///android_asset/index.html");
WebView 的一些重要设置
- //先获取到WebSettings控制类WebSettings settings = mWebView.getSettings();//设置支持javascriptsettings.setJavaScriptEnabled(true);//设置为false表示将图片调整为适合WebView的大小settings.setUseWideViewPort(false);//设置可以访问文件settings.setAllowFileAccess(true);
- settings.setAllowContentAccess(true);
- settings.setAllowFileAccessFromFileURLs(true);//设置js支持数据库settings.setDatabaseEnabled(true);//设置js支持window.localStorage,如果不设置,js中获取的window和localStorage都是null,之前我就被坑了,项目中js界面用到了window.localStorage,然后我和js采用alert的方式调试的过程中,发现这个方法一直报错才找到的这个api.settings.setDomStorageEnabled(true);
- mWebView.loadUrl("file:///android_asset/index.html");//添加了一个java和js交互的接口,android字符串相当于一个Brige桥梁的作用,安卓4.2以后增加了@JavascriptInterface接口,只有代码@JavascriptInterface注解的方法js才能调用,之前是被注入的类和从父类继承的所有的public的方法都能访问,这也是进一步保证APP的安全性.mWebView.addJavascriptInterface(mSnMap,"android");//设置WebView是否加载完成的监听mWebView.setWebViewClient(newWebViewClient() {@Override
- //WebView加载完成会调用的方法
- public void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);
- }@Override
- //WebView开始加载调用的方法
- public void onPageStarted(WebView view, String url, Bitmap favicon) {super.onPageStarted(view, url, favicon);@Override
- //WebView的界面可见时调用的方法
- public void onPageCommitVisible(WebView view, String url) {super.onPageCommitVisible(view, url);
- }@Override
- //是否要拦截js和java调用的方法
- public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {return true;
- }
- });//该设置保证加载界面时会自动调用系统的浏览器,而不是提示给用户让用户去选择哪个浏览器mWebView.setWebChromeClient(newWebChromeClient(){//对应js中的alert()方法,可以重写该方法完成与js的交互
- @Override
- public boolean onJsAlert(WebView view, String url, String message, JsResult result) {return super.onJsAlert(view, url, message, result);
- }//对应js中promt(),可以重写该方法完成与js的交互
- @Override
- public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {return super.onJsPrompt(view, url, message, defaultValue, result);
- }//对应js中的console.log方法,可以重写该方法完成与js的交互
- @Override
- public boolean onConsoleMessage(ConsoleMessage consoleMessage) {return super.onConsoleMessage(consoleMessage);
- }
- });
java 调用 js 的方法
- //比如我要调用addline(jsonline)方法,这里给出我写的一个示例
- //WebView规定java和js交互的时候前面的字段是javascript:+方法名
- //注意:传变量的时候注意要给字符串加上两个单引号,传递方式就是我下面写的那种规范
- public void addLine(Line line) {if(line !=null) {
- jsonLine = mGson.toJson(line);
- mWebView.loadUrl("javascript:addLine('"+ jsonLine +"')");
- }
- }
js 调用 java 的方法
- //这里介绍一种最简单的方式,当然也可以自己使用伪协议去封装
- //1.添加一个交互的接口,mSnMap表示要注入的java类,android是桥接字符串,js调用的使用就使用这个字符串进行交互mWebView.addJavascriptInterface(mSnMap,"android");//2.在js中调用,比如要调用本地读取二进制文件的一个方法@JavascriptInterfacepublicStringreadshape(String mapshape) {
- Gson gson =newGson();
- MapShape mapShape = gson.fromJson(mapshape, MapShape.class);
- String shapeBase64 = SEInterfacePvReader.getMapShape(mapShape);
- System.out.println(shapeBase64);returnshapeBase64;
- }//3.js调用并获取返回值,另外解释一下,js调用java的方法是在WebView的一个独立的后台线程中,另外这里js调用Android的方法时传递参数只能传一个,而且java与js交互的方法是不支持二进制流交互的,只支持简单的基本数据类型,比如int,boolean,String,数组也是不支持的,数组可以采用json字符串的形式
- varbufferData = android.readshape(json);
三. 数据结构, 文件读取
- 文件读取这块内容,
- 因为矢量数据的存储结构不是我们公司的人设计的,
- 是和我们公司合作的人设计的,
- 他们的服务器代码采用的是C++结合lua脚本语言共同编写的,
- 涉及到数据结构的具体详情不变透漏,
- 主要说下C++和java数据结构的差别以及读取数据时选择的API.
1.C++ 中的 char 和 java 中的 char C++ 中的 char 与 IOS object-c 中的 char 一样, 都是占一个 byte java 中的 char 占 2 个 byte 所以在数据读取过程中 c++ 经常创建一个 vector buf 就等价于 java 中读取文件时创建的 byte 数组. 这里用到了 java 中 int 转 byte 数组的工具类.
- //具体使用高位到低位还是低位到高位根据具体数据结构而定
- public static byte[]intToByteArray(inti) {byte[] result =new byte[4];//由高位到低位
- // result[0] = (byte)((i >> 24) & 0xFF);
- // result[1] = (byte)((i >> 16) & 0xFF);
- // result[2] = (byte)((i >> 8) & 0xFF);
- // result[3] = (byte)(i & 0xFF);
- //低位在前
- //由低位到高位result[0] = (byte) (i &0xFF);
- result[1] = (byte) ((i >>8) &0xFF);
- result[2] = (byte) ((i >>16) &0xFF);
- result[3] = (byte) ((i >>24) &0xFF);returnresult;
- }/**
- * byte[] 转化为int[] ,低位在前的方式
- * @paramtitle
- * @return*/
- public static int[]byteArrayToIntArray(byte[] title) {int[] array =new int[title.length /4];byte[] temp =new byte[4];intk =0;for(inti =0; i < title.length; i++) {
- temp[i %4] = title[i];if(i >0&& (i+1) %4==0) {
- array[k] = byteArrayToInt2(temp);
- k++;
- }
- }returnarray;
- }/**
- * byte数组转化为int值的工具类,低位在前
- *
- * @paramb
- * @returnbyte[]转化为的int数
- */
- public static int byteArrayToInt2(byte[] b) {intMASK =0xFF;intresult =0;
- result = b[0] & MASK;
- result = result + ((b[1] & MASK) <<8);
- result = result + ((b[2] & MASK) <<16);
- result = result + ((b[3] & MASK) <<24);returnresult;
- }
2. 文件的读取可以选择 RandomAccessFile 类和 FileInputStream 类 两个类都能实现读取二进制文件的效果, 同时两个类中都有定位到文件的某个位置的方法, 但是他们是有区别的. FileInputStream 的 skip() 方法是相对于当前位置定位的 RandomAccessFile 的 seek() 方法则可以定位到文件的任意位置 下面用代码举个例子
- fis.skip(10);
- fis.skip(5);
- //执行完这两行代码后读取的输入流FileInputStream定位到文件的第15个字节处
- raf.seek(10);
- raf.seek(5);
- //这两行代码的最终结果是RandomAccessFile最终定位到文件的第5个字节处.
- //另外需要注意的是:RandomAccessFile是继承于Object的,只是他实现了DataOutput, DataInput,所以可以读文件也可以写文件.而FileInputStream是继承于InputStream的,只能读文件,而我在项目中读文件采用的是InputStream读,ByteArrayOutputStream作为输出流存储数据.
java 和 js 如何交互文件 java 和 js 是不支持直接的二进制流的交互, 所以我们就换了一种方式进行交互, 将二进制数据读取后使用 Base64 算法转化为字符串, 将字符串传递给 js,js 再使用 Base64 算法反编码为二进制数据流. 当然除了这种方式外, 还有其他的思路, 比如移动端开发一个本地的服务器给 js 发请求, 完成数据的交互.
四. 项目总结
- 目前来说,
- 原生与H5的混合开发相对比较成熟,
- 但是现在没有任何一个工具能够在js与java之前完成debug调试,
- 所以项目上遇到问题只能采用日志和alert弹框的方式一步一步排查代码中的错误,
- 调试起来复杂又繁琐,
- 而且java和js在数据交互上依赖浏览器内核,
- 性能上也存在问题,
- 希望不久的将来,
- 技术上能够突破这些瓶颈.地图的开发还是使用原生调用c++的OpenGL绘制矢量地图比较靠谱,
- 之前研究过1个月的OpenGL开发,
- 因为太难以及项目进度比较赶的原因没有继续下去,
- 接下来会抽出更多的时间去完成OpenGL的底层绘制地图,
- 后续的博客也会分享OpenGL的学习之路.
奉上我很喜欢的一句话, 与君共勉: 比你聪明的人比你还要努力, 你又有什么理由不努力呢
如有不足之处请指正评论, 谢谢!
来源: http://blog.csdn.net/liuxu841911548/article/details/71216439