As next week will have importat launch for Rust 2018 and Flutter 1.0, I thought to build an app using Rust for the business logic and Flutter for the user interface, that can run at both Android and iOS, I built one and tested it at Android and it is working fine.
I just wonder how to measure the performance and compare it with native Android/iOS app.
The app flow is:
The structure is as below:
The code used is:
main.dart
:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const platform = const MethodChannel('samples.flutter.io/battery');
String _batteryLevel = 'Unknown battery level.';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final String hello = await platform.invokeMethod('getText');
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = '$hello Battery level at $result %.';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RaisedButton(
child: Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel),
],
),
),
);
}
}
JNI wrapper - RustGreetings.kt
package com.mozilla.greetings
class RustGreetings {
companion object {
init {
System.loadLibrary("greetings")
}
}
private external fun greeting(pattern: String): String
fun sayHello(to: String): String = greeting(to)
}
And the Main Android activity is:
package com.example.batterylevel
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugin.common.MethodChannel
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import lib.Library
import com.mozilla.greetings.RustGreetings
class MainActivity: FlutterActivity() {
private val CHANNEL = "samples.flutter.io/battery"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getText") {
result.success(getText())
} else if (call.method == "getBatteryLevel") {
// result.success(getText())
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
}
else {
result.notImplemented()
}
}
}
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
private fun getText(): String {
val x = Library().someLibraryMethod()
val g = RustGreetings()
val r = g.sayHello("My $x Rust")
return r
}
}
In the Android gradle.build
I just added the below, as I'm interested to check also the impact of adding kotlin JVM library and getting it interacted with the Rust library within the mobile application:
dependencies {
implementation(files("src/main/libs/lib.jar"))
}
My question is: How can check the performance and impact of each process when it is executed or called by another process
You can also read this post while taking a look at the associated GitHub repository. Let’s start by creating a folder called rust-for-android-ios-flutter and create four folders in it ( android, ios, flutter & rust ): Once we have it, just cd into the rust folder and create a new Rust library called rustylib:
Now our native Android and Flutter Project is successfully integrated. Flutter provides FlutterActivity inside the android app that simulates the flutter experience. We need to register flutter activity in AndroidManifest.xml. First, we add Activity. Main.
Open the flutter/ios/Classes/RustyFlutterLibPlugin.swift file and add the following code: Open the flutter/lib/rusty_flutter_lib.dart file and add a new static method in the RustyFlutterLib class: Let’s open the flutter/example/lib/main.dart file with your IDE of choice and let’s consume our recently created Flutter package:
The biggest challenge is to build a proper bridge between Rust and client frameworks, if you can live with it — it could be a great solution for mobile. My previous investigation: Go + Gomobile for Android and IOS.
With the introduction of ffi in Dart, things became more smoother now, with a better performance as the interction now is Dart/Rust directly, without a need for Dart/Kotlin/Rust or Dart/Swift/Rust cycle, below a simple example:
First src/lib.rs
#[no_mangle]
pub extern fn rust_fn(x: i32) -> i32 {
println!("Hello from rust\nI'll return: {}", x.pow(2));
x.pow(2)
}
and Cargo.toml
[package]
name = "Double_in_Rost"
version = "0.1.0"
authors = ["Hasan Yousef"]
edition = "2018"
[lib]
name = "rust_lib"
crate-type = ["dylib"] # could be `staticlib` as well
[dependencies]
Running cargo build --release
will generate target\release\rust_lib.dll
copy/paste it into Dart application root directory
Write Dart code as below:
import 'dart:ffi';
import 'dart:io' show Platform;
// FFI signature of the hello_world C function
typedef ffi_func = Int32 Function(Int32 x); //pub extern fn rust_fn(x: i32) -> i32
// Dart type definition for calling the C foreign function
typedef dart_func = int Function(int x);
void main() {
// Open the dynamic library
var path = './rust_lib.so';
if (Platform.isMacOS) path = './rust_lib.dylib';
if (Platform.isWindows) path = 'rust_lib.dll';
final dylib = DynamicLibrary.open(path);
// Look up the Rust/C function
final my_func =
dylib.lookup<NativeFunction<ffi_func>>('rust_fn').asFunction<dart_func>();
print('Double of 3 is ${my_func(3)}');
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With