-
Notifications
You must be signed in to change notification settings - Fork 207
新增Bridge
xuwhale6 edited this page Jan 19, 2020
·
18 revisions
根据是否需要创建实例分类(面向对象分类):
- 实例类型,需要在业务层创建对象,Lua可GC,虚拟机销毁时释放所有未释放的实例
- 静态类型,和原生静态方法类似,不需要创建对象,和虚拟机共存亡
- 枚举类型,主要是字符串或数字枚举
根据Lua调用方式分类:
- 实例调用型: object = BridgeName() object:methodName()
- 静态调用型: BridgeName:methodName()
- 枚举调用型: BridgeName.name
Android桥接步骤分三步:
1.新建桥接类
2.编写桥接方法
3.在Application中通过MLSEngine注册
- 静态调用型,可分为两类,一类为单例,一类为静态方法。
- 单例:即有状态(虚拟机销毁时通知),调用和静态类型相同(不需要创建对象)
将MLN模板压缩包解压后的MLN文件夹放入Android Studio安装目录/Contents/plugins/android/lib/templates文件夹下
中(注:如果安装多个版本的studio,需要将压缩包放入使用版本的目录下),重启Android Studio。在New选项中,将会看到MLN选项,根据需要做相应选择。建议优先选择带(Simple)
标记的构建方法。
如图:
建议使用模板,能通过提示或注释快速创建Bridge,下面以SingleInstance为例讲解如何新建Bridge类和方法
1)在工程下选择一个目录->new->MLN->SingleInstance,Java Class Name命名为UDTestBridge,Lua Class Name命名为Toast,添加Bridge方法:
@LuaBridge
public void toast(String text) {
// 调用该方法时会弹出吐司
Toast.makeText(MLSEngine.getContext(), text, Toast.LENGTH_SHORT);
}
2)注册新建的UDTestBridge类,可以在Application中调用如下代码:
MLSEngine.registerUD(Register.newUDHolderWithLuaClass(UDTestBridge.LUA_CLASS_NAME, UDTestBridge.class, true))
3)在lua中调用桥接的toast方法
local obj = Toast()
window:onClick(function ()
obj:toast("新建bridge")
end)
4)查看结果,调用toast方法后,点击屏幕会弹出吐司:"新建bridge"(创建的应用需要手动获取存储权限)
MLSEngine.init(this, BuildConfig.DEBUG)
.setLVConfig(new LVConfigBuilder(this)
.setRootDir(SD_CARD_PATH) //set lua root directory
.setImageDir(SD_CARD_PATH + "image") // set lua picture root directory
.setCacheDir(SD_CARD_PATH + "cache") // set lua cache directory
.setGlobalResourceDir(SD_CARD_PATH + "g_res") // set the resource file directory
.build())
.setImageProvider(new GlideImageProvider()) // lua loading image tool, if it is not implemented, the image cannot be displayed
.registerSingleInsance(new MLSBuilder.SIHolder(UDTestBridge1.LUA_CLASS_NAME, UDTestBridge1.class))
.registerSingleInsance(new MLSBuilder.SIHolder(UDTestBridge.LUA_CLASS_NAME, UDTestBridge.class))
.registerConstants(TestEnum.class) // enum in lua
.registerUD(Register.newUDHolderWithLuaClass(TestUserDataBridge.LUA_CLASS_NAME, TestUserDataBridge.class, true)) // register the Userdata class in lua
.registerSC(Register.newSHolderWithLuaClass(TestStaticBridge.LUA_CLASS_NAME, TestStaticBridge.class)) // register the static tool class in Lua, that is StaticBridge
.registerSingleInsance(new MLSBuilder.SIHolder(TestSingleInstance.LUA_CLASS_NAME, TestSingleInstance.class)) // register singleton in lua
.registerUD(Register.newUDHolder(TestLuaView.LUA_CLASS_NAME, TestLuaView.class, true, TestLuaView.methods)) // LuaView registration method
.build(true);
iOS桥接步骤分三步:
1.新建桥接类
2.编写桥接方法
3.注册到Instance中
#import <UIKit/UIKit.h>
#import "MLNEntityExportProtocol.h"
#import "MLNView.h"
NS_ASSUME_NONNULL_BEGIN
@interface MLNTestView : MLNView <MLNEntityExportProtocol>
@end
NS_ASSUME_NONNULL_END
#import "MLNTestView.h"
#import "MLNViewExporterMacro.h"
#import "UIView+MLNKit.h"
@interface MLNTestView()
@property (nonatomic, copy) NSString *text;
@end
@implementation MLNTestView
//将虚拟机与注册类绑定
- (instancetype)initWithLuaCore:(MLNLuaCore *)luaCore frame:(CGRect)frame
{
if (self = [super initWithLuaCore:luaCore frame:frame]) {
}
return self;
}
//这是一个测试桥接方法,展示一个Label到TestView上
- (void)lua_showLabel
{
UILabel *label = [[UILabel alloc] initWithFrame:self.bounds];
[self addSubview:label];
label.text = _text;
}
#pragma mark - Export To Lua
/**
导出View开始
@param CLZ 类名 (例:NSObject)
*/
LUA_EXPORT_VIEW_BEGIN(MLNTestView)
/**
导出属性方法映射
@param LUA_FUNC Lua中的方法名称
@param SETTER_NAME 原生View属性的setter方法
@param GETTER_NAME 原生View属性的getter方法
@param CLZ 原生类名称
*/
LUA_EXPORT_VIEW_PROPERTY(text, "setText:", "text", MLNTestView)
/**
导出方法映射
@param LUA_FUNC Lua中的方法名称
@param SEL_NAME 原生View的对象方法名称
@param CLZ 原生类名称
*/
LUA_EXPORT_VIEW_METHOD(show, "lua_showLabel", MLNTestView)
/**
标记完成View UserData类导出
@note ⚠️如果需要自定义初始化方法,第一个参数必须是MLNLuaCore。
@param CLZ 原生类名称
@param LUA_CLZ Lua中的类名称
@param HAS_SUPER 是否有父类 (YES/NO),这是在Lua中的继承关系,并非原生的继承关系
@param SUPERCLZ 父类的原生类名字,可以没有原生的继承关系。
@param CONSTRUCTOR_NAME 构造器方法,默认为”initWithLuaCore:“。
**/
LUA_EXPORT_VIEW_END(MLNTestView, TestView, YES, "MLNView", "initWithLuaCore:frame:")
@end
简单的使用场景,在创建Lua控制器的时候,可以注册一组桥接类
- 新建一个demo.lua文件如下,点击TestView的时候,展示一个Label到视图上
testView = TestView():marginTop(120):width(300):height(300)
testView:bgColor(Color(211,211,211, 1.0))
testView:text("哈哈哈哈哈")
local text = testView:text()
print("text:", text)
window:addView(testView)
--点击,展示Label
testView:onClick(function()
testView:show()
end)
- 创建MLN控制器,注册桥接类,push后展示demo
// 在默认的包含MLNKitInstance的视图控制器中注册桥接类,可通过加载本地lua进行测试
MLNKitViewController *viewController = [[MLNKitViewController alloc] initWithEntryFilePath:@"demo.lua"];
[viewController regClasses:@[[MLNTestView class]]];
[self.navigationController pushViewController:viewController animated:YES];
//or 在热重载控制器中注册桥接类,采用HotReload方式进行测试
MLNHotReloadViewController *hotVC = [[MLNHotReloadViewController alloc] initWithRegisterClasses:@[[MLNTestView class]] extraInfo:nil navigationBarTransparent:YES];
[self.navigationController pushViewController:hotVC animated:YES];
#import <Foundation/Foundation.h>
#import <MLNCore.h>
NS_ASSUME_NONNULL_BEGIN
@interface MLNTestObject : NSObject <MLNEntityExportProtocol>
@end
NS_ASSUME_NONNULL_END
#import "MLNTestObject.h"
#import "MLNBlock.h"
@interface MLNTestObject()
@property (nonatomic, copy) NSString *message;
@end
@implementation MLNTestObject
#pragma mark - 测试接收数据
- (void)testReceive:(NSString *)msg
{
_message = msg;
NSLog(@"收到了:%@",msg);
}
#pragma mark - 测试接返回数据
- (NSInteger)testAdd:(NSInteger)numberA numberB:(NSInteger)numberB
{
return numberA + numberB;
}
#pragma mark - 测试回调数据
- (void)testAddWithCallback:(NSInteger)numberA numberB:(NSInteger)numberB callback:(MLNBlock *)callback
{
if (callback) {
//添加参数
[callback addIntegerArgument:numberA + numberB];
//回调给Lua
[callback callIfCan];
}
}
#pragma mark - 注册方法到lua中
LUA_EXPORT_BEGIN(MLNTestObject)
LUA_EXPORT_PROPERTY(message, "setMessage:", "message", MLNTestObject)
LUA_EXPORT_METHOD(testReceive, "testReceive:", MLNTestObject)
LUA_EXPORT_METHOD(testAdd, "testAdd:numberB:", MLNTestObject)
LUA_EXPORT_METHOD(testAddWithCallback, "testAddWithCallback:numberB:callback:", MLNTestObject)
LUA_EXPORT_END(MLNTestObject, TestObject, NO, NULL, NULL)
@end
- 注册到Lua中
[viewController regClasses:@[[MLNTestObject class]]];
- Lua测试代码
test = TestObject()
--发送数据到原生
test:testReceive("哈哈哈哈哈,你好呀")
--读取原生收到并记录的值
print("message:", test:message())
--调用原生加法,返回值方式
print("11 + 22 = ", test:testAdd(11,22))
test:testAddWithCallback(11, 22, function(sum)
--异步获取计算结果
print("callback sum:", sum)
end)
#import <Foundation/Foundation.h>
#import <MLNCore.h>
NS_ASSUME_NONNULL_BEGIN
@interface MLNStaticObject : NSObject <MLNStaticExportProtocol>
@end
NS_ASSUME_NONNULL_END
2.桥接静态类方法
#import "MLNStaticObject.h"
@implementation MLNStaticObject
+ (void)test:(NSString *)msg
{
NSLog(@"static test: %@", msg);
}
LUA_EXPORT_STATIC_BEGIN(MLNStaticObject)
LUA_EXPORT_STATIC_METHOD(test, "test:", MLNStaticObject)
LUA_EXPORT_STATIC_END(MLNStaticObject, StaticObject, NO, NULL)
@end
3.注册并测试
- 注册
MLNLuaPageViewController *viewController = [[MLNLuaPageViewController alloc] initWithEntryFilePath:entryFile];
[viewController regClasses:@[[MLNStaticObject class]]];
- 测试
StaticObject:test("测试静态类方法")
桥接的对象有某些情况下,有不同参数个数的场景,此时需要有一个处理多参数的能力,下面介绍一下如何桥接这种类型的对象。
#import <Foundation/Foundation.h>
#import "MLNEntityExportProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface MLNMultiParamObject : NSObject <MLNEntityExportProtocol>
@end
NS_ASSUME_NONNULL_END
#import "MLNMultiParamObject.h"
#import "MLNLuaCore.h"
#import "MLNKitHeader.h"
@interface MLNMultiParamObject()
@property (nonatomic, assign) NSInteger a;
@property (nonatomic, assign) NSInteger b;
@property (nonatomic, assign) NSInteger c;
@end
@implementation MLNMultiParamObject
- (instancetype)initWith:(NSInteger)a b:(NSInteger)b c:(NSInteger)c
{
if (self = [super init]) {
_a = a;
_b = b;
_c = c;
}
return self;
}
static int lua_multi_param_init(lua_State *L) {
MLNMultiParamObject *object = nil;
NSUInteger argCount = lua_gettop(L);
switch (argCount) {
case 3: {
NSUInteger a = lua_tonumber(L, 1);
NSUInteger b = lua_tonumber(L, 2);
NSUInteger c = lua_tonumber(L, 3);
object = [[MLNMultiParamObject alloc] initWith:a b:b c:c];
}
break;
case 2: {
NSUInteger a = lua_tonumber(L, 1);
NSUInteger b = lua_tonumber(L, 2);
object = [[MLNMultiParamObject alloc] initWith:a b:b c:-1];
}
break;
case 1: {
NSUInteger a = lua_tonumber(L, 1);
object = [[MLNMultiParamObject alloc] initWith:a b:-1 c:-1];
}
break;
default: {
object = [[MLNMultiParamObject alloc] init];
object.a = -1;
object.b = -1;
object.c = -1;
break;
}
}
if (object) {
// 标记为Lua创建
object.mln_isLuaObject = YES;
[MLN_LUA_CORE(L) pushNativeObject:object error:NULL];
return 1;
}
return 0;
}
- (void)lua_descript
{
NSLog(@"a:%ld, b:%ld, c:%ld", _a, _b, _c);
}
#pragma mark - Export To Lua
LUA_EXPORT_BEGIN(MLNMultiParamObject)
LUA_EXPORT_METHOD(descript, "lua_descript", MLNTestObject)
LUA_EXPORT_END_WITH_CFUNC(MLNMultiParamObject, MultiParamObject, NO, NULL, lua_multi_param_init)
@end
- 注册
MLNLuaPageViewController *viewController = [[MLNLuaPageViewController alloc] initWithEntryFilePath:entryFile];
[viewController regClasses:@[[MLNMultiParamObject class]]];
- 测试
multi1 = MultiParamObject(1,2,3)
multi2 = MultiParamObject(1,2)
multi3 = MultiParamObject(1)
multi4 = MultiParamObject()
multi1:descript()
multi2:descript()
multi3:descript()
multi4:descript()