赞
踩
使用Rust一处编写,横跨中Android & IOS 多端场景使用,相比较 React Native 方案更加高效。并且Rust是一门系统级编程,Rust编写也可以在其它场景下复用。
本文主要介绍了Flutter 集成Rust,所以并不会在Flutter、Rust等开发环境搭建以及Dart、Rust语言上做介绍。
考虑Android & IOS 同时使用,所以本文使用MacOS系统作为演示,如仅仅需做安卓上测试可跳过相关IOS的配置等操作。
rustc 1.61.0 (fe5b13d68 2022-05-18)
cargo 1.61.0 (a028ae42f 2022-04-29)
可通过 Android Studio 安装 NDK 版本 22.1.7171670
测过着23版本之后cargo 构建编译会出问题
此处使用VSCode编辑器编辑
ANDROID_NDK_HOME 指定 NDK 安装目录
code ~/.zshrc
export ANDROID_NDK_HOME=/Users/username/Library/Android/sdk/ndk/22.1.7171670
source ~/.zshrc
mkdir ~/.NDK
python3 $ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --api 21 --arch arm64 --install-dir ~/.NDK/arm64
python3 $ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --api 16 --arch arm --install-dir ~/.NDK/arm
python3 $ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --api 16 --arch x86 --install-dir ~/.NDK/x86
code ~/.cargo/config
[target.aarch64-linux-android]
ar = ".NDK/arm64/bin/aarch64-linux-android-ar"
linker = ".NDK/arm64/bin/aarch64-linux-android-clang"
[target.armv7-linux-androideabi]
ar = ".NDK/arm/bin/arm-linux-androideabi-ar"
linker = ".NDK/arm/bin/arm-linux-androideabi-clang"
[target.i686-linux-android]
ar = ".NDK/x86/bin/i686-linux-android-ar"
linker = ".NDK/x86/bin/i686-linux-android-clang"
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android
rustup target add aarch64-apple-ios x86_64-apple-ios
cargo install cargo-lipo
cargo init my-app-base --lib
使用任意编辑器打开项目,编辑src中lib.rs文件,添加如下代码,其中定义了一个hello输出world字符以及count_add_self每次调用加2
use std::os::raw::c_char; use std::ffi::CString; static mut COUNT: u32 = 0; #[no_mangle] pub unsafe extern "C" fn count_add_self() -> u32 { COUNT += 2; COUNT } #[no_mangle] pub unsafe extern fn hello() -> *const c_char { let s = CString::new("world").unwrap(); s.into_raw() }
修改 Cargo.toml 文件增加如下内容
Rust 构建出来的二进制库
在 IOS 中是静态链接进最终的程序之中,需要对构建staticlib
的支持
在 Android 是通过动态链接在运行时装在进程序运行空间的,需要对构建cdylib
的支持
[lib]
name = "hello_lib"
crate-type = ["staticlib", "cdylib"]
# IOS
cargo lipo --release
# Android
cargo build --target aarch64-linux-android --release
cargo build --target armv7-linux-androideabi --release
cargo build --target i686-linux-android --release
使用Android Studio、VSCode或者终端创建一个Flutter项目
在Flutter项目ios目录下新建Framework文件夹
将Rust项目中target/universal/release/libhello_lib.a 复制到 Framework 文件夹
在 ios 目录上右键使用 xcode 打开项目
在 Build Phases 中 Link Binary With Libraries 添加 Framework文件夹中 libhello_lib.a 文件
在 Build Settings 中 Other Linker Flags 中添加 -all_load 的参数
在 Build Settings 中 Architectures 中 Excluded Architectures 添加 arm64 的参数,默认应该有一个 i386 因为Rust编译后的是 arm64 架构
在Flutter项目android/app/src/main目录下新建jniLibs目录,并在新建 arm64-v8a 、 armeabi-v7a 、x86 三个文件夹
将 Rust 项目编译后 target 项目下对应架构so文件复制到 对应 架构文件夹下
在flutter项目pubspec.yaml中添加FFI
ffi: ^2.0.0
在 main.dart 中修改后
import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'dart:io'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { String? hello; int count = 0; void _incrementCounter() { setState(() { countAdd(); }); } @override void initState() { super.initState(); final dylib = Platform.isAndroid ? DynamicLibrary.open('libhello_lib.so') :DynamicLibrary.process(); var result = dylib.lookupFunction<Pointer<Utf8> Function(),Pointer<Utf8> Function()>('hello'); hello = result().toDartString(); } void countAdd() { final dylib = Platform.isAndroid ? DynamicLibrary.open('libhello_lib.so') :DynamicLibrary.process(); var countAddSelf = dylib.lookupFunction<Pointer<Uint32> Function(),Pointer<Uint32> Function()>('count_add_self'); count = countAddSelf().address; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( '以下内容为Rust侧结果', ), Text('$hello'), Text('$count'), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。