教程:Flutter 和 Rust混合编程,使用flutter_rust_bridge自动生成ffi代码

news2024/11/26 0:23:20

实践环境:Arch Linux

flutter_rust_bridge官方文档

Flutter环境配置教程 | Rust环境配置教程

记录使用flutter_rust_bridge遇到的一些坑。

假设已经我们配置了Fluuter与Rust环境

现在直接使用flutter_rust_bridge模板创建自己的项目

运行:

git clone https://github.com/Desdaemon/flutter_rust_bridge_template && cd flutter_rust_bridge_template

现在我们先让项目跑起来:

flutter run

添加新代码:

编辑 native/src/api.rs

安装代码生成器flutter_rust_bridge_codegen

cargo install flutter_rust_bridge_codegen

按照flutter_rust_bridge文档示例运行代码生成器:

flutter_rust_bridge_codegen --rust-input native/src/api.rs \
                            --dart-output lib/bridge_generated.dart

发现报错了:

找不到stdbool.h文件

bridge_generated.dart报错信息:

void store_dart_post_cobject(int ptr)
package:flutter_rust_bridge_template/bridge_generated.dart

Not to be used by normal users, but has to be public for generated code

Copied from FlutterRustBridgeWireBase.

'NativeWire.store_dart_post_cobject' ('void Function(int)') isn't a valid override of 'FlutterRustBridgeWireBase.store_dart_post_cobject' ('void Function(Pointer<NativeFunction<Bool Function(Int64, Pointer<Void>)>>)').dartinvalid_override
stub.dart(21, 8): The member being overridden.

运行:

flutter_rust_bridge_codegen --rust-input native/src/api.rs \
                            --dart-output lib/bridge_generated.dart \
                            --c-output ios/Runner/bridge_generated.h

发现还是老样子?怎么办?

解决方案:

添加CPATH环境变量,重新运行代码生成器:

export CPATH="$(clang -v 2>&1 | grep "Selected GCC installation" | rev | cut -d' ' -f1 | rev)/include"
flutter_rust_bridge_codegen --rust-input native/src/api.rs \
                            --dart-output lib/bridge_generated.dart \
                            --c-output ios/Runner/bridge_generated.h

现在就正常了

打开lib/ffi.dart

看到有两处致命错误

报错信息:

package:flutter_rust_bridge_template/bridge_generated.dart

The name 'Native' is defined in the libraries 'package:flutter_rust_bridge_template/bridge_definitions.dart' and 'package:flutter_rust_bridge_template/bridge_generated.dart'.
Try removing the export of one of the libraries, or explicitly hiding the name in one of the export directives.
[abstract class Native, abstract class Native]
The name 'Native' is defined in the libraries 'package:flutter_rust_bridge_template/bridge_definitions.dart' and 'package:flutter_rust_bridge_template/bridge_generated.dart'.
Try using 'as prefix' for one of the import directives, or hiding the name from all but one of the imports.

解决方案:

去掉import 'bridge_definitions.dart'; 和 export 'bridge_definitions.dart';

lib/ffi.dart原代码:

// This file initializes the dynamic library and connects it with the stub
// generated by flutter_rust_bridge_codegen.

import 'dart:ffi';

import 'bridge_generated.dart';
import 'bridge_definitions.dart';
export 'bridge_definitions.dart';

// Re-export the bridge so it is only necessary to import this file.
export 'bridge_generated.dart';
import 'dart:io' as io;

const _base = 'native';

// On MacOS, the dynamic library is not bundled with the binary,
// but rather directly **linked** against the binary.
final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so';

final Native api = NativeImpl(io.Platform.isIOS || io.Platform.isMacOS
    ? DynamicLibrary.executable()
    : DynamicLibrary.open(_dylib));

lib/ffi.dart修改后的代码:

// This file initializes the dynamic library and connects it with the stub
// generated by flutter_rust_bridge_codegen.

import 'dart:ffi';

import 'bridge_generated.dart';

// Re-export the bridge so it is only necessary to import this file.
export 'bridge_generated.dart';
import 'dart:io' as io;

const _base = 'native';

// On MacOS, the dynamic library is not bundled with the binary,
// but rather directly **linked** against the binary.
final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so';

final Native api = NativeImpl(io.Platform.isIOS || io.Platform.isMacOS
    ? DynamicLibrary.executable()
    : DynamicLibrary.open(_dylib));

一切正常:

main.dart调用rust函数

main.dart完整代码:

