dna, dart native access. A lightweight dart to native super channel plugin

Related tags

Templates dna
Overview

dna

中文文档 👉

相关文章

dart native access. A lightweight dart to native super channel plugin, You can use it to invoke any native code directly in dart code.

Supported Platform(Language):

  • iOS(Objective-C)
  • Android(Java)

The primary scenario:

  • Implement some simple channels directly in dart code;
  • Native code that are calling using dna can also be hot-reloaded.

Add dependency

  1. Add folllowing code to the pubspec.yaml file in your flutter project:

    dependencies:
    dna:
    	git:[email protected]:Assuner-Lee/dna.git
    

    Reference: https://flutter.dev/docs/development/packages-and-plugins/using-packages

  2. import header file in dart code:

    import 'package:dna/dna.dart';
    
  3. add gradle dependency in Android project:

    implementation 'me.ele:dna-annotations:1.2.0'
    annotationProcessor 'me.ele:dna-compiler:1.2.0'
    
  4. add following conconfiguration in Android project's proguard-rules

    -keep class **.Dna_Class_Proxy { *; }
    -keep class me.ele.dna_compiler.**  { *; }
    -keep class me.ele.dna.**  { *; }
    

Usage

Main class

  • NativeContext: You can use it to describe Native code by Dart code, then call context.execute() to execute the final Native code on associated platform and get the returned value.

  • NativeObject: Used to identify the native variable. The caller NativeObject can call the invoke method to pass in the method name and the parameter array args list in the context of the NativeContext to get the return value NativeObject object.

The API of NativeContext is consistent. Now we will make a detailed introduction for call ObjC using ObjCContext, Then call Java using JAVAContext.

Call ObjC using Dart

ObjCContext is the final executor on iOS platform.

Context call supported

Returned value as caller

ObjC code

NSString *versionString = [[UIDevice currentDevice] systemVersion];
// Return versionString using fluter channel

Dart code

ObjCContext context = ObjCContext();
NativeObject UIDevice = context.classFromString('UIDevice');
NativeObject device = UIDevice.invoke(method: 'currentDevice');
NativeObject version = device.invoke(method: 'systemVersion');

context.returnVar = version; // Can be omitted, See:Quick use of instantiated objects in JSON supported

// Get native execution results directly
var versionString = await context.execute(); 
Returned value as parameters

ObjC code

NSString *versionString = [[UIDevice currentDevice] systemVersion];
NSString *platform = @"iOS-";
versionString = [platform stringByAppendingString: versionString];

// Return versionString using fluter channel

Dart code

ObjCContext context = ObjCContext();
NativeClass UIDevice = context.classFromString('UIDevice');
NativeObject device = UIDevice.invoke(method: 'currentDevice');
NativeObject version = device.invoke(method: 'systemVersion');
NativeObject platform = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']);
version = platform.invoke(method: 'stringByAppendingString:', args: [version]);

context.returnVar = version; // Can be omitted, See:Quick use of instantiated objects in JSON supported

// Get native execution results directly
var versionString = await context.execute(); 

Chaining calls supported

ObjC code

NSString *versionString = [[UIDevice currentDevice] systemVersion];
versionString = [@"iOS-" stringByAppendingString: versionString];

// Return versionString using fluter channel

Dart code

ObjCContext context = ObjCContext();
NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion');
version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]);

context.returnVar = version; // Can be omitted, See:Quick use of instantiated objects in JSON supported


// Get native execution results directly
var versionString = await context.execute(); 

Something about the final returned value of the context

context.returnVar is the marker of the final returned value of context.

  1. When setting context.returnVar, you can get the Native variable corresponding to the NativeObject;
  2. Without setting context.returnVar, execute to the last invoke, if there is a return value, it will be the final returned value of context; if not, it will return a null value.
ObjCContext context = ObjCContext();
context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion');

// Get native execution results directly
var versionString = await context.execute(); 

Quick use of instantiated objects in JSON supported

Sometimes, we need to directly instantiate an object with JSON.

ObjC code

ClassA *objectA = [ClassA new]; 
objectA.a = 1;
objectA.b = @"sss";

Dart code

One way

ObjCContext context = ObjCContext();
NativeObject objectA = context.classFromString('ClassA').invoke(method: 'new');
objectA.invoke(method: 'setA:', args: [1]);
objectA.invoke(method: 'setB:', args: ['sss']);

The other way

ObjCContext context = ObjCContext();
NativeObject objectA = context.newNativeObjectFromJSON({'a':1,'b':'sss'}, 'ClassA');

Call Java using Dart

JAVAContext is the final executor on Android platform, it has all the fetures that ObjCContext have.

  • Context call supported;
  • Chaining calls supported;
  • Quick use of instantiated objects in JSON supported.

In addition, it additionally supports the instantiation of an object from the constructor.

The instantiation of an object from the constructor supported

Java code

