⚠️ 此代码仓已归档。新地址请访问 flutter_dart_native。| ⚠️ This repository has been archived. For the new address, please visit flutter_dart_native.
DartNative operates as a bridge to communicate between Dart and native APIs.
Replaces the low-performing Flutter channel with faster and more concise code.
DartNative calls any native API dynamically. It supports both synchronous and asynchronous channeling.
Serialization of parameters and return values like Flutter Channel is no longer required. DartNative provides direct calls and automatic object marshalling between language interfaces.
Dart finalizer is only supported above Flutter 3(Dart 2.17), but with DartNative it is available in Dart Flutter 2.2.0(Dart 2.13.0) and up.
DartNative supports automatic type conversion so its bridging code is shorter & simpler than the Flutter channel.
The design and vision of this package:
DartNative Version | Flutter Requirements | Codegen Version |
---|---|---|
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
Add dart_native
to dependencies and build_runner
to dev_dependencies. Then you can write code. Here are some examples:
Dart code:
final interface = Interface("MyFirstInterface");
// Example for string type.
String helloWorld() {
return interface.invokeMethodSync('hello', args: ['world']);
}
// Example for num type.
Future<int> sum(int a, int b) {
return interface.invokeMethod('sum', args: [a, b]);
}
Corresponding Objective-C code:
@implementation DNInterfaceDemo
// Register interface name.
InterfaceEntry(MyFirstInterface)
// Register method "hello".
InterfaceMethod(hello, myHello:(NSString *)str) {
return [NSString stringWithFormat:@"hello %@!", str];
}
// Register method "sum".
InterfaceMethod(sum, addA:(int32_t)a withB:(int32_t)b) {
return @(a + b);
}
@end
Corresponding Java code:
// load 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;
}
}
NOTE: If your so path is custom, you need pass specific path.
DartNativePlugin.loadSoWithCustomPath("xxx/libdart_native.so");
And before using DartNative in dart, first invoke dartNativeInitCustomSoPath()
. It will get path from channel.
Dart code:
interface.setMethodCallHandler('totalCost',
(double unitCost, int count, List list) async {
return {'totalCost: ${unitCost * count}': list};
});
Corresponding Objective-C code:
[self invokeMethod:@"totalCost"
arguments:@[@0.123456789, @10, @[@"testArray"]]
result:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@", result);
}];
Corresponding Java code:
invokeMethod("totalCost", new Object[]{0.123456789, 10, Arrays.asList("hello", "world")},
new DartNativeResult() {
@Override
public void onResult(@Nullable Object result) {
Map retMap = (Map) result;
// do something
}
@Override
public void error(@Nullable String errorMessage) {
// do something
}
}
);
final foo = Bar(); // A custom instance.
unitTest.addFinalizer(() { // register a finalizer callback.
print('The instance of \'foo\' has been destroyed!'); // When `foo` is destroyed by GC, this line of code will be executed.
});
Dart | Objective-C | Swift | Java |
---|---|---|---|
null | nil | nil | null |
bool | BOOL | Bool | bool |
int | NSInteger | Int | int |
double | double | Double | double |
String | NSString | String | String |
List | NSArray | Array | List, ArrayList |
Map | NSDictionary | Dictionary | Map, HashMap |
Set | NSSet | Set | Set, HashSet |
Function | Block | Closure | Promise |
Pointer | void * | UnsafeMutableRawPointer | - |
NativeByte | NSData | Data | DirectByteBuffer |
NativeObject | NSObject | NSObject | Object |
Step 1: Add dart_native
to dependencies and build_runner
to dev_dependencies.
Step 2: Generate Dart wrapper code with @dartnative/codegen or write Dart code manually.
Step 3: Generate code for automatic type conversion using dart_native_gen with the following steps (3.1-3.3):
3.1 Annotate a Dart wrapper class with @native
.
@native
class RuntimeSon extends RuntimeStub {
RuntimeSon([Class isa]) : super(Class('RuntimeSon'));
RuntimeSon.fromPointer(Pointer<Void> ptr) : super.fromPointer(ptr);
}
3.2 Annotate your own entry (such asmain()
) with @nativeRoot
.
@nativeRoot
void main() {
runApp(App());
}
3.3 Run
flutter packages pub run build_runner build --delete-conflicting-outputs
to generate files into your source directory.
Note: we recommend running clean
first:
flutter packages pub run build_runner clean
Step 4: Call autogenerated function in <generated-name>.dn.dart
in 3.3. The function name is determined by name
in pubspec.yaml
.
@nativeRoot
void main() {
// Function name is generated by name in pubspec.yaml.
runDartNativeExample();
runApp(App());
}
Step 5: Then you can write code. Here are some examples:
5.1 iOS:
Dart code (generated):
// new Objective-C object.
RuntimeStub stub = RuntimeStub();
// Dart function will be converted to Objective-C block.
stub.fooBlock((NSObject a) {
print('hello block! ${a.toString()}');
return 101;
});
// support built-in structs.
CGRect rect = stub.fooCGRect(CGRect(4, 3, 2, 1));
print(rect);
Corresponding Objective-C code:
typedef int(^BarBlock)(NSObject *a);
@interface RuntimeStub
- (CGRect)fooCGRect:(CGRect)rect;
- (void)fooBlock:(BarBlock)block;
@end
More iOS examples see: ios_unit_test.dart
5.2 Android:
Dart code (generated):
// new Java object.
RuntimeStub stub = RuntimeStub();
// get java list.
List list = stub.getList([1, 2, 3, 4]);
// support interface.
stub.setDelegateListener(DelegateStub());
Corresponding Java code:
public class RuntimeStub {
public List<Integer> getList(List<Integer> list) {
List<Integer> returnList = new ArrayList<>();
returnList.add(1);
returnList.add(2);
return returnList;
}
public void setDelegateListener(SampleDelegate delegate) {
delegate.callbackInt(1);
}
}
More android examples see: android_unit_test.dart
NOTE: If you use dart_native on macOS, you must use use_frameworks!
in your Podfile.
Q: Failed to lookup symbol (dlsym(RTLD_DEFAULT, InitDartApiDL): symbol not found) on macOS archive.
A: Select one solution:
use_frameworks!
in Podfile.DartNative is available under the BSD 3-Clause License. See the LICENSE file for more info.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。