Dart FFI的简单分析

Flutter 直接调用so动态库,或调用C/C++源文件内函数 我把 .so 文件尝试放过好几个目录/lib/,最终都会报这个错误,现在才知道库文件需要放在你根本想象不到的地方!!!尝试了一些方法还是不行后我放弃了 ffi,想着用 Flutter 的 MethodChannel 桥接 android/ios 原生,再让原生去调 native 层。一顿操作把Android端的搞定了,当然中间涉及到 Kotlin和C++ 层的数据类型映射的痛苦,而且业务函数也不像一个 helloworld 那么简单,别提有多痛苦了。 阅读详情

本文是阅读dart ffi相关的代码记录。

源码的位置

分成几个部分,dart的代码在sdk/lib/ffi下,有4个文件

  • annotations.dart
  • dynamic_library.dart : 定义DynamicLibrary类,用于加载so库
  • ffi.dart 定义Pointer类
  • native_type.dart 定义NativeType

Pointer相关的实际实现的代码,
在runtime/lib/ffi_path.dart, 定义的对应的native实现,关键的如

  • Pointer.asFunction对应 Ffi_asFunction
  • fromFunction 对应Ffi_fromFunction
  • 等等

runtime/lib/ffi_dynamic_library_patch.dart定义DynamicLibrary的实现

  • DynamicLibrary._open对应 Ffi_dl_open
  • DynamicLibrary.lookup 对应 Ffi_dl_lookup
  • 等等

对应的c++类
runtime/lib/ffi_dynamic_library.cc 实现open, loopkup等函数
runtime/lib/ffi.cc 实现fromFunction, asFunction等函数

lookup取得函数指针

dart的用法

import 'dart:ffi' as ffi;
import 'dart:io' show Platform;

// FFI signature of the hello_world C function
typedef hello_world_func = ffi.Void Function();
// Dart type definition for calling the C foreign function
typedef HelloWorld = void Function();

main() {
  // Open the dynamic library
  var path = "./hello_library/libhello.so";
  if (Platform.isMacOS) path = './hello_library/libhello.dylib';
  if (Platform.isWindows) path = r'hello_library\Debug\hello.dll';
  final dylib = ffi.DynamicLibrary.open(path);
  // Look up the C function 'hello_world'
  final HelloWorld hello = dylib
      .lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
      .asFunction();
  // Call the function
  hello();
DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) {
  // 取得type_args, 指 lookup的模板参数0:上面的例子ffi.NativeFunction<hello_world_func>>
  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
  // 对象指针,即this指针:DynamicLibrary实现
  GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0));
  //函数名
  GET_NON_NULL_NATIVE_ARGUMENT(String, argSymbolName,
                               arguments->NativeArgAt(1));

  void* handle = dlib.GetHandle();
  // 调用dlsysm获得函数值
  const intptr_t pointer = reinterpret_cast<intptr_t>(
      ResolveSymbol(handle, argSymbolName.ToCString()));

  // TODO(dacoharkes): should this return Object::null() if address is 0?
  // https://github.com/dart-lang/sdk/issues/35756
  // 创建一个native指针,使用int类型保存
  // type_arg确定参数类型,pointer保存地址
  RawPointer* result =
      Pointer::New(type_arg, Integer::Handle(zone, Integer::New(pointer)));
  // result对应dart中的ffi.NativeFunction<hello_world_func>类型
  return result;
}

asFunction的实现

DEFINE_NATIVE_ENTRY(Ffi_asFunction, 1, 1) {
  //获得 Pointer对象,如上面的例子ffi.NativeFunction<hello_world_func>
  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
  AbstractType& pointer_type_arg = // 获得类型信息
      AbstractType::Handle(pointer.type_argument());
  ASSERT(IsNativeFunction(pointer_type_arg));
  // 获得asFunction的模板参数
  // asFunction的声明: external R asFunction<@DartRepresentationOf("T") R extends Function>(); 获取其中的R类型,上面的例子 HelloWorld类型
  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
  ASSERT(DartAndCTypeCorrespond(pointer_type_arg, type_arg));

  // dart_signature 获得R的签名,上面例子 HelloWorld类型
  Function& dart_signature = Function::Handle(Type::Cast(type_arg).signature());
  // Pointer类的类型参数,即NativeType的类型
  TypeArguments& nativefunction_type_args =
      TypeArguments::Handle(pointer_type_arg.arguments());
  AbstractType& nativefunction_type_arg =
      AbstractType::Handle(nativefunction_type_args.TypeAt(0));
  Function& c_signature =
      Function::Handle(Type::Cast(nativefunction_type_arg).signature());
  //  生成内部函数接口,TrampolineFunction创建一个跳板函数对象,参数从dart_signature转换为c_signature
  Function& function =
      Function::Handle(TrampolineFunction(dart_signature, c_signature));

  // Set the c function pointer in the context of the closure rather than in
  // the function so that we can reuse the function for each c function with
  // the same signature.
  // C函数指针包装在context中
  Context& context = Context::Handle(Context::New(1));
  context.SetAt(0, Integer::Handle(zone, pointer.GetCMemoryAddress()));

  // 包装成Function类,在dart中可以直接调用
  RawClosure* raw_closure =
      Closure::New(Object::null_type_arguments(), Object::null_type_arguments(),
                   function, context, Heap::kOld);

  return raw_closure;
}

