qidao123.com技术社区-IT企服评测·应用市场

标题: Flutter-->Flutter通过ffi调用Rust编译天生的产物.so文件(Android)和.a文 [打印本页]

作者: 半亩花草    时间: 2024-9-3 13:34
标题: Flutter-->Flutter通过ffi调用Rust编译天生的产物.so文件(Android)和.a文
flutter_rust_ffi

Flutter 通过ffi调用Rust编译天生的产物.so文件(Android)和.a文件(iOS)接口方法;
拾用本文您将获取以下技能:

附加Buff:

本文情况


情况预备


使用Rust编译.so

工程预备

使用Rust IDE创建一个Library的工程.

在Cargo.toml文件中设置库的类型.
[lib]的描述说明可以参考: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library


如果您还想了解更多类型可以参考: https://doc.rust-lang.org/reference/linkage.html
之后在src/lib.rs文件内里写上非常牛逼自大的高级算法.

工程预备就绪之后, 就可以着手编译了.
安装编译链

rustup target add aarch64-linux-android armv7-linux-androideabi

您可以通过rustup target list检察所有支持的工具链.
安装编译工具

cargo install cargo-ndk

编译

cargo ndk -t armeabi-v7a -t arm64-v8a build --release
关于cargo ndk更多用法可以参考: https://github.com/bbqsrc/cargo-ndk


之后将产物分别复制到Flutter工程中的android/src/main/jniLibs/arm64-v8a和android/src/main/jniLibs/armeabi-v7a这样在Android平台上,就会根据CPU的架构自动加载对应的so文件, 这一点在iOS平台上必要手动处置惩罚, 在先容iOS时, 会提及.
到这为止, Android平台的产物so文件就已经输出了. 接下来编译iOS.
使用Rust编译.a

工程预备

与上述一致.
安装编译链

rustup target add aarch64-apple-ios aarch64-apple-ios-sim

您可以通过rustup target list检察所有支持的工具链.
安装编译工具

cargo install cargo-lipo

编译

cargo lipo --targets aarch64-apple-ios --release
cargo lipo --targets aarch64-apple-ios-sim --release
这里要分开2个下令编译差别的文件.
关于cargo lipo更多用法可以参考: https://github.com/TimNN/cargo-lipo


之后将产物分别复制到Flutter工程中的ios/iphoneos(iPhone真机)和ios/iphonesimulator(iPhone模拟器).
之后在iOS工程中的xxx.podspec文件中加入:
  1. ...
  2. s.user_target_xcconfig = {
  3. 'OTHER_LDFLAGS' => '-force_load ${PODS_ROOT}/../.symlinks/plugins/flutter_rust_ffi/ios/${PLATFORM_NAME}/librust_api_test.a'
  4. }
  5. ...
复制代码

如果要区分i386或arm64架构, 可以使用${ARCHS_STANDARD_INCLUDING_64_BIT}情况变量.
之后在Flutter工程中的example/ios文件夹中使用pod install下令.
到这为止, iOS平台的产物a文件就已经输出了.
Rust导出ffi

上述天生的产物还不支持ffi调用, 以是这里阐述一下.
传统的导出ffi的方式extern fn比力繁琐, 并且不易于天生.h头文件.
参考: https://doc.rust-lang.org/nomicon/ffi.html
这里使用safer_ffi库(https://getditto.github.io/safer_ffi/)导出`ffi`
首先在Cargo.toml文件中加入safer-ffi依赖:
  1. [dependencies]
  2. safer-ffi = "0.1.12"
复制代码
并且指定特性:
  1. [features]
  2. headers = ["safer-ffi/headers"]
复制代码
其次在必要导出的方法中使用#[ffi_export]宏:
  1. #[ffi_export]
  2. pub fn test_bool(value: bool) -> bool {
  3.     !value
  4. }
复制代码
末了设置一下天生头文件名的方法generate_headers:
  1. #[test]
  2. #[cfg(feature = "headers")]
  3. fn generate_headers() -> std::io::Result<()> {
  4.     safer_ffi::headers::builder()
  5.         .to_file("rust_api_test.h")?
  6.         .generate()
  7. }
复制代码
之后就可以使用下令运行这个方法generate_headers天生对应的头文件了:
cargo test --lib generate_headers --features headers
Flutter导入ffi

   使用Flutter创建一个FFI Plugin工程, 既可以得到相应的模板代码.
  有了.h头文件, Flutter就可以借助ffigen工具创建对应的dart绑定类
dart run ffigen --config ffigen.yaml
ffigen.yaml设置文件内容, 请参考: https://pub.dev/packages/ffigen 文档. 很简单, 只必要指定对应的.h文件位置即可.
这里必要注意的是, Flutter在加载.so文件或.a文件时, 有所差异.

  1. final DynamicLibrary _dylib = () {
  2.   if (Platform.isMacOS || Platform.isIOS) {
  3.     //return DynamicLibrary.open('$_libName.framework/$_libName');
  4.     return DynamicLibrary.executable();
  5.   }
  6.   if (Platform.isAndroid || Platform.isLinux) {
  7.     return DynamicLibrary.open('lib$_libName.so');
  8.   }
  9.   if (Platform.isWindows) {
  10.     return DynamicLibrary.open('$_libName.dll');
  11.   }
  12.   throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
  13. }();
复制代码
到这里为止, Flutter就已经可以在Android平台上愉快的调用ffi了, 而不必要额外的设置.
但是, 在iOS平台上, 会有问题, 如下:

为了办理这个问题, 您必要在Xcode中举行如下设置:




   这里说明一点: -all_load和上文中的-force_load xxx.a作用是一致的,自行取其一设置即可.
  设置完成之后, rebuildFlutter在iOS平台上也可以愉快的调用ffi了.
文中源码有所省略, 文末有开源代码堆栈地点, 欢迎食用.
至此文章就结束了!

群内有各(pian)种(ni)各(jin)样(qun)的大佬,等你来撩.
接洽作者

点此QQ对话 该死的空格 点此快速加群


开源地点

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4