Skip to content
master
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
Dec 15, 2021
Dec 15, 2021

Dart_Native

Dart_Native operates as both a code generator tool and a bridge to communicate between Dart and native APIs.

Replaces the low-performing Flutter channel with faster and more concise code.

  • Under development

pub package Build Status Dart CI

This package is the blue part(DartNative Bridge):

Requirements

Dart_Native Version Flutter Requirements Codegen Version
0.4.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 & Android

Usage

  1. Add dart_native to dependencies and build_runner to dev_dependencies.

  2. Generate Dart wrapper code with @dartnative/codegen or write Dart code manually.

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

Features

High-performance synchronous & asynchronous channeling

Dart_Native costs significantly less time than the Flutter channel and supports both synchronous and asynchronous channeling. A comparison of two native channeling tasks using Flutter channel and Dart_Native is shown below.

Both tasks were executed 10,000 times in the same environment using either Flutter channel or Dart_Native:

Task Total time cost (ms) (Channel/Dart_Native) Channeling time cost (ms) (Channel/Dart_Native)
Checking if an app needs to be installed 5202/4166 919/99
Logging 2480/2024 1075/432

Autogenerate succinct bridging code

Dart_Native supports automatic type conversion so its bridging code is shorter & simpler than the Flutter channel.

A comparison of the task of "checking if an app needs to be installed" is shown below:

# of lines of bridging code Coding complexity
Dart_Native Dart 1 + Native 1 Autogenerated code returns BOOL directly
Channel Dart 15 + Native 30 Needs to manually define return format, convert INT to BOOL, determine channel & methodName

Automatic object marshalling between Dart and native

Examples

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

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

Documentation

Readme

  1. dart_native README.md
  2. dart_native_gen README.md

Further reading

FAQs

Q: Failed to lookup symbol (dlsym(RTLD_DEFAULT, InitDartApiDL): symbol not found) on iOS archive.

A: Select one solution:

  1. Use dynamic library: Add use_frameworks! in Podfile.
  2. 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.