TrampolineFunction

指定RawFunction::kFfiTrampoline类型,专门用于ffi调用

// TODO(dacoharkes): Cache the trampolines.
// We can possibly address simultaniously with 'precaching' in AOT.
static RawFunction* TrampolineFunction(const Function& dart_signature,
                                       const Function& c_signature) {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();
  String& name =
      String::ZoneHandle(Symbols::New(Thread::Current(), "FfiTrampoline"));
  const Library& lib = Library::Handle(Library::FfiLibrary());
  const Class& owner_class = Class::Handle(lib.toplevel_class());
  Function& function =
      Function::Handle(zone, Function::New(name, RawFunction::kFfiTrampoline,
                                           /*is_static=*/true,
                                           /*is_const=*/false,
                                           /*is_abstract=*/false,
                                           /*is_external=*/false,
                                           /*is_native=*/false, owner_class,
                                           TokenPosition::kMinSource));
  function.set_is_debuggable(false);
  function.set_num_fixed_parameters(dart_signature.num_fixed_parameters());
  function.set_result_type(AbstractType::Handle(dart_signature.result_type()));
  function.set_parameter_types(Array::Handle(dart_signature.parameter_types()));

  // The signature function won't have any names for the parameters. We need to
  // assign unique names for scope building and error messages.
  const intptr_t num_params = dart_signature.num_fixed_parameters();
  const Array& parameter_names = Array::Handle(Array::New(num_params));
  for (intptr_t i = 0; i < num_params; ++i) {
    if (i == 0) {
      name = Symbols::ClosureParameter().raw();
    } else {
      name = Symbols::NewFormatted(thread, ":ffiParam%" Pd, i);
    }
    parameter_names.SetAt(i, name);
  }
  function.set_parameter_names(parameter_names);
  function.SetFfiCSignature(c_signature);

  return function.raw();
}
Flutter协程与FFI的Native代码调用 如何安全高效地在Dart中调用Native代码如何利用协程简化异步Native调用的复杂性FFI与平台通道(Platform Channel)的性能对比跨平台Native调用的最佳实践文章首先介绍Dart的异步模型和协程基础,然后深入FFI的工作原理,接着通过实际案例展示集成方案,最后讨论性能优化和未来发展方向。: 允许一种编程语言调用另一种编程语言函数的机制协程(Coroutine): 可暂停和恢复执行的轻量级线程,不依赖操作系统调度Isolate。 阅读详情

相关推荐

通义万相Wan2.1模型Lora训练以及推理

使用DiffSynth-Studio进行通义万象Wan2.1的Lora训练和推理

qq_64858624的博客 4604

Dart中FFI学习

Dart中如何与C语言交互

yong_19930826的博客 1725

为什么你的Nginx配置SM2国密SSL证书失败?这些坑我都帮你踩过了

本文针对Nginx配置SM2国密SSL证书的常见失败原因,提供了详细的排查与解决方案。核心在于使用支持国密算法的Nginx版本(如集成Tongsuo库),正确处理从阿里云等平台获取的证书格式,并正确配置ssl_ciphers等关键参数。文章还解释了浏览器兼容性差异及双证书部署等进阶场景,帮助运维和开发人员高效完成国密合规改造。

weixin_29228203的博客 387

跨语言通信——dart::ffi

