小程序基础库与Android之间通信优化的可能

news/2024/7/20 2:43:06 标签: 小程序, android

最近在学习graalvm,发现有一个graaljs项目,项目中介绍可以让java与JavaScript做数据转换,比如JavaScript中可以使用java的数据类型与结构。突然想到之前遇到的一个问题,小程序中开发的代码和基础库的部分代码都是j2v8来执行的,其中的数据通信是通过bridge去做的,其实就是把数据结构都转换为字符串,这样就存在问题,比如Android这边的网络请求、音视频帧数据、文件流对外都是通过java封装的对象,无法直接在JavaScript中使用,只能是通过转换为base64来做,而且一个buffer数据基本需要两次转换,sdk转一次,基础库转一次,比较消耗性能。

如果JavaScript和java之间的结构互通,那是不是就解决这个问题了,理论上来说如果js引擎是通过java编写的解释器去执行,那确实是可以这样的。

GraalJs

GraalJs核心代码如下:

BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader("/Users/xxx/tmp/index.md"));
} catch (FileNotFoundException e) {
    throw new RuntimeException(e);
}
try (Context context = Context.newBuilder().allowAllAccess(true).build()) {
    Set<String> languages = context.getEngine().getLanguages().keySet();
    for (String id : languages) {
        context.initialize(id);
        if (id.equals("js")) {
            context.eval("js", "function main(data) { console.log(data.readLine()); }");
            Value funMain = context.getBindings("js").getMember("main");
            funMain.execute(br);
        }
    }
}

这里我们使用GraalVM的jdk是可以运行的,可以看到JavaScript中接收到的data其实是java的BufferedReader,执行之后就发现JavaScript中的data.readLine成功执行并打印了文件内容,WC,如果Android可以这样那就太强了。可惜,GraalJs必须使用GraalVM提供的jdk,也不好直接替换android中使用的jdk。。。
那有没有其他办法?对了,GraalVM是可以将java代码生成分享库的,比如.so,Android也正好可以加载so库。有没有可能这样搞。最终项目如下https://github.com/schizobulia/GraalJs-Android ,可以看到releases中tag为v0.0.8中有arrch64和armv7的so库
截屏2024-01-11 10.02.00.png
可惜拿到so库之后去Android中使用发现,这个so库不是ABI。麻了…
然后查了相关资料发现GraalVM目前也没有计划支持Android。

不过好在最后发现ChatGPT确实是个好东西,现在查资料基本都是先问问ChatGPT,上面项目中的GitHub Action配置文件也是ChatGPT写的。

参考资料:
Android 关于CPU类型的so文件兼容问题(ABI) - 掘金
一分钟搞明白Android的.so文件、ABI和CPU的关系-CSDN博客

J2V8

那有没有可能从j2v8入手,比如node很多内置函数其实在v8中也是没有的,如果可以在v8中实现这些函数然后提供给JavaScript调用好像有可以,然后开始查node这部分功能的实现原理,最后看到一篇博客:Node.js的底层原理 - 掘金其中说到这个部分的实现是V8的自定义拓展实现的,好像确实可以。不过后来试了试,发现还是不行。

主要原因有:比如文件流、帧数据在Android端对外都是通过java封装的对象,v8的自定义扩展需要c++或者v8提供的语言来编写,依然存在语言之间数据结构转换的问题。

次要原因:实在不想看c++的代码

Rhino

然后通过ChatGPT最终选择试试Rhino,因为他也是java写的,缺点是性能可能没没v8那么强,JavaScript中新的语法糖或者全局属性可能没那么快支持到(不过可以使用一些打包库和第三方静态分析库去优化)。
小程序中存在大量的数据交互,如果使用Rhino说不定会有更好的效果,以下为示例代码,可以看到JavaScript中可以使用java的数据结构,这得益于解释器是使用java写的,节省了不同语言之间数据结构的转换。

var System = java.lang.System;
System.out.println(myClass.add(1, 2));
function test(str) {
    myClass.show(str);
}

通过下面代码的测试,发现读取一个53kb的文件从调用test方法到show方法的触发基本没消耗时间。而且根据这种方式其实也很节省内存,因为数据其实只保存在了jvm中,按j2v8的思路同一份数据需要在v8、jvm中各保存一份。
以下为完整代码:

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.myapplication.ui.theme.MyApplicationTheme
import org.mozilla.javascript.Context
import org.mozilla.javascript.Function
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject
import java.nio.ByteBuffer
import java.nio.CharBuffer
import java.nio.charset.Charset


class MainActivity : ComponentActivity() {
    class MyFunctions {
        fun add(a: Int, b: Int): Int {
            return a + b
        }

        fun show(buffer: ByteArray) {
            println("这是js传递过来的:")
            println(System.currentTimeMillis())
            println(buffer)
//            val text = String(buffer)
//            println("File Content: $text")
        }
    }
    class JsEngine {
        public val rhino: Context = Context.enter()
        public val scope: Scriptable

        init {
            rhino.optimizationLevel = -1
            scope = rhino.initStandardObjects()

        }