import 'package:flutter/material.dart';
import 'ffi.dart' if (dart.library.html) 'ffi_web.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(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        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);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // These futures belong to the state and are only initialized once,
  // in the initState method.
  late Future<Platform> platform;
  late Future<bool> isRelease;

  late Future<String> test;

  @override
  void initState() {
    super.initState();
    platform = api.platform();
    isRelease = api.rustReleaseMode();

    test = api.test();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text("You're running on"),
            FutureBuilder<List<dynamic>>(
                future: Future.wait([test]),
                builder: (context, snap) {
                  final data = snap.data;
                  if (data == null) {
                    return const Text("Loading");
                  }

                  return Text('${data[0]}');
                }),

            // To render the results of a Future, a FutureBuilder is used which
            // turns a Future into an AsyncSnapshot, which can be used to
            // extract the error state, the loading state and the data if
            // available.
            //
            // Here, the generic type that the FutureBuilder manages is
            // explicitly named, because if omitted the snapshot will have the
            // type of AsyncSnapshot<Object?>.
            FutureBuilder<List<dynamic>>(
              // We await two unrelated futures here, so the type has to be
              // List<dynamic>.
              future: Future.wait([platform, isRelease]),
              builder: (context, snap) {
                final style = Theme.of(context).textTheme.headline4;
                if (snap.error != null) {
                  // An error has been encountered, so give an appropriate response and
                  // pass the error details to an unobstructive tooltip.
                  debugPrint(snap.error.toString());
                  return Tooltip(
                    message: snap.error.toString(),
                    child: Text('Unknown OS', style: style),
                  );
                }

                // Guard return here, the data is not ready yet.
                final data = snap.data;
                if (data == null) return const CircularProgressIndicator();

                // Finally, retrieve the data expected in the same order provided
                // to the FutureBuilder.future.
                final Platform platform = data[0];
                final release = data[1] ? 'Release' : 'Debug';
                final text = const {
                      Platform.Android: 'Android',
                      Platform.Ios: 'iOS',
                      Platform.MacApple: 'MacOS with Apple Silicon',
                      Platform.MacIntel: 'MacOS',
                      Platform.Windows: 'Windows',
                      Platform.Unix: 'Unix',
                      Platform.Wasm: 'the Web',
                    }[platform] ??
                    'Unknown OS';
                return Text('$text ($release)', style: style);
              },
            )
          ],
        ),
      ),
    );
  }
}

运行项目:

flutter run

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

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

相关文章

W13Scan 扫描器挖掘漏洞实践

一、背景 这段时间总想捣鼓扫描器&#xff0c;发现自己的一些想法很多前辈已经做了东西&#xff0c;让我有点小沮丧同时也有点小兴奋&#xff0c;说明思路是对的&#xff0c;我准备站在巨人的肩膀去二次开发&#xff0c;加入一些自己的想法&#xff0c;从freebuf中看到W13Scan…

进程调度模块

目录 1.进程介绍 2.进程调度 2.1.进程状态 2.2.进程调度函数 ---schedule 2.3.进程切换函数 ---switch_to&#xff08;&#xff09; 1.进程介绍 在进程模块里面&#xff0c;我们知道了进程就是一个task_struct的结构体&#xff0c;里面含有进程的各种信息。进程存放在进程…

AppScan被动手动探索扫描

系列文章 AppScan介绍和安装 AppScan 扫描web应用程序 第三节-AppScan被动手动探索扫描 被动式扫描&#xff1a;浏览器代理到AppScan&#xff0c;然后进行手工操作&#xff0c;探索产生出的流量给AppScan进行扫描。 他的优点是&#xff1a;扫描足够精准&#xff0c;覆盖率更…

注册中心和负载均衡(黑马SpringCloud笔记)

注册中心和负载均衡 目录注册中心和负载均衡一、服务远程调用1. RestTemplate2. 服务调用关系3. 远程调用的问题二、注册中心1. Eureka注册中心1.1 搭建Eureka注册中心1.2 服务注册1.3 服务拉取1.4 小结2. nacos注册中心2.1Nacos搭建2.2 服务注册2.3 服务拉取2.4 服务分级存储模…

虹科新闻 | 虹科与丹麦Eupry正式建立合作伙伴关系

近期&#xff0c;虹科与丹麦Eupry正式建立合作伙伴关系。未来&#xff0c;虹科与Eupry将共同关注最具创新性和稳定性的解决方案&#xff0c;为客户提供温度记录仪、温湿度记录仪、Mapping温度分布验证服务、以及基于云的温湿度自动监测系统。 虹科非常高兴欢迎并宣布我们的新合…

【Linux】基础:进程信号

【Linux】基础&#xff1a;进程信号 摘要&#xff1a;本文将会从生活实际出发&#xff0c;由此掌握进程信号的学习过程&#xff0c;分别为信号的产生、信号的传输、信号的保存和信号的处理&#xff0c;最后再补充学习信号后方便理解的其他概念。 文章目录【Linux】基础&#xf…

echarts柱状图值为0时不显示以及柱状图百分比展示