ffi是一个比一般通信更底层的机制,接近于jni或者jsi。主要用来做dart和c++的interop。 方法定义和绑定 dart call c++ 官方demo是: import 'dart:ffi'; // For FFI import 'dart:io'; // For Platform.isX final DynamicLibrary nativeAddLib = Platform.isAndroid ? DynamicLibrary.open("libnative_add.so")

pouloghost的专栏 2117

NXP(imx8qxp)系列DDR校准以及android镜像烧录

文章目录一、 不得不吐槽以下nxp的这个代码镜像烧写的过程,做得太开源了,导致镜像根本烧录不进去,实属令人头痛。 一、

永不秃头的程序员的博客 5991

大模型越狱指令数据集全解析:从AdvBench到HarmBench

本文全面解析了AdvBench、HarmBench等主流大模型越狱指令数据集。AdvBench作为基础测试集,用于快速评估模型安全基线;HarmBench则以其全面的文本、多模态及对抗性攻击评估,成为当前权威的深度安全审计工具。文章还介绍了MaliciousInstruct、JailbreakBench等特色数据集,并提供了根据实际场景选择与使用这些数据集的具体实战指南。

weixin_29327525的博客 619

Dart FFi

FFI: 全称Foregin Function Interface,外部函数接口,是dart sdk的一个新的语言特性,提供了一套动态库加载器,能直接查找内存中已有的函数符号,也支持将指定路径的库加加载到内存中.通在dart侧持有这个库的文件句柄,利用dart暴露的方法查找对应的native方法返回给dart调用,从而提交与native通信的效率,相比较JNI和iOS的混编,它为开发者提供了一套额外的技术方案.实例代码可以参考 https://dart.dev/guides/libraries/c-inte

jiodg45的博客 1238

