浅谈混合开发与android,js数据交互

沉睡的雄狮      2022-02-10     362

关键词:

本文是作者原创,如转载请注明出处!

一.概论

  现在时代已经走过了移动互联网的超级火爆阶段,市场上移动开发人员已经趋于饱和,显然,只会原生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 = new WebView(mContext);
//加载网络上的一个url
String url = "https://www.baidu.com";
mWebView.loadUrl(url);
//加载本地的一个url,asserts目录下的
mWebView.loadUrl("file:///android_asset/index.html");

WebView的一些重要设置

//先获取到WebSettings控制类
WebSettings settings = mWebView.getSettings();
//设置支持javascript
settings.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(new WebViewClient() {
            @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(new WebChromeClient(){
            //对应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中调用,比如要调用本地读取二进制文件的一个方法
@JavascriptInterface
    public String readshape(String mapshape) {
        Gson gson = new Gson();
        MapShape mapShape = gson.fromJson(mapshape, MapShape.class);
        String shapeBase64 = SEInterfacePvReader.getMapShape(mapShape);
        System.out.println(shapeBase64);
        return shapeBase64;
    }
//3.js调用并获取返回值,另外解释一下,js调用java的方法是在WebView的一个独立的后台线程中,另外这里js调用Android的方法时传递参数只能传一个,而且java与js交互的方法是不支持二进制流交互的,只支持简单的基本数据类型,比如int,boolean,String,数组也是不支持的,数组可以采用json字符串的形式
var bufferData = 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(int i) {
        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);
        return result;
    }
    /**
     * byte[] 转化为int[] ,低位在前的方式
     * @param title
     * @return
     */
    public static int[] byteArrayToIntArray(byte[] title) {
        int[] array = new int[title.length / 4];
        byte[] temp = new byte[4];
        int k = 0;
        for (int i = 0; i < title.length; i++) {
            temp[i % 4] = title[i];
            if (i > 0 && (i+1) % 4 == 0) {
                array[k] = byteArrayToInt2(temp);
                k++;
            }
        }
        return array;
    }
     /**
     * byte数组转化为int值的工具类,低位在前
     *
     * @param b
     * @return byte[]转化为的int数
     */
    public static int byteArrayToInt2(byte[] b) {
        int MASK = 0xFF;
        int result = 0;
        result = b[0] & MASK;
        result = result + ((b[1] & MASK) << 8);
        result = result + ((b[2] & MASK) << 16);
        result = result + ((b[3] & MASK) << 24);
        return result;
    }

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的学习之路.

奉上我很喜欢的一句话,与君共勉:比你聪明的人比你还要努力,你又有什么理由不努力呢?

如有不足之处请指正评论,谢谢!










js与app原生控件交互

...每次发布一个活动,都要发布一个现版本,当然这样对于Android还算可以,但是对于Ios呢?苹果应用商店每次审核的时间基本都在1~2周,这对于一个促销活动来说审核时间实在太长。而混合式开发正好可以解决这个问题,基本的... 查看详情

android与html+js交互入门

...ttp://blog.csdn.net/leejizhou/article/details/50894531李济洲的博客在Android开发中,越来越多的商业项目使用了Android原生控件与WebView进行混合开发,当然不仅仅就是显示一个WebView那么简单,有时候还需要本地Java代码与HTML中的javascript进行... 查看详情

oc与js混合开发

...bsp;随着iOS开发的成本增大,越来越多的公司开始使用html5混合开发软件了,因为使用原生的开发花费的成本跟时间都很大,而使用html5来搭建界面会方便很多,效率相对而言也提高了。虽然使用UIWebView实现的交互效果与原生效果... 查看详情

浅谈js中的mvc

MVC是什么?MVC是一种架构模式,它将应用抽象为3个部分:模型(数据)、视图、控制器(分发器)本文将用一个经典的例子todoList来展开一个事件发生的过程(通信单向流动):1、用户在视图V上与应用程序交互2、控制器C触发... 查看详情

androidwebview与js的数据交互

关于WebView我们知道目前android市场上的一些应用采用的开发方式大致分为三种:NativeApp、WebApp、HybridApp。本文主要是HybridApp中实现的主要技术native组件与js的数据交互的理解以及实现。 AndroidAPI中提供了WebView组件来实现对html... 查看详情

wkwebview与js交互之完美解决方案

??最近对团队中的混合开发框架进行了重构,下面就和大家来说说自己的思路以及解决方案。??随着H5功能愈发的强大,没进行过混合开发的小伙们都不好意思说自己能够独立进行iOS的app开发,在iOS7操作系统下,常用的native,js交... 查看详情

浅谈接口测试

...p; ios用到的语言为object-c、swfit     Android用到的语言为Android后端:是业务逻辑,功能的实现、数据的存储。语言有java、php、python、go等。前端和后端都是不同语言来开发的,但是他们需要交互,那怎么交互... 查看详情

androidwebview实现原生与js的交互(代码片段)

个人主页 Documents在现在的Android开发中,为了追求开发的效率以及移植的便利性,越来越多的开发者会在App中使用WebView作为部分业务内容展示与交互的主要载体。那么在这种Hybrid(混合式)App中,难免就会遇到页面JS需... 查看详情

android与h5数据交互(kotlin)(代码片段)

...项目换成了原生+h5混合开发所有的功能基本都由H5做了android这边只负责调用硬件设备拿到硬件返回的数据再返回H5交由他来加载显示主要方法有2个一是H5输入内容传给androidandroid接受到保存数据库这样做的好处是即使重新加载H... 查看详情

iosjs与原生交互(全集)

混合开发的重要性不言而喻,一个移动端开发的了解前端开发是一个趋向,总之每个人都向往成为一个全栈工程师,废话不多说,直接上主题一、交互(UIWebView)1、OC调用JS (1)OC调用代码  [self.webViewstringByEvaluatingJavaScriptFr... 查看详情

javascript:浅谈ios与h5的交互-javascriptcore框架

JavaScript:浅谈iOS与H5的交互-JavaScriptCore框架  前言小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCore框架主要是用来实... 查看详情

androidwebview实现原生与js的交互(代码片段)

个人主页 Documents在现在的Android开发中,为了追求开发的效率以及移植的便利性,越来越多的开发者会在App中使用WebView作为部分业务内容展示与交互的主要载体。那么在这种Hybrid(混合式)App中,难免就会遇到页面JS需... 查看详情

apsarastack技术百科|浅谈阿里云混合云新一代运维平台演进与实践

随着企业业务规模扩大和复杂化及云计算、大数据等技术的不断发展,大量传统企业希望用上云来加速其数字化转型,以获得虚拟化、软件化、服务化、平台化的红利。在这个过程中,因为软件资产规模持续增大而导... 查看详情

flutter与原生混合开发(代码片段)

  在说flutter与原生的混合开发之前,先和初学flutter的小伙伴提个建议,建议大家刚开始的时候先在纯flutter的项目上练习flutter的相关技术,等练习的差不多了,再练习flutter与原生的交互。主要原因是:与原... 查看详情

web前端培训课程都学习啥内容?

...ue.js开发WebApp项目、应用React.js开发WebApp项目5.第五阶段:混合(Hybrid,ReactNative)开发内容包含:微信小程序开发、ReactNative、各类混合应用开发6.第六阶段:NodeJS全栈开发内容包括:WebApp后端系统开发、NodeJS基础与NodeJS核心模块... 查看详情

androidwebview与js的交互方式最全面汇总

...商平台,淘宝、京东、聚划算等等,如下图上述功能是由Android的WebView实现的,其中涉及到Android客户端与Web网页交互的实现今天我将全面介绍Android通过WebView与JS交互的全面方式阅读本文前请先阅读:Android开发:最全面、最易懂... 查看详情

浅谈前后端分离与不分离

前后端的分离与不分离  随着不同终端的兴起,对开发人员的要求越来越高,纯浏览器端的响应式已经不能满足用户体验的高要求,我们往往需要针对不同的终端开发定制的版本,为了提升开发效率,前后端分离的需求越来越... 查看详情

浅谈ajax

ajax介绍      ajax即“AsynchronousJavascriptAndXML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术,它并不是一门新的语言。       通过在后台与服务器进行少量数... 查看详情