Flutter->`Flutter` 通过`ffi`调用`Rust`编译生成的产物.so文件(Android)和.a文件(iOS)接口方法

news2024/11/18 10:36:28

flutter_rust_ffi

Flutter 通过ffi调用Rust编译生成的产物.so文件(Android)和.a文件(iOS)接口方法;

拾用本文您将获取以下技能:

  • Rust编译.so文件的能力;
  • Rust编译.a文件的能力;
  • Flutter调用.so文件的能力;
  • Flutter调用.a文件的能力;

附加Buff:

  • Flutter环境安装指南;
  • Rust环境安装指南;
  • Android不同架构(v7a/v8a)的.so文件加载方式;
  • iOS不同设备(真机/模拟器)的.a文件加载方式;

本文环境

  • 开发电脑: Apple M3 Max
  • Flutter IDE: Android Studio Koala | 2024.1.1 Patch 2
  • iOS IDE: Xcode Version 15.4
  • Rust IDE: RustRover 2024.1.7
  • Flutter: Flutter 3.24.0 / Dart 3.5.0
  • Rust: rustc 1.80.1 / rustup 1.27.1

环境准备

  • 开发电脑: 自行解决
  • Flutter IDE: https://developer.android.com/studio
  • iOS IDE: https://developer.apple.com/cn/xcode
  • Rust IDE: https://www.jetbrains.com/zh-cn/rust/
  • Flutter: https://docs.flutter.dev/get-started/install
  • Rust: https://www.rust-lang.org/learn/get-started

使用Rust编译.so

工程准备

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

在这里插入图片描述

Cargo.toml文件中配置库的类型.

[lib]的描述说明可以参考: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library

在这里插入图片描述

  • cdylib用于输出.so
  • staticlib用于输出.a

如果您还想了解更多类型可以参考: https://doc.rust-lang.org/reference/linkage.html

之后在src/lib.rs文件里面写上非常牛逼自信的高级算法.

在这里插入图片描述

工程准备就绪之后, 就可以着手编译了.

安装编译链

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

  • aarch64-linux-android 用于输出arm64-v8a的.so文件
  • armv7-linux-androideabi 用于输出armeabi-v7a的.so文件

您可以通过rustup target list查看所有支持的工具链.

安装编译工具

cargo install cargo-ndk

  • cargo-ndk 用来编译so文件

编译

cargo ndk -t armeabi-v7a -t arm64-v8a build --release

关于cargo ndk更多用法可以参考: https://github.com/bbqsrc/cargo-ndk

  • arm64-v8a平台的so文件输出在target/aarch64-linux-android/release/xxx.so
  • armeabi-v7a平台的so文件输出在target/armv7-linux-androideabi/release/xxx.so

在这里插入图片描述

之后将产物分别复制到Flutter工程中的android/src/main/jniLibs/arm64-v8aandroid/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

  • aaarch64-apple-ios 用于输出iPhone真机的.a文件
  • aarch64-apple-ios-sim 用于输出iPhone模拟器的.a文件

您可以通过rustup target list查看所有支持的工具链.

安装编译工具

cargo install cargo-lipo

  • cargo-lipo 用来编译.a文件

编译

cargo lipo --targets aarch64-apple-ios --release
cargo lipo --targets aarch64-apple-ios-sim --release

这里要分开2个命令编译不同的文件.

关于cargo lipo更多用法可以参考: https://github.com/TimNN/cargo-lipo

  • iPhone真机的a文件输出在target/aarch64-apple-ios/release/xxx.a
  • iPhone模拟器的a文件输出在target/aarch64-apple-ios-sim/release/xxx.a

在这里插入图片描述

之后将产物分别复制到Flutter工程中的ios/iphoneos(iPhone真机)和ios/iphonesimulator(iPhone模拟器).

之后在iOS工程中的xxx.podspec文件中加入:

...
s.user_target_xcconfig = {
'OTHER_LDFLAGS' => '-force_load ${PODS_ROOT}/../.symlinks/plugins/flutter_rust_ffi/ios/${PLATFORM_NAME}/librust_api_test.a'
}
...
  • ${PLATFORM_NAME}是用来自动加载iPhone真机iPhone模拟器的关键.

