-
Notifications
You must be signed in to change notification settings - Fork 115
Android集成使用文档(适用1.x.x版本)
打开项目的Gradle文件,在dependencies
中增加一行compile 'com.github.vimfung.luascriptcore:luascriptcore:1.3.1'
即可正常使用LuaScriptCore。
-
下载源码到本地
-
打开Release目录,将Android目录中的LuaScriptCore.jar文件拷贝到项目的libs目录中,其他的子目录(如:arm64-v8a、armeabi等)拷贝到jniLibs目录中。
-
在Android Studio中选中刚添加的LuaScriptCore.jar,右键弹出菜单选择"Add As Library..."。
-
打开主模块的build.gradle配置文件,设置jniLibs.srcDirs属性,如下:
android { //... sourceSets { main { jniLibs.srcDirs "jniLibs" } } }
-
成功编译后则可以正常使用LuaScriptCore了。
- 打开Android Studio,然后导入Source/Android/目录下的项目。
- Command + F9 重新编译目录。
- 编译成功后,在模块的build/intermediates/bundles/release目录可以找到一个classes.jar和jni的文件夹。
- 这个jar和jni目录中的so库就是LuaScriptCore的库文件。
LuaScriptCore中提供了LuaContext这个上下文对象类来维护整个Lua的环境,所以使用LuaScriptCore的第一步就是对LuaContext进行初始化。如:
LuaContext context = LuaContext.create(this);
初始化完毕后才能进行下面的各种操作。
原生层中要操作Lua中的变量或者方法,通常使用到的就是组织Lua脚本来进行一些列的Lua操作(LuaScriptCore屏蔽了Lua库中的C Api,目的是让代码更加接近原生,使用起来更加得心应手),然后交由Context进行脚本的解析。如:
context.evalScript("print('Hello World');");
对于一些耗时或者Lua无法实现的功能(如:手机设备的拍照),都可以考虑交由原生层来实现,然后提供接口让Lua进行调用。如下面获取手机设备信息的方法:
在Java代码中定义方法
context.registerMethod("getDeviceInfo", new LuaMethodHandler() {
@Override
public LuaValue onExecute(LuaValue[] arguments) {
HashMap devInfoMap = new HashMap();
devInfoMap.put("deviceName", Build.DISPLAY);
devInfoMap.put("deviceModel", Build.MODEL);
devInfoMap.put("systemName", Build.PRODUCT);
devInfoMap.put("systemVersion", Build.VERSION.RELEASE);
return new LuaValue(devInfoMap);
}
});
在Lua代码中调用方法
local tbl = getDeviceInfo();
有时候需要通过调用Lua中的方法来取得返回值(在原生层中只能取得一个返回值),然后再做后续的处理,例如:
在Lua代码中有add方法的定义
function add (a, b)
return a+b;
end
在Java代码中通过context调用Lua方法
LuaValue retValue = context.callMethod("add", new LuaValue[]{new LuaValue(100), new LuaValue(924)});
Log.v("luaScriptCore", String.format("%d", retValue.toInteger()));
LuaContext所定义的方法都是全局的,有时候需要对一系列的方法进行一个包装,希望这些方法都归类在某个模块下,一来方便根据模块来划分方法的功能,二来可以避免名称的冲突。因此,可以使用LuaModule来对Lua的功能进行扩展。需要根据下面步骤实现:
- 新声明一个模块类继承于LuaModule类(必须继承于LuaModule类,否则无法进行模块注册)
- 在创建的模块类中定义需要导出到lua的类方法(即static修饰的方法),声明方法完全跟Java声明方法一样(对于不想导出到Lua的方法可以在设置为非public访问权限或者以下划线“_”开头)。
- 调用LuaContext的registerModule方法将定义的类型传入即完成功能模块的扩展。
下面例子定义了一个日志模块,如:
在Java代码中定义LuaModule的子类
/**
* 日志模块
* Created by vimfung on 16/9/23.
*/
public class LogModule extends LuaModule
{
public static String version()
{
return "1.0.0";
}
public static void writeLog(String message)
{
Log.v("luascriptcore", message);
}
}
注册模块
luaContext.registerModule(LogModule.class);
在Lua代码中调用
LogModule.writeLog('Hello Lua Module!');
Lua中没有明确的面向对象特性,LuaScriptCore提供了一个面向对象的扩展,Lua可以简单地封装类型,并且进行类型实例的使用。首先需要先注册面向对象的模块类LuaObjectClass(如果原生层有继承于LuaObjectClass类的子类需要注册时,该步骤可省略),如:
luaContext.registerModule(LuaObjectClass.class);
注册成功后,可以直接在Lua中定义类型,如:
Object.subclass("MyClass");
-- 重写类型的初始化方法
function MyClass:init ()
print("MyClass instance initialize...");
end
-- 定义类型属性
MyClass.property = 0;
local instance = MyClass.create();
print (instance.property);
上述代码的subclass就是子类化对象方法,其接收一个类型名称参数,调用后会创建一个对应名称的类型。该类型拥有Object的所有特性。
对于Lua的类定义有如下设定:
- 所有类型的根类是Object,这个注册LuaObjectClass后会有这个类的定义.
- 必须使用subclass方法来进行子类化,必须传入一个有效并且不重复的类型名称参数。
- 必须使用类型的create方法进行类对象的实例化。
- 类型中的方法(即类方法)都以.号进行调用,类实例中的方法都以:号进行调用。类型和实例的属性都以.号进行访问。
- 每个类中都有一个叫super的属性来指代其父类型。
- 需要调用父类方法时,请使用"类型.super:method"方式进行调用,如:
MyClass.super:test();
。- 当类实例对象初始化时会触发init方法,销毁时会触发destroy方法,可以通过重写这些方法来进行一些额外的工作。
如果需要让原生类直接映射到Lua中,按照下面步骤实现:
- 定义一个新的类继承于LuaObjectClass类。
- 定义新类型的属性和方法(注:原生类中的public访问权限的属性会转换为Lua类中的setXXX和XXX方法),对于不想导出到Lua中的方法或属性可以在声明时使用非public访问权限或以下划线"_"开头。
- 定义类的类方法会导出给类型,定义实例方法会导出给类型的实例
- 调用LuaContext的registerModule方法将定义的类型传入即完成Lua类的声明。导入时可以直接导入子类,LuaContext会检测是否有导入根类型。
如在Java中有如下类型定义:
public class Person extends LuaObjectClass
{
public String name;
public void speak()
{
Log.v("luascriptcore", String.format("%s speak", name));
}
public void walk()
{
Log.v("luascriptcore", String.format("%s walk", name));
}
public static void printPersonName (Person person)
{
NSLog(@"Person name = %@", person.name);
}
public Person(LuaContext context)
{
super(context);
};
}
然后对该类型进行注册:
_luaContext.registerModule(Person.class);
注册成功后,在lua中即可使用该类型:
local person = Person.create();
person:setName("vimfung");
person:walk();
person:speak();
Person.printPersonName(person);
从v1.3.1版本开始,LuaScriptCore提供了ClassImport允许动态导入原生类型到Lua的功能。目的是为了帮助在程序执行过程中需要调用非LuaObjectClass子类型的原生对象功能。若要使用ClassImport请注册模块:
_luaContext.registerModule(LuaClassImport.class);
假设存在一个NativeData的类型,如:
public class NativeData
{
public String dataId;
private HashMap<String, String> _data = new HashMap<String, String>();
public static Person createPerson()
{
return new Person();
}
public void setData(String key, String value)
{
_data.put(key, value);
}
public String getData(String key)
{
return _data.get(key);
}
}
然后设置允许动态导出的类型,基于安全的考虑默认是不允许导出任意类型到Lua中的,所以必须要设置哪些类型允许被导出,如:
ArrayList<Class> exportsClasses = new ArrayList<Class>();
exportsClasses.add(NativeData.class);
LuaClassImport.setInculdesClasses(_luaContext, exportsClasses);
然后在Lua中进行使用:
local Data = ClassImport('cn.vimfung.luascriptcore.sample.NativeData');
print(Data);
local d = Data.create();
print(d);
d:setDataId('xxxx');
print(d:dataId());
d:setData('xxx','testKey');
print(d:getData('testKey'));
关于ClassImport的几点注意事项
- 只能导入允许的类型。
- 当导入LuaObjectClass的子类型时会触发类型注册,并返回指定类型。
- ClassImport导入的类型为全属性全方法导出,不带有继承特性(导入LuaObjectClass子类型除外)。