dart_native

Creator: coderz1093

Last updated:

Add to Cart

Description:

dart native

DartNative #
DartNative operates as a bridge to communicate between Dart and native APIs.
Replaces the low-performing Flutter channel with faster and more concise code.



Features #
Dynamic synchronous & asynchronous channeling #
DartNative calls any native API dynamically. It supports both synchronous and asynchronous channeling.
Direct call between multi-language interfaces #
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 #
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.
Autogenerate succinct bridging code #
DartNative supports automatic type conversion so its bridging code is shorter & simpler than the Flutter channel.
The design and vision of this package:

Requirements #



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



Supported Platforms #
iOS & macOS & Android
Usage #
Basic usage: Interface binding #
Add dart_native to dependencies and build_runner to dev_dependencies. Then you can write code. Here are some examples:
Dart calls Native
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]);
}
copied to clipboard
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
copied to clipboard
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;
}
}
copied to clipboard
NOTE: If your so path is custom, you need pass specific path.
DartNativePlugin.loadSoWithCustomPath("xxx/libdart_native.so");
copied to clipboard
And before using DartNative in dart, first invoke dartNativeInitCustomSoPath(). It will get path from channel.
Native calls Dart
Dart code:
interface.setMethodCallHandler('totalCost',
(double unitCost, int count, List list) async {
return {'totalCost: ${unitCost * count}': list};
});
copied to clipboard
Corresponding Objective-C code:
[self invokeMethod:@"totalCost"
         arguments:@[@0.123456789, @10, @[@"testArray"]]
            result:^(id _Nullable result, NSError * _Nullable error) {
    NSLog(@"%@", result);
}];

copied to clipboard
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
}
}
);
copied to clipboard
Dart finalizer
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.
});
copied to clipboard
Data types support



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



Advanced usage: Invoke methods dynamically #


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);
}
copied to clipboard


3.2 Annotate your own entry (such asmain()) with @nativeRoot.
@nativeRoot
void main() {
runApp(App());
}
copied to clipboard


3.3 Run
flutter packages pub run build_runner build --delete-conflicting-outputs
copied to clipboard
to generate files into your source directory.
Note: we recommend running clean first:
flutter packages pub run build_runner clean
copied to clipboard




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());
}
copied to clipboard


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);

copied to clipboard
Corresponding Objective-C code:
typedef int(^BarBlock)(NSObject *a);

@interface RuntimeStub

- (CGRect)fooCGRect:(CGRect)rect;
- (void)fooBlock:(BarBlock)block;

@end
copied to clipboard
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());

copied to clipboard
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);
}
}
copied to clipboard
More android examples see: android_unit_test.dart




NOTE: If you use dart_native on macOS, you must use use_frameworks! in your Podfile.
Documentation #
Further reading #

告别 Flutter Channel,调用 Native API 仅需一行代码!
如何实现一行命令自动生成 Flutter 插件
用 Dart 来写 Objective-C 代码
谈谈 dart_native 混合编程引擎的设计
DartNative Memory Management: Object
DartNative Memory Management: C++ Non-Object
DartNative Struct
在 Flutter 中玩转 Objective-C Block
Passing Out Parameter in DartNative

FAQs #
Q: Failed to lookup symbol (dlsym(RTLD_DEFAULT, InitDartApiDL): symbol not found) on macOS archive.
A: Select one solution:

Use dynamic library: Add use_frameworks! in Podfile.
Select Target Runner -> Build Settings -> Strip Style -> change from "All Symbols" to "Non-Global Symbols"

Contribution #

If you need help or you'd like to ask a general question, open an issue.
If you found a bug, open an issue.
If you have a feature request, open an issue.
If you want to contribute, submit a pull request.

License #
DartNative is available under the BSD 3-Clause License. See the LICENSE file for more info.

License

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files:

Customer Reviews

There are no reviews.