如果要区分i386arm64架构, 可以使用${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依赖:

[dependencies]
safer-ffi = "0.1.12"

并且指定特性:

[features]
headers = ["safer-ffi/headers"]

其次在需要导出的方法中使用#[ffi_export]宏:

#[ffi_export]
pub fn test_bool(value: bool) -> bool {
    !value
}

最后配置一下生成头文件名的方法generate_headers:

#[test]
#[cfg(feature = "headers")]
fn generate_headers() -> std::io::Result<()> {
    safer_ffi::headers::builder()
        .to_file("rust_api_test.h")?
        .generate()
}

之后就可以使用命令运行这个方法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文件时, 有所差异.

  • 加载.so文件直接使用默认的DynamicLibrary.open('lib$_libName.so');方法即可.
  • 但是加载.a文件则需要使用DynamicLibrary.executable();方法.
final DynamicLibrary _dylib = () {
  if (Platform.isMacOS || Platform.isIOS) {
    //return DynamicLibrary.open('$_libName.framework/$_libName');
    return DynamicLibrary.executable();
  }
  if (Platform.isAndroid || Platform.isLinux) {
    return DynamicLibrary.open('lib$_libName.so');
  }
  if (Platform.isWindows) {
    return DynamicLibrary.open('$_libName.dll');
  }
  throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}();

到这里为止, Flutter就已经可以在Android平台上愉快的调用ffi了, 而不需要额外的配置.

但是, 在iOS平台上, 会有问题, 如下:

  • IOS Failed to lookup symbol (dlsym(RTLD_DEFAULT, test_func): symbol not found)

为了解决这个问题, 您需要在Xcode中进行如下配置:

  • 导航到TARGETS->Runner->Build Settings->Linking - GeneralDead Code Stripping配置改成No(这是iOS移除未使用的代码用的)

在这里插入图片描述

  • 在同级的Ohter Linker Flags中加入-all_load(这是加载所有符号表用的)

在这里插入图片描述

这里说明一点: -all_load和上文中的-force_load xxx.a作用是一致的,自行取其一配置即可.

配置完成之后, rebuildFlutter在iOS平台上也可以愉快的调用ffi了.

文中源码有所省略, 文末有开源代码仓库地址, 欢迎食用.

至此文章就结束了!


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

联系作者

点此QQ对话 该死的空格 点此快速加群
在这里插入图片描述

在这里插入图片描述

开源地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2066163.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

游戏行业如此竞争激烈,个人开发者是否仍存机会?

在当今这个数字化时代&#xff0c;游戏行业以其庞大的市场规模、高速的增长速度以及无限的创意空间&#xff0c;吸引了无数开发者投身其中。然而&#xff0c;随着技术的进步、资本的涌入以及大型游戏公司的强势扩张&#xff0c;游戏行业的竞争日益激烈&#xff0c;似乎形成了一…

选择合适系统

选择合适系统 原厂SDK系统 硬件兼容性 ⭐⭐⭐⭐⭐软件功能完善度 ⭐⭐⭐⭐⭐开发使用难度 ⭐⭐⭐⭐⭐烧写工具 全志自家烧录器。 TinaSDK-4.0 TF卡系统镜像 tina_v851se-tinyvision_uart0.img 默认TinaSDK编译出来 支持ADB 和默认SDK兼容性最好 tina-4.0_cameratest_ti…

使用知识图谱,大幅提升RAG准确性

大家好&#xff0c;图形检索—增强生成&#xff08;GraphRAG&#xff09;的发展势头日益强劲&#xff0c;已成为传统向量搜索检索方法的有力补充。这种方法利用图数据库的结构化特性&#xff0c;将数据组织为节点和关系&#xff0c;从而增强了检索信息的深度和上下文关联性。 知…

Stablediffusion有哪几种模型,小白入门必看!

前言 在Stable Diffusion中&#xff0c;模型有好几种&#xff0c;不同插件有不同的模型&#xff0c;分别作用于不同的功能。 今天卧龙君就带着大家一起来了解一下。 大模型&#xff1a;Stable Diffusion StableDiffusion大模型&#xff0c;可以理解为绘画风格集合&#xff…

16:【stm32】I2C的使用一:I2C片上外设的使用

I2C 1、片上外设1.1&#xff1a;寄存器与内部结构 2、通过I2C向外发送数据2.1&#xff1a;I2C的初始化2.1.1&#xff1a;初始化SCL和SDA2.1.2&#xff1a;使能时钟PCLK1&#xff08;APB1&#xff09;2.1.3&#xff1a;配置I2C1的参数 2.2&#xff1a;发送数据2.2.1&#xff1a;…

P2P 文件共享:现代网络中的高效文件传输

在互联网的世界中&#xff0c;不同应用程序的数据传输方法各异。P2P文件共享&#xff08;Peer-to-Peer File Sharing&#xff09; 作为一种高效的文件传输方式&#xff0c;使得用户可以在没有中央服务器的情况下直接进行文件交换。本文将详细介绍P2P文件共享的基本原理、优势及…

【通俗理解】CNN复杂度——卷积神经网络的计算成本解析

【通俗理解】CNN复杂度——卷积神经网络的计算成本解析 关键词提炼 #CNN复杂度 #卷积神经网络 #计算成本 #输入数据尺寸 #卷积核大小 #卷积核数量 #复杂度公式 第一节&#xff1a;CNN复杂度的类比与核心概念【尽可能通俗】 1.1 CNN复杂度的类比 CNN的复杂度就像是烹饪一道大…

引擎切换pdf识别简历分析

文章目录 1.EasyCode生成interview_history的crud1.在模板设置中手动指定逻辑删除的值2.生成代码&#xff0c;进行测试 2.PDF识别关键字1.引入依赖2.代码概览3.PDFUtil.java4.keyword1.EndType.java2.FlagIndex.java3.WordType.java4.KeyWordUtil.java 3.策略模式实现引擎切换&…

QT-window记事本

QT-window记事本 一、演示效果二、核心代码三、下载连接 一、演示效果 二、核心代码 #include <QMessageBox> #include <QFileDialog> #include <QDebug> #include <QProcess> #include <QDesktopServices> #include <QDateTime> #includ…

孙宇晨:区块链领域的坚韧领航者,以智慧铸就行业基石

​ 在区块链领域&#xff0c;孙宇晨以其卓越的智慧与不懈的韧性&#xff0c;成为行业内备受瞩目的领军人物。从创立波场 TRON 到引领去中心化的变革&#xff0c;孙宇晨始终以坚定的信念和独特的战略眼光推动着区块链技术的发展。 孙宇晨的成功不仅仅是因为他对技术的深入…

叉车驾驶员状态监控系统,司机身份安全识别,强化监管能力建设!

人脸识别技术作为人工智能领域的一个重要分支&#xff0c;已经广泛应用于安全识别、个人化推荐、社交网络等多个领域。其基于计算机视觉、图像处理、人脸检测、特征提取和人脸识别等先进技术&#xff0c;能够实现对人脸图像的精准分析和识别。在叉车驾驶场景中&#xff0c;AI人…

windows mfc webview2 接收html信息

webview2导入到mfc参考&#xff1a; windows vs2022 MFC使用webview2嵌入网页-CSDN博客 webview2与js交互参考&#xff1a;WebView2教程(基于C)【四】JS与C互访&#xff08;上&#xff09;_window.chrome.webview.postmessage-CSDN博客 一、JS端发送和接收 JS中&#xff0c;…

12代装win7影响性能吗?12代酷睿装win7关闭小核提高性能方法

12代酷睿装win7影响性能吗&#xff1f;12代酷睿装win7在性能上有点损耗&#xff0c;可以关闭小核提高性能。有些小朋友不知道怎么关闭上核来提高性能&#xff0c;下面电脑系统城小编就教大家12代酷睿装win7关闭核提高性能方法。 12代酷睿装win7说明&#xff1a;关闭小核解锁更多…

【分布式】分布式Session共享

这里通过SpringSession来实现Session的共享&#xff0c;Session数据存储在Redis中 SpringSession的操作指南&#xff1a; https://docs.spring.io/spring-session/docs/2.5.6/reference/html5/guides/boot-redis.html 导入相关的依赖 <dependency><groupId>org.s…

算法入门-递归3

第四部分&#xff1a;递归 143.重排链表&#xff08;中等&#xff09; 题目&#xff1a;给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → …

问题-小技巧-win11状态栏卡住

目前我只知道治标不治本的办法&#xff0c;打开任务管理器&#xff0c;找到Windows资源管理器右键重新启动&#xff0c;就可以解决这个问题。 这个问题我觉得是Win11自己的问题&#xff0c;等有新的发现&#xff0c;会进行补充。

使用Hutool工具类轻松生成验证码

效果图&#xff1a; 引入依赖&#xff1a; <!--hutool工具包--> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.15</version> </dependency>核心代码 import cn.hutool.…

使用docker-compose运行kafka及验证(无需zookpeer)

前言&#xff1a;要求安装docker-compose kafka镜像版本&#xff1a;apache/kafka:3.8.0 可能存在镜像拉不下来的情况&#xff1a; 1、vim /etc/docker/daemon.json {"data-root":"/data/docker","registry-mirrors": ["https://docker.m…

高性价比百元蓝牙耳机如何选择?四款首选高性价比蓝牙耳机推荐

不知道什么时候开始&#xff0c;有线耳机悄悄的淡出了我们的视线。现在几乎都是蓝牙耳机首当前冲&#xff0c;因为比起有线耳机&#xff0c;蓝牙耳机更携带方便&#xff0c;拿出来就是秒连&#xff0c;体验感也不差。而且随着蓝牙耳机的价格不断下降&#xff0c;同时&#xff0…

【图文并茂】ant design pro 如何优雅奇妙地添加修改密码的功能

如上图所示&#xff0c;我们要加这样的一个功能&#xff0c;如何做呢&#xff1f; 首先要写好前端页面&#xff0c;再对接好后端&#xff0c;然后我们要判断当前密码是否正确&#xff0c;如果正确才能新密码修改好。 前端页面 src/pages/account/change-password/index.tsx …