UG NX二次开发(C#)--详细讲述编程模板NXOpen_CS_Wizard的代码意义,帮你轻松进入NXOpen(C#)二次开发

有几个读者私信问我,在看了“NX1957在VS2019上二次开发的环境配置”后,能完成了UG NX二次开发(C#)模板的配置,也能根据模板创建工程,但是对工程文件.cs不甚理解;并且,在UG Styler新建完成后,其也有一个dlx文件和.cs文件,也不清楚怎么使用。本文先对UG NX二次开发(C#)模板文件进行讲解,在下一个博客中,讲解Styler新建后的模板文件。以上就是对编程模板NXOpen_CS_Wizard(c#)的讲解,其实只要明白了逻辑关系,编程实现只是时间问题,祝你好运。

GimiGimmy 1786

在Dart中使用FFI调用Rust函数

什么是FFI 外部函数接口 (FFI) 是一种机制,通过该机制,以一种编程语言编写的程序可以调用以另一种编程语言编写的服务。当你需要额外的速度🚀或需要使用其他语言的库时,应用FFI会很方便。 为什么需要FFI Dart是Flutter底层的语言,Dart引入FFI机制很大程度上是为了帮Flutter在桌面开发领域铺路。 假设你像我一样是一个懒惰的程序员,并且你现在需要一个库来在你的计算机上播放音乐/音频。不幸的是,Flutter/Dart 中不存在这样的东西,因为它是一个相对年轻的生态系统(语言实际上并不那

whuhewei的博客 4798

【OpenClaw从入门到精通】第07篇:2026实测!零基础开发OpenClaw自定义Skill——招聘外呼自动邀约完整教程

本文聚焦OpenClaw自定义Skill开发全流程,针对现成技能无法满足个性化场景(如专属招聘流程、内部系统对接)的痛点,以“招聘外呼自动邀约”为实战案例,从概念认知、环境搭建、分步开发到测试优化,手把手教读者从零构建自定义Skill。内容涵盖Skill目录结构、SKILL.md核心配置、Python主逻辑实现、API对接、安全配置等关键环节,融入2026年ClawHavoc事件安全警示,强调最小权限、凭证安全等开发原则。所有代码经实测可运行,步骤详尽且兼顾新手友好与进阶需求。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1193

虚拟化 之三 详解 ARM 平台 jailhouse 的移植适配、构建及使用(飞腾派)

本文将探索学习通过在飞腾官方提供的 Buildroot 构建系统移植适配 openEuler 内核以及 jailhouse 源码 Package 进而直接构建一个适用于飞腾派开发板的带有 jailhouse 的 openEuler 发行版。

技术干货 1004

DevTools Network Profiler 的 FFI Hook:拦截 Dart `HttpClient` 的原生调用

本次讲座我们深入探讨了如何利用 Dart FFI 和操作系统动态链接特性,为 DevTools 网络分析器构建一个能够拦截 DartHttpClient原生调用的 Hook。从理解HttpClient的原生边界,到 FFI 的核心概念,再到 C 垫片库的实现、Dart 侧的集成以及数据传输机制,我们详细阐述了这一复杂而强大的技术方案。尽管存在性能和安全性考量,FFI Hook 仍然为深度诊断和性能优化提供了无与伦比的洞察力,极大地扩展了 Dart 应用程序的可观测性。

weixin_41455464的博客 1006

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的体育赛事目标检测系统(Python+PySide6界面+训练代码)

本文详细介绍了一个基于YOLOv5/v6/v7/v8的体育赛事目标检测系统的设计与实现。系统采用先进的深度学习算法,结合PySide6图形界面,实现了对体育赛事中运动员、球类、裁判等多种目标的实时检测与跟踪。本文将全面阐述系统的架构设计、算法原理、训练流程、界面实现以及实际应用效果,并提供完整的代码实现。

YOLO 509

POSIX 线程与 Dart Isolate:在 FFI 中创建原生线程的上下文管理

POSIX 线程 (pthreads) 是一个定义在 POSIX 标准(例如 IEEE Std 1003.1)中的线程 API。它提供了一组函数,用于创建、管理和同步线程。pthreads 在 Unix-like 系统(如 Linux、macOS)和一些其他平台上广泛使用。

weixin_41455464的博客 737

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Flutter 与 Dart 的市场应用

Dart 为什么选择 Flutter ,通过 isoalte、ffi 等方向介绍了 Dart 对于 Flutter 的配合与支持接着我们介绍过了 Flutter 的优劣,通过市场占有和热度展示了 Flutter 的优势,通过一些特殊场景展示了 Flutter 的不足最后我们通过 Widget、BuildContext、Flutter Web、动画等角度介绍了 Flutter 里一些比较重要的内容,帮助大家从各个角度更好地去理解 Flutter。

恋猫de小郭的博客 2089

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

终极Rust FFI开发利器:Diplomat的5大核心特性与优势

Diplomat是一款强大的Rust工具,专为生成FFI(Foreign Function Interface)定义而设计,能够让多种其他编程语言轻松调用Rust代码。作为Rust FFI开发的终极解决方案,Diplomat凭借其高效、安全和跨语言的特性,成为连接Rust与其他语言的桥梁。 ## 1. 多语言支持:无缝连接Rust与主流编程语言 Diplomat支持多种主流编程语言,包括C、C

gitblog_00752的博客 845

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Flutter 三方库 h3_dart 的鸿蒙化适配指南 - 全球六边形网格索引、支持高精度地理分析、助力鸿蒙端位置大数据应用

在处理海量地理位置数据时,如何进行高效的聚合运算是一个巨大的挑战。Uber 开源的 H3 网格系统是目前的行业标准。通过h3_dart库,Flutter 开发者可以在不牺牲性能的前提下,在 OpenHarmony 平台上实现复杂的空间索引。本文将详细讲解该库的适配要点,手把手教你如何利用六边形网格优化鸿蒙端的位置大数据分析。H3 将全球地表划分为多层级的六边形网格。相比传统的正方形网格,六边形到相邻网格中心的距离是相等的,这为地理围栏和路径分析带来了更高的精度。graph TD。

大山哥 1017

Dart VM Heap Fragmentation:外部内存(如图像)对 GC 压力与碎片化的影响

内部碎片(Internal Fragmentation): 当分配的内存块比实际需要的大,导致内存块内部有未使用的空间。例如,一个分配器总是分配固定大小的块,即使你只需要其中一小部分。Dart VM通常通过精确分配和对象头来最小化内部碎片。外部碎片(External Fragmentation): 这是我们关注的重点。当总的空闲内存量足够满足一个分配请求,但这些空闲内存分散成许多不连续的小块,以至于没有任何一个单独的空闲块能够满足请求时,就发生了外部碎片。

weixin_41455464的博客 671

Dart 3.2 更新盘点

作者 / Kevin Moore 和 Michael Thomsen我们隆重宣布推出 Dart 3.2,这一版本针对以下方面做出了改进: 新增了一项语言功能,可对私有 final 字段进行非空升级;通过新增的互操作功能改善了开发者体验;支持 DevTools 的扩展程序;并更新了我们的 Web 路线图,包括提供对 Wasm (又名 WebAssembly) 的支持。私有 final 字段的非空升级...

谷歌开发者 1255

Flutter 三方库 libserialport 的鸿蒙化适配指南 - 让工业通讯回归“物理层直连”,打造鸿蒙应用专家级的串口交互与物联网硬件治理中台

在鸿蒙(OpenHarmony)应用进军专业工业自动化、医疗仪器监控或边缘计算网关的进程中,如何实现对物理串口(Serial Port,如 RS-232/RS-485)的底层驱动与数据泵送?如何在大规模波特率变换与流式报文解析中保持毫秒级的交互抖动?是一款专为 Dart 设计的工业级串口库(基于 C 语言 libserialport 的 FFI 封装)。它通过对底层 TTY 设备的直接控制,实现了从基础连接到复杂 MODBUS 协议封装的一站式治理。将。

大山哥 4595

当Rust遇见Android:实测JNI方案比Flutter FFI快多少?含完整性能对比数据

本文通过实测对比了在Android平台上,使用Rust编写高性能模块时,JNI与Flutter FFI两种调用方案的性能差异。测试数据显示,在处理10MB数据时,JNI方案比FFI方案快约154%,性能优势显著。文章深入分析了不同数据量下的耗时、CPU与内存占用,并为移动端高性能模块的技术选型提供了基于数据的决策参考。

weixin_29018335的博客 127

DCLI项目在Dart 3.5环境下的兼容性问题解析

DCLI项目在Dart 3.5环境下的兼容性问题解析 DCLI是一个基于Dart语言的命令行工具开发框架,近期在升级到Dart 3.5版本后出现了兼容性问题。本文将深入分析该问题的技术背景、产生原因以及解决方案。 问题现象 当用户在Dart 3.5环境下执行dcli compile --install命令时,会遇到以下错误: ArgumentError: Invalid argument(s): ...

gitblog_07395的博客 364

鸿蒙平台适配duckdb_dart实现高性能移动数据分析

嵌入式数据库作为移动端数据处理的关键技术,通过本地化计算有效解决了数据隐私和网络延迟问题。DuckDB作为轻量级OLAP引擎,其列式存储和向量化执行引擎特别适合资源受限的移动设备。通过FFI(外部函数接口)技术,Flutter应用可以无缝集成原生数据库能力。在鸿蒙系统上适配duckdb_dart需要处理平台特定的线程模型、内存管理和文件系统访问,最终实现端侧商业智能分析、实时数据可视化等场景。该方案特别适合需要处理销售数据、用户行为日志等分析型任务的移动应用,在保证数据安全合规的同时提供亚秒级查询响应。

weixin_34293911的博客 423

鸿蒙适配dart_dice_parser:高性能规则解析实践

规则解析是软件开发中的基础技术,用于处理结构化文本和业务逻辑。基于LL(1)算法的解析器具有线性时间复杂度,能高效处理复杂表达式。在跨平台开发中,Flutter组件的鸿蒙适配尤为重要,特别是dart_dice_parser这样的高性能解析引擎。通过FFI和C++实现原生交互,结合鸿蒙的TaskDispatcher并发机制,可显著提升金融风控、游戏逻辑等场景的解析性能。本文以dart_dice_parser为例,详细讲解如何优化内存管理和多线程处理,实现毫秒级响应,为鸿蒙生态填补高效规则解析的空白。

weixin_30924087的博客 366

Dart调用Python模型推理服务,性能提升8倍的秘密是什么?

auto-generated

PixelFlow的博客 1135

Flutter BLE高频数据处理方案对比

本文对比了Flutter BLE开发中处理高频数据(如8kHz心电设备)的三种方案:Dart解析、透传原生层处理、FFI直接调用C++。通过性能、开发成本、维护性和调试难度四个维度的分析,指出方案三(FFI)在高频场景下最优,具备零拷贝、无线程切换优势;方案一适合低频简单场景;方案二因多级拷贝和双端维护成本,不推荐高频使用。最终建议根据数据频率和团队技术栈选择:低频选Dart方案,高频医疗设备优先FFI方案,已有原生SDK可考虑透传方案但需承担性能损耗。

唐诺 384
上一篇: v8 8.0以上版本中,V8_COMPRESS_POINTERS引发的崩溃
漂流的代码
博客等级 码龄23年 188粉丝 99原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值