DartNative:Dart与原生API之间的桥梁
DartNative 是一款高效通信工具,用于连接Dart和原生API,它将低效率的Flutter通道替换为更快、更简洁的代码。
功能亮点
动态同步与异步通道
DartNative 支持动态调用任何原生API,无论是同步还是异步,都能轻松应对。
多语言接口直接调用
不再需要像Flutter Channel那样的参数序列化和返回值处理,DartNative 提供了直接调用,实现了不同语言接口间的自动对象转换。
Dart最终器支持
即使你的环境低于Flutter 3(Dart 2.17),DartNative 也能在Dart Flutter 2.2.0(Dart 2.13.0)及更高版本中支持Dart最终器。
简洁的桥接代码生成
DartNative 自动类型转换功能使得其生成的桥接代码比Flutter通道更加简洁。
项目要求
不同的DartNative版本对应不同版本的Flutter和codegen,请参考下表:
| DartNative 版本 | Flutter 要求 | Codegen 版本 | | --- | --- | --- | | 0.4.x - 0.7.x | Flutter 2.2.0 (Dart 2.13.0) | 2.x | | 0.3.x | Flutter 1.20.0 (Dart 2.9.1) | 1.2.x | | 0.2.x | Flutter 1.12.13 (Dart 2.7) | 1.x |
支持平台
包括iOS、macOS和Android。
使用教程
基础用法:接口绑定
首先,在dependencies
添加dart_native
,在dev_dependencies
中添加build_runner
。然后你可以开始编写以下示例代码:
Dart 调用 Native
Dart 代码:
final interface = Interface("MyFirstInterface");
// 示例:字符串类型
String helloWorld() {
return interface.invokeMethodSync('hello', args: ['world']);
}
// 示例:数字类型
Future<int> sum(int a, int b) {
return interface.invokeMethod('sum', args: [a, b]);
}
对应的Objective-C代码:
@implementation DNInterfaceDemo
// 注册接口名称。
InterfaceEntry(MyFirstInterface)
// 注册方法 "hello"。
InterfaceMethod(hello, myHello:(NSString *)str) {
return [NSString stringWithFormat:@"hello %@!", str];
}
// 注册方法 "sum"。
InterfaceMethod(sum, addA:(int32_t)a withB:(int32_t)b) {
return @(a + b);
}
@end
对应的Java代码:
// 加载libdart_native.so
DartNativePlugin.loadSo();
@InterfaceEntry(name = "MyFirstInterface")
public class InterfaceDemo extends DartNativeInterface {
@InterfaceMethod(name = "hello")
public String hello(String str) {
return "hello " + str;
}
@InterfaceMethod(name = "sum")
public int sum(int a, int b) {
return a + b;
}
}
若动态库路径非默认,可采用dartNativeInitCustomSoPath()
初始化,并传入特定路径。
Native 调用 Dart
Dart 代码:
interface.setMethodCallHandler('totalCost',
(double unitCost, int count, List list) async {
return {'totalCost: ${unitCost * count}': list};
});
对应的Objective-C代码:
[self invokeMethod:@"totalCost"
arguments:@[@0.123456789, @10, @[@"testArray"]]
result:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@", result);
}];
对应的Java代码:
invokeMethod("totalCost", new Object[]{0.123456789, 10, Arrays.asList("hello", "world")},
new DartNativeResult() {
@Override
public void onResult(@Nullable Object result) {
Map retMap = (Map) result;
// 进行操作
}
@Override
public void error(@Nullable String errorMessage) {
// 错误处理
}
});
Dart 最终器
final foo = Bar(); // 自定义实例
unitTest.addFinalizer(() { // 注册最终器回调
print('The instance of \'foo\' has been destroyed!'); // 当 'foo' 被GC销毁时,此行会被执行。
});
数据类型支持
DartNative 支持多种数据类型,如null、bool、int、double、String、List、Map、Set以及Function等。具体详情见项目文档。
高级用法:动态调用方法
-
添加
dart_native
至依赖项,将build_runner
加入开发依赖项。 -
使用@dartnative/codegen或手动编写Dart代码进行代码生成。
-
使用dart_native_gen创建自动类型转换代码(步骤3.1-3.3):
- 3.1 在Dart包装类上注解
@native
。@native class RuntimeSon extends RuntimeStub { RuntimeSon([Class isa]) : super(Class('RuntimeSon')); RuntimeSon.fromPointer(Pointer<Void> ptr) : super.fromPointer(ptr); }
- 3.2 在你自己的入口(如
main()
)上注解@nativeRoot
。@nativeRoot void main() { runApp(App()); }
- 3.3 运行以下命令以生成文件:
首先建议运行flutter packages pub run build_runner build --delete-conflicting-outputs
clean
命令:flutter packages pub run build_runner clean
- 3.1 在Dart包装类上注解
-
在第3.3步中生成的
<generated-name>.dn.dart
文件中的函数名(由pubspec.yaml
中的name
决定)调用自动生成的函数。@nativeRoot void main() { // 函数名由 pubspec.yaml 的 name 生成。 runDartNativeExample(); runApp(App()); }
-
根据生成的代码,可以继续编写iOS和Android相关的示例代码。
- iOS 示例(查看
/dart_native/example/lib/ios/unit_test.dart
) - Android 示例(查看
/dart_native/example/lib/android/unit_test.dart
)
- iOS 示例(查看
注意:如果你在macOS上使用dart_native,请确保在Podfile中使用use_frameworks!
。
文档资源
了解更多关于DartNative的信息:
- 告别Flutter Channel,调用Native API只需一行代码!
- 如何实现一行命令自动生成Flutter插件
- 用Dart来写Objective-C代码
- 谈谈dart_Native混合编程引擎设计
- DartNative内存管理:对象
- DartNative内存管理:C++非对象
- DartNative结构体
- 在Flutter中玩转Objective-C Block
- DartNative中传递出参
常见问题
- Q: macOS归档时出现 "Failed to lookup symbol (dlsym(RTLD_DEFAULT, InitDartApiDL): symbol not found)" 错误。 A: 选择其中一个解决方案:
-
- 使用动态库:在Podfile中添加
use_frameworks!
。
- 使用动态库:在Podfile中添加
-
- 选择目标Runner -> 构建设置 -> � rip Style -> 更改为“非全局符号”。
-
贡献说明
- 如需帮助或想要提问,请开放问题。
- 如果发现bug,请提交问题。
- 对于特性请求,请开放问题。
- 如果要贡献,提交拉取请求。
许可证
DartNative遵循BSD 3-Clause许可证。更多信息请参阅LICENSE文件。
尝试DartNative,体验快速、强大的原生API交互,让您的Dart开发工作更加高效!