String platform = new String("android");

Dart code

NativeObject version = context
            .newJavaObjectFromConstructor('java.lang.String', ["android "])

Fast organization of dual platform code

We provide you with a quick way to initialize and execute context:

static Future traversingNative(ObjCContextBuilder(ObjCContext objcContext), JAVAContextBuilder(JAVAContext javaContext)) async {
    NativeContext nativeContext;
    if (Platform.isIOS) {
      nativeContext = ObjCContext();
      ObjCContextBuilder(nativeContext);
    } else if (Platform.isAndroid) {
      nativeContext = JAVAContext();
      JAVAContextBuilder(nativeContext);
    }
    return executeNativeContext(nativeContext);
}

 

So you can write the native call of two platforms quickly:

platformVersion = await Dna.traversingNative((ObjCContext context) {
    NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion');
    version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]);
    
    context.returnVar = version; // Can be omitted
}, (JAVAContext context) {
    NativeObject versionId = context.newJavaObjectFromConstructor('com.example.dna_example.DnaTest', null).invoke(method: 'getDnaVersion').invoke(method: 'getVersion');
    NativeObject version = context.newJavaObjectFromConstructor('java.lang.String', ["android "]).invoke(method: "concat", args: [versionId]);
    
    context.returnVar = version; // Can be omitted
});

Principle introduction

dna does not involve the transformation from a dart object to a native object, it also does not care about the life cycle of the native object, but focuses on describing the context of native method calls, When context.execute() called, a native method is called through channel, and the call stack is passed in the form of JSON for native dynamic parsing and calling.

for example, Let's take a look at the previous Dart code:

ObjCContext context = ObjCContext();
NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion');
version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]);

context.returnVar = version; // Can be omitted, See: Quick use of instantiated objects in JSON supported

// Get native execution results directly
var versionString = await context.execute(); 

What the execute() method of NativeContext actually called is the following method:

static Future executeNativeContext(NativeContext context) async {
    return await _channel.invokeMethod('executeNativeContext', context.toJSON());
}

 

In the native executed method corresponding to the executeNativeContext method, the received 'JSON' is as follows:

{
	"_objectJSONWrappers": [],
	"returnVar": {
		"_objectId": "_objectId_WyWRIsLl"
	},
	"_invocationNodes": [{
		"returnVar": {
			"_objectId": "_objectId_KNWtiPuM"
		},
		"object": {
			"_objectId": "_objectId_qyfACNGb",
			"clsName": "UIDevice"
		},
		"method": "currentDevice"
	}, {
		"returnVar": {
			"_objectId": "_objectId_haPktBlL"
		},
		"object": {
			"_objectId": "_objectId_KNWtiPuM"
		},
		"method": "systemVersion"
	}, {
		"object": {
			"_objectId": "_objectId_UAUcgnOD",
			"clsName": "NSString"
		},
		"method": "stringWithString:",
		"args": ["iOS-"],
		"returnVar": {
			"_objectId": "_objectId_UiCMaHAN"
		}
	}, {
		"object": {
			"_objectId": "_objectId_UiCMaHAN"
		},
		"method": "stringByAppendingString:",
		"args": [{
			"_objectId": "_objectId_haPktBlL"
		}],
		"returnVar": {
			"_objectId": "_objectId_WyWRIsLl"
		}
	}]
}

Then we maintain an objectsInContextMap on the native side, its key is objectId, and the value is native object.

_invocationNodes is the call context of the method, let's take a look at one of them.

Here we will dynamically call [UIDevice currentDevice], and return the object to objectsInContextMap with _objectId_KNWtiPuM stored in returnVar as the key.

{
	"returnVar": {
		"_objectId": "_objectId_KNWtiPuM"
	},
	"object": {
		"_objectId": "_objectId_qyfACNGb",
		"clsName": "UIDevice"
	},
	"method": "currentDevice"
 },

Here, the object _objectId_KNWtiPuM is the returned value of the previous method. Take it out from the objectsInContextMap, continue the dynamic call, and store the new returned value with the _objectId of the returnVar as the key.

{
	"returnVar": {
		"_objectId": "_objectId_haPktBlL"
	},
	"object": {
		"_objectId": "_objectId_KNWtiPuM" // Will find the real object in objectsInContextMap
	},
	"method": "systemVersion"
}

dna supports automatic package loading and unpacking when the method has parameters, such as int<->NSNumber, If the parameter is not one of the 15 basic types specified by channel but NativeObject, we will find the object from objectsInContextMap and put it into the actual parameter list.