        fun evaluate(jsCode: String) {
            try {
                ScriptableObject.putProperty(scope,"myClass", Context.javaToJS(MyFunctions(), scope))
                ScriptableObject.putProperty(scope, "javaContext", Context.javaToJS(this, scope))
                ScriptableObject.putProperty(scope, "javaLoader", Context.javaToJS(JsEngine::class.java.classLoader, scope))
                rhino.evaluateString(scope, jsCode, JsEngine::class.java.simpleName, 1, null)
            } finally {
//                Context.exit()
            }
        }

        fun callFunction(functionName: String, vararg args: Any): Any? {
            try {
                val function = scope[functionName, scope] as Function
                return function.call(rhino, scope, scope, args)
            } finally {
//                Context.exit()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    Greeting("Android")
                }
            }
        }

        val inputStream = resources.assets.open("data.txt");
        val size = inputStream.available()
        val buffer = ByteArray(size)
        inputStream.read(buffer)
        inputStream.close()
        Thread {
            val jsCode = """
            var System = java.lang.System;
            System.out.println(myClass.add(1, 2));
            function test(str) {
                myClass.show(str);
            }
                """.trimIndent()
            val jsEngine = JsEngine()
            jsEngine.evaluate(jsCode)
            println(System.currentTimeMillis())
            jsEngine.callFunction("test", buffer)
        }.start()
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
            text = "Hello $name!",
            modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MyApplicationTheme {
        Greeting("Android")
    }
}

最后:ChatGPT真👍🏻


http://www.niftyadmin.cn/n/5318878.html

相关文章

通义千问协助分析openHarmony内核编译故障记录

drivers/hdf/khdf/manager/../../../..//framework/utils/src/hdf_sbuf.c:271:6: 错误&#xff1a; ‘-mgeneral-regs-only’ is incompatible with floating-point argument 这个编译错误提示指出&#xff0c;在编译源文件 "hdf_sbuf.c"&#xff08;位于 "driv…

ASP.NET摄影展示网站源码

ASP.NET摄影展示网站源码 项目描述 网站利用了ext技术&#xff0c;用户自定义了展示控件 前台展示类别有&#xff1a; 协会动态&#xff0c;摄影理论&#xff0c;影展影赛&#xff0c;采风路线&#xff0c; 影友之窗&#xff0c;佳作欣赏&#xff0c;器材专区&#xff0c;展览信…

Pandas实战100例 | 案例 20: 日期时间运算

案例 20: 日期时间运算 知识点讲解 Pandas 提供了强大的日期和时间处理功能。你可以从 datetime 类型的列中提取出年份、月份、日、星期等信息,也可以进行日期时间的加减运算。 提取日期时间信息: 使用 dt 访问器,你可以从 datetime 类型的列中提取出年份 (year)、月份 (mo…

YOLOv8改进 | 二次创新篇 | 在Dyhead检测头的基础上替换DCNv3 (全网独家首发)

一、本文介绍 本文给大家带来的改进机制是在DynamicHead上替换DCNv3模块,其中DynamicHead的核心为DCNv2,但是今年新更新了DCNv3其作为v2的升级版效果肯定是更好的,所以我将其中的核心机制替换为DCNv3给Dyhead相当于做了一个升级,效果也比之前的普通版本要好,这个机制我认…

【投稿优惠|火热征稿】2024年测量控制与轨道交通国际学术会议(ICMCRT 2024)

【投稿优惠|火热征稿】2024年测量控制与轨道交通国际学术会议(ICMCRT 2024) 2024 International Conference Measurement Control and Rail Transit(ICMCRT 2024) 一、【会议简介】 业内专家认为&#xff0c;在当今以信息技术带动工业化发展的时代&#xff0c;测量控制与仪器仪…

20240112-【UNITY 学习】实现第一人称移动教程

1、创建一个空物体&#xff0c;挂载Rigidbody组件&#xff0c;并设置相应参数 2、在上述空物体下创建一个胶囊体&#xff0c;两个空物体&#xff0c;一个用来控制朝向&#xff0c;另一个用来控制摄像机 3、给摄像机创建一个父物体&#xff0c;并挂载脚本MoveCamera_01.cs using…

工具推荐:知识库软件那么多,到底哪些最好用?

在这个信息爆炸的时代&#xff0c;有效地管理和利用知识已经成为企业发展的关键一环。一个强大的知识库软件可以帮助企业储存、分类、检索和分享知识&#xff0c;提升工作效率&#xff0c;提高竞争力。以下&#xff0c;我们为你推荐三款高效、易用的知识库软件。 HeLpLook He…

SQL基础知识3

一、删除数据 1、delete操作 删除之前一定要查询一下&#xff0c;确保删除的数据是对的 逻辑删除&#xff1a;在表中新增一个字段&#xff1a;flag/status 二、更新数据 本质上的逻辑删除 三、查询数据 1、联表查询 1、内连接 交集的部分叫内连接 小知识&#xff1a;一般…