echarts柱状图值为0时不显示以及柱状图百分比展示 1.效果展示 2.代码 <template><div id"container"><div id"main"></div></div> </template> <script>import * as echarts from echarts import * as lodash…

(JVM)浅堆深堆与内存泄露

​浅堆深堆与内存泄露 1. 浅堆&#xff08;Shallow Heap&#xff09; 浅堆是指一个对象所消耗的内存。在 32 位系统中&#xff0c;一个对象引用会占据 4 个字节&#xff0c;一个 int 类型会占据 4 个字节&#xff0c;long 型变量会占据 8 个字节&#xff0c;每个对象头需要占用…

01.【Vue】Vue2基础操作

一、Vue Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。另一方面&…

十五天学会Autodesk Inventor,看完这一系列就够了(七),工程图纸

众所周知&#xff0c;Autocad是一款用于二维绘图、详细绘制、设计文档和基本三维设计&#xff0c;现已经成为国际上广为流行的绘图工具。Autodesk Inventor软件也是美国AutoDesk公司推出的三维可视化实体模拟软件。因为很多人都熟悉Autocad&#xff0c;所以再学习Inventor&…

自动化测试 | 这些常用测试平台,你们公司在用的是哪些呢?

本文节选自霍格沃兹测试学院内部教材 测试管理平台是贯穿测试整个生命周期的工具集合&#xff0c;它主要解决的是测试过程中团队协作的问题。在整个测试过程中&#xff0c;需要对测试用例、Bug、代码、持续集成等等进行管理。下面分别从这四个方面介绍现在比较流行的管理平台。…

Spring入门-SpringAOP详解

文章目录SpringAOP详解1&#xff0c;AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念2&#xff0c;AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知…

Anaconda+VSCode配置tensorflow

主要参考https://blog.csdn.net/qq_42754919/article/details/106121979vscode的安装以及Anaconda的安装网上有很多教程&#xff0c;大家可以自行百度就行。在安装Anaconda的时候忘记勾选自动添加path&#xff0c;需要手动添加环境变量path下面介绍tensorflow安装教程:1.打开An…

getRequestDispatcher()转发和sendRedirect()重定向介绍与比较

文章目录1. request.getRequestDispatcher()1.1请求转发和请求包含的区别1.2request域2.response.sendRedirect()3.请求转发与重定向的区别比较测试1. request.getRequestDispatcher() getRequestDispatcher()包含两个重要方法&#xff0c;分别是请求转发和请求包含。一个请求…

系分 - 案例分析 - 系统设计

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录系分 - 案例分析 - 系统设计结构化设计SD内聚偶然内聚逻辑内聚时间&#xff08;瞬时&#xff09;内聚过程内聚通信内聚顺序内聚功能内聚耦合内容耦合公共耦合外部耦合控制耦合标记耦合数据耦合非直接耦合补…

DTO 与 PO的相互转换

目录 常见Bean映射框架 Dozer Orika MapStruct ModelMapper JMapper 测试模型 转化器 OrikaConverter DozerConverter MapperStructConvert JMapperConvert ModelMapperConverter 测试 平均时间 吞吐量 SingleShotTime 采集时间 DTO&#xff08;Data Transfer …

Android项目Gadle统一依赖管理

一.Gradle管理依赖版本 在中大型Android项目中&#xff0c;都会有多个Module进行协同配合。这些module中可能会依赖同一个库的不同版本&#xff0c;这将导致一些问题&#xff0c;要么是代码冲突&#xff0c;要么是APK包体积增大&#xff0c;亦或是项目构建的时间变长&#xff…

在Revit里如何将普通墙与曲面墙的内壁连接

在Revit里如何将普通墙与曲面墙的内壁连接&#xff1f;创建异形建筑时&#xff0c;为了达到如图1所示的效果&#xff0c;该如何操作&#xff1b; 我们可以使用体量建模的方式来创建该类建筑&#xff0c;要点在于如将幕墙与曲面墙的内壁连接。具体方法如下&#xff1a; 一、创建…

ASP.NET Core+Element+SQL Server开发校园图书管理系统(一)

随着技术的进步&#xff0c;跨平台开发已经成为了标配&#xff0c;在此大背景下&#xff0c;ASP.NET Core也应运而生。本文主要基于ASP.NET CoreElementSql Server开发一个校园图书管理系统为例&#xff0c;简述基于MVC三层架构开发的常见知识点&#xff0c;仅供学习分享使用&a…

ubuntu20.04下出现protoc与gazebo版本问题

ubuntu20protocgazebo问题描述问题定位解决方案问题描述 今天在搞路径规划算法时&#xff0c;从git上拉下来一个算法&#xff0c;ros环境那些都有&#xff0c;但是在编译的时候出现了如下图所示的一下问题&#xff1a;&#xff08;为了方便搜索关键词&#xff09; In file incl…