{
	"object": {
		"_objectId": "_objectId_UiCMaHAN"
	},
	"method": "stringByAppendingString:",
	"args": [{
		"_objectId": "_objectId_haPktBlL" // Will find the real object in objectsInContextMap
	}],
	"returnVar": {
		"_objectId": "_objectId_WyWRIsLl"
}

If final returnVar is set, The object corresponding to the returnVar objectId will be found from the objectsInContextMap and called back as the return value of the channel , if not, take the return value of the last invocation(if any).

Author

Change log

version note
0.1.0 alpha version

License

dna is available under the MIT license. See the LICENSE file for more info.

Other Tips

  • Code warehouse will be migrated to eleme in the near future;
  • You are welcome to star, issue and PR.
You might also like...

A Flutter plugin for Android and iOS allowing access to the device cameras, a bit deeper!!

flutter_cameraview A Flutter plugin for Android and iOS allowing access to the device cameras, a bit deeper!!. This plugin was created to offer more a

Oct 22, 2022

A Flutter sensor plugin which provide easy access to the Pitch and Roll on Android and iOS devices.

A Flutter sensor plugin which provide easy access to the Pitch and Roll on Android and iOS devices.

Flutter Aeyrium Sensor Plugin Aeyrium Sensor Plugin A Flutter sensor plugin which provide easy access to the Pitch and Roll on Android and iOS devices

Nov 3, 2022

System info plus - A Flutter plugin to get device Random Access Memory (RAM) size

system_info_plus A Flutter plugin to get device Random Access Memory (RAM) size.

Aug 21, 2022

A Flutter plugin to access TensorFlow Lite apis.

tensorflow_lite A Flutter plugin to access TensorFlow Lite apis. TensorFlow Lite is TensorFlow’s lightweight solution for mobile and embedded devices.

Nov 22, 2022

A Flutter plugin for iOS and Android allowing access to the device cameras.

A Flutter plugin for iOS and Android allowing access to the device cameras.

Jan 8, 2023

A super effective dart library delivering performance & ensuring greater build speed.

A super effective dart library delivering performance & ensuring greater build speed.

A super effective Dart and Flutter library for delivering performante app 🌝 & ensuring greater build speed 🚀 . The package has some cook utilizes wh

Nov 22, 2021

A lightweight flutter plugin to check if your app is up-to-date on Google Play Store or Apple App Store

App Version Checker this package is used to check if your app has a new version on playstore or apple app store. or you can even check what is the lat

Dec 14, 2022

Super Useful Flutter Layouts - Right in Your Pocket. 😉

Super Useful Flutter Layouts - Right in Your Pocket. 😉

Super Useful Flutter Layouts - Right in Your Pocket. 😉 Update: Flutter web app preview here: https://flutter-layouts-demo.web.app/ YouTube video walk

Jan 8, 2023

A super powerful widget to help developers build complex views quickly and comfortably.

A super powerful widget to help developers build complex views quickly and comfortably.

FSuper FSuper can help developers build complex views quickly and comfortably. It supports rich text, rounded corners, borders, pictures, small red do

Dec 29, 2022
Owner
Assuner
An iOS Developer With Great Enthusiasm
Assuner
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
Write iOS&Android Code using Dart. This package liberates you from redundant glue code and low performance of Flutter Channel.

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 F

DartNative 893 Jan 4, 2023
An open source food delivery product and service that will be developed on the FilledStacks YouTube channel

Box't Out An open source food delivery product and service that will be developed on the FilledStacks YouTube channel. The repo will contain all the s

Dane Mackier 379 Jan 7, 2023
The repo contains the source code for all the tutorials on the FilledStacks Youtube channel.

Flutter tutorials The repo contains the source code for all the written tutorials by Filledstacks. All Tutorials plus additional snippets and shorter

Dane Mackier 4.5k Dec 31, 2022
Master Channel cannot use Glass Floating Action Button

Problem Master Channel cannot use GlassFloatingActionButton. About This package

null 7 Oct 2, 2022
Flutter tutorial - This is my first Flutter tutorial app. Thanks to The Net Ninja youtube channel for this wonderful tutorial

ninja_id A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

null 1 Jun 9, 2022
SMS Receiver Channel For Android

SMS Receiver Channel SMS Receiver Channel For Android Getting Started Use channel on the client_side (flutter) and the platform_side (android) and inv

Niloofar Amerian 2 Nov 3, 2022
Starter project for Flutter plugins willing to access native and synchronous rust code using FFI

Flutter Rust FFI Template This project is a Flutter Plugin template. It provides out-of-the box support for cross-compiling native Rust code for all a

Jør∂¡ 561 Dec 7, 2022
A Dart-native lightweight Apache Pulsar client primarily focused on the IoT telemetry domain

pulsar_iot_client A lightweight Apache Pulsar client primarily focused on the IoT telemetry domain. This project aims to improve the resulting perform

Mike Zolotarov 5 May 10, 2022
A Flutter plugin for iOS and Android allowing access to the device cameras.

Camera Plugin A Flutter plugin for iOS and Android allowing access to the device cameras. Note: This plugin is still under development, and some APIs

Rebar Ahmad 1 Mar 17, 2020