开源软件名称(OpenSource Name):ichenhe/Android-Lua开源软件地址(OpenSource Url):https://github.com/ichenhe/Android-Lua开源编程语言(OpenSource Language):C 89.2%开源软件介绍(OpenSource Introduction):Android-LuaBased on Androlua for Lua5.3.3, make some practical changes. blog: https://www.jianshu.com/p/908a1ac893bb 依赖 Dependency
Because JCenter is read only now, this lib has published to maven central. But the coordinate changed to 混淆 ProGuard如果你使用R8(Gradle 3.4.0 默认使用)则无需添加任何规则。否则请添加下述内容: If you use R8 which is default in Gradle 3.4.0 nothing need to do. Else add the rules below:
DEMODemo 工程位于源码的 使用 Usage初始化Lua 与 C 依靠一个虚拟的栈来完成数据交换。包括变量、函数、参数、返回值等在内的一切数据,都要放入栈中来共享。为了调用方便,这个栈并不是严格遵循栈的规则。从索引来看,栈底索引为1,往上依次递增。而栈顶索引是-1,往下依次递减。因此,正负索引都是合法的,但是0不可以。下面是栈的示意图: 所以要在 java 中使用 Lua,首先我们需要创建一个 Lua 运行环境,也就是 Lua 栈: LuaState lua = LuaStateFactory.newLuaState(); //创建栈
lua.openLibs(); //加载标准库
lua.close(); //养成良好习惯,在执行完毕后销毁Lua栈。 这样我们就创建了一个 Lua 运行时。每一个
加载 Lua 脚本使用 同时也提供了
获取 Lua 变量首页要说明的是,只有全局变量(非 local)才可以读取。 lua: v1 = "this is value from lua" java: lua.getGlobal("v1"); // 请求 v1 变量的值,入栈
String s = lua.toString(-1) // 从栈中取得了值
lua.pop(1); // 及时将不用的数据出栈避免栈溢出
// 此时 s = "this is value from lua" 记住, 注入 Lua 变量有时我们需要在 android 中创建 Lua 变量,这样就可以在 Lua 中直接使用了。注意,这里创建的变量都是全局的(非 local)。 java: lua.pushString( "from java" ); //压入欲注入变量的值
lua.setGlobal("v2"); // 设置变量名
// 现在可以在 lua 脚本中使用 `v2` 变量了。 首先通过
遍历 Lua 表(数组)Lua 的表相对来说是特别灵活的,既可以作为数组,也可以作为键值数组。而且同一个 table 里,key 与 value 的数据类型都可以不同。但无论如何,在 java 中的遍历方式都是一样的。 lua: -- 以键值数组为例
table = {}
table["name"] = "Lily"
table["age"] = 18
table["sex"] = "female" java: lua.getGlobal( "table" );
StringBuilder s = new StringBuilder();
if ( lua.isTable( -1 ) )
{
lua.pushNil(); // 压入一个空值作为初始 key 启动遍历
while ( lua.next( -2 ) != 0 )
{
s.append( lua.toString( -2 ) ).append( " = " )
.append( lua.toString( -1 ) ).append( "\n" );
lua.pop( 1 );
}
lua.pop( 1 ); // 弹出 table 本身
}
// 最后 StringBuilder 里的内容是:name = Lily\nage=18\nsex=female
// 顺序可能错乱,因为 k-v 不一定是有序的。 类似之前,首先找到了
取出所需数据后我们将 注入 Lua 表类似注入普通变量。 java: lua.newTable(); // 新建一个table,并压入栈。
lua.pushString( "from" );
lua.pushString( "java" );
lua.setTable( -3 ); // 设置一个元素
lua.pushString( "value" );
lua.pushString( "Hello lua" );
lua.setTable( -3 );
lua.setGlobal( "table" ); 首先需要创建一个 table。接着将 key、value 依次入栈,随后调用 上面代码运行后,等价于下面的 Lua table 定义: table = {}
table["from"] = "java"
table["value"] = "Hello lua" Java 调用 Lua 函数你可以将 Lua 函数理解为一个特殊的变量。因此要调用 Lua 函数,首先要像获取 Lua 变量那样获取它。 lua: -- 这是一个获取最大值与最小值的函数
-- Lua 允许多个返回值,其实这是一个语法糖,内部使用的是 table 包装
function extreme(a, b, c)
local max = a
local min = a
if(b>max) then
max = b
elseif(b<min) then
min = b
end
if(c>max) then
max = c
elseif(c<min) then
min = c
end
return max, min
end java: StringBuilder s = new StringBuilder();
lua.getGlobal("extreme"); // 获取到函数入栈
lua.pushNumber(15.6); // 依次压入三个参数
lua.pushNumber(0.8);
lua.pushNumber(189);
lua.pcall(3, 2, 0); // 调用函数
s.append("max:").append(lua.toString(-2)).append(" min:").append(lua.toString(-1));
// 最后 StringBuilder 里的内容是:max:189 min:0.8
类似
Lua 调用 Java 函数Lua 调用 java 函数相对复杂,毕竟 java 不是脚本语言。我们需要将 java 函数包装成一个 public class MyJavaFunction extends JavaFunction {
public MyJavaFunction(LuaState luaState) {
super(luaState);
}
@Override
public int execute() {
// 获取Lua传入的参数,注意第一个参数固定为上下文环境。
String str = L.toString(2);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(System.currentTimeMillis());
L.pushString(simpleDateFormat.format(date) + str);
return 1; // 返回值的个数
}
public void register() {
try {
// 注册为 Lua 全局函数
register("getTime");
} catch (LuaException e) {
e.printStackTrace();
}
}
}
new MyJavaFunction(lua).register();
// 现在我们可以在 lua 中直接调用 `getTime(" -suffix")`,
// 得到的返回值类似 2019-06-01 23:56:49 -suffix 我们创建一个类继承 与传参类似,返回值也是直接入栈即可。最后我们需要返回返回值的个数,这样 Lua 就知道从栈里取出几个元素作为返回值了。这些元素会被自动出栈。这里我们利用 最后实例化刚才包装的类就可以成功注册了。现在我们可以在 Lua 中调用
注入 java 对象除了注入简单的 java 函数,甚至可以直接注入一个 java 对象,这样这个对象所拥有的所有成员都可以在 Lua 中直接使用。 java: TextView textView = findViewById(R.id.textView);
lua.pushJavaObject(textView);
lua.setGlobal("textView");
lua.pushInteger(Color.RED);
lua.setGlobal("red");
// 现在可以直接在 Lua 中调用 `textView:setTextColor(red)` 来将文本框设置为红色
// setTextColor() 是 TextView 的成员函数,我们没有显式注入但可以直接使用。
// 类似的,setTextSize() 也可以直接使用。 使用
Lua 回调 (HTTP 请求)前面讲了 Lua 调用 java 函数并可以取得返回值,这是在单线程情况下的。如果 java 需要异步执行一个耗时的操作(例如 HTTP 请求),那么就需要 Lua 提供一个回调函数。Lua 是支持闭合函数(closure)的,因此回调要比 java 定义一个接口简单不少。下面看一个例子: java: // 简单起见省略了一些代码和必要的 try-catch
public class AsyncJavaFunction extends JavaFunction {
// lua 回调函数
private LuaObject callbackFun;
@Override
public int execute() {
if (L.isFunction(2)) {
callbackFun = L.getLuaObject(2); // 获取回调
new MyAsync().execute();
}
return 0;
}
private class MyAsync extends AsyncTask<Integer, Integer, Integer> {
long t;
@Override
protected void onPreExecute() {
super.onPreExecute();
t = System.currentTimeMillis();
}
@Override
protected Integer doInBackground(Integer... integers) {
Thread.sleep(2000); // 模拟耗时操作(例如网络请求)
return null;
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
if (callbackFun != null)
callbackFun.call(new Object[]{"OK", System.currentTimeMillis() - t}, 0);
}
}
} lua: http(function(result, time)
r = string.format("result: %s\ntime: %dms", result, time)
end
)
-- 最后r的结果可能是:result: OK \n time: 2231ms 类似前面的,首先我们需要向 Lua 注入一个 java 函数并取得 Lua 传入的参数。只不过这一次有一个参数是 当 java 异步任务执行完毕后,通过
更多高级用法基础用法基本上讲完了,其实所谓的高级用法都是由基础用法拼接来的。尤其是 这个 README 只是抛砖引玉,帮助各位快速在 Android 上整合 Lua,更加深入的问题还请自行查阅 Lua API 文档或其他资料。 链接 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论