跨语言通信——luascriptcore

40 篇文章 0 订阅
36 篇文章 1 订阅

luascriptcore

luascriptcore是一个用来绑定lua、java、oc的跨语言通信开源框架。被引入到了公司的项目中。

方法定义和绑定

lua call java

注册

使用的是带方法名的回调,即LuaContext#registerMethod(String, Callable)

  1. LuaContext持有了Java侧的Callable
  2. 通过LuaNativeUtil向LuaContext.cpp注册了该方法名和LuaJavaEnv#luaMethodHandler
  3. 通过LuaSession(类似于ThreadLocal)获取到lua_state(原生lua)
  4. 依次把当前LuaContext、方法名、方法回调LuaContext#methodRouteHandler压栈
  5. 把栈顶元素(方法回调)设置为名为methodName的global对象并出栈

这里没有用lua_pushcfunction。

调用(LuaContext#methodRouteHandler
  1. 在虚拟栈中向上找到LuaContext和方法名
  2. LuaContext#getMethodHandler 找到注册进来的LuaJavaEnv#luaMethodHandler
  3. 反解Lua数据至C++对象(详见参数序列化方式部分)
  4. 调用LuaJavaEnv#luaMethodHandler
    a. JNI反射查找到LuaContext.java#methodInvoke
    b. 将3中反解的数据再封装成Java对象
    c. 调用java方法,并获得返回值
  5. 释放对lua对象的引用

java call lua

注册

因为lua是纯动态化语言,不需要注册

调用
  1. LuaContext.java#callMethod(String, LuaValue[]);
  2. LuaNativeUtil#callMethod->LuaContext::callMethod
  3. lua_getglobal找到对应的lua方法
  4. lua_pcall调用方法,并用context绑定的异常处理函数处理异常
  5. 处理栈顶的返回值(可能是多个或者一个)
  6. 序列化数据,并返回给java

类型约束及传输

分为primitive、collection和自定义三种。Primitive包括了Nil、Number、Boolean、String、Integer、Data(bytes)。Collection包括了Array、Map<String, Any>、Tuple。自定义包括了Object、Function和ptr。

JavaToLua

只有两大步

  1. 利用jni构建与LuaValue.java对应的LuaValue.cpp,LuaJavaConverter#convertToLuaValueByJLuaValue
  2. 直接把值push到lua stack中,LuaDataExchanger::pushStack
Primitive
  • step1,jni调LuaValue#toXValue接口,传值获得具体的值
  • step2,直接调lua_pushx接口,把具体值push。Data是当做string push进去的
Collection
  • step1,把每个子元素读出来,按未知类型进行转换后填入到C++对应集合中
  • step2,tuple比较特殊,直接挨个push进栈。另两个都被当做table来push。push的过程:
    • 保证有全局的_G table(全局)和_G[‘vars’] table(变量),并将_G[‘vars’]置于栈顶
    • 如果没有该对象(_G[‘vars’][table_id] == null)则新建一个包含所有元素的table,并置于栈顶
自定义
Object
  • step1,能传递的Object必须是通过LuaJavaEnv#associcateInstance的对象,即以id->jobject形式存到了_instanceMap中。这里只是取出来二者,整合到一起
  • step2,看有没有通过LuaExportsTypeManager注册过对应的类。
    • 注册的,直接利用LuaExportsTypeManager使用反射+annotation的方式把序列化变成了metadata[’__index’]处理函数。利用LuaExportsTypeManager#globalIndexMetaMethodHandler来做数据读写
    • 创建userData,并绑定到this
    • 创建metadata,并metadata[’__gc’] = release方法,release方法内将this释放掉。
Function
  • step1,只支持lua方法
  • step2,function本来就是全局的变量,所以只是把对应的对象拿出来
Ptr
  • step1,只支持lua对象,保存成了light-userdata
  • step2,把light-userdata拿出来,push到栈顶

LuaToJava

三步:LuaDataExchanger#getValue把每个参数转成LuaValue。LuaJavaConverter#convertToJavaObjectByLuaValue把LuaValue.cpp转成JObject。LuaJavaConverter#convertToJavaLuaValueByLuaValue把JObject转成LuaValue.java。

Primitive
  • step1,lua提供了各种toX的接口
  • step2,搞成Box的对象
  • step3,传值给jni,直接构造对应的LuaValue.java
Collection
  • step1,都是按table读。key是Integer、从0开始、顺序递增就转成Array,其他转成Map
  • step2,构建Java的List/Map,再反解每个元素,add或者put
  • step3,传值给jni,直接构造对应的LuaValue.java
自定义
Object
  • step1,获取userdata
  • step2,只支持从java过去的对象,直接从userdata里拿到java对象
  • step3,传值给jni,直接构造对应的LuaValue.java
Function
  • step1,获取function,构建一个LuaFunction。通过让Global持有指针保证不释放,并利用引用计数来做释放(LuaDataExchanger#retainLuaObject)
  • step2,把LuaFunction放到LuaObjectManager中
  • step3,传值给jni,直接构造对应的LuaValue.java
Ptr
  • step1,获取light-userdata,构建LuaPointer
  • step2,构建LuaPointer
  • step3,传值给jni,直接构造对应的LuaValue.java

其他细节

JNI对象的gc管理

java对象直接通过jni在native侧创建,并

  • 将native侧的counterpart保存在LuaObjectManager中
  • 将jni对象以GlobalWeakRef形式保存在LuaJavaEnv中,方便后续调用时快速查找
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值