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

这篇具有很好参考价值的文章主要介绍了教程:Flutter 和 Rust混合编程,使用flutter_rust_bridge自动生成ffi代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

实践环境: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 和 Rust混合编程,使用flutter_rust_bridge自动生成ffi代码
教程:Flutter 和 Rust混合编程,使用flutter_rust_bridge自动生成ffi代码

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

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

添加新代码:

编辑 native/src/api.rs

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

安装代码生成器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文件

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

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

现在就正常了

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

打开lib/ffi.dart

看到有两处致命错误

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

报错信息:

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));

一切正常:

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

main.dart调用rust函数

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

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);
              },
            )
          ],
        ),
      ),
    );
  }
}

运行项目:文章来源地址https://www.toymoban.com/news/detail-483424.html

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

到了这里,关于教程:Flutter 和 Rust混合编程,使用flutter_rust_bridge自动生成ffi代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter 生成运行小程序的混合App开发实践

    微信小程序发展的越来越快,目前小程序甚至取代了大部分 App 的生态位,公司的坑位不增反降,只能让原生应用开发兼顾或换岗进行小程序的开发。 以我的实际情况来讲,公司应用采用的 Flutter 框架,同样的功能不可避免的就会存在 Flutter 应用开发和微信小程序开发兼顾的

    2024年02月14日
    浏览(44)
  • 掘力计划第 20 期:Flutter 混合开发的混乱之治

    在掘力计划系列活动第20场,《Flutter 开发实战详解》作者,掘金优秀作者,Github GSY 系列目负责人恋猫的小郭分享了Flutter 混合开发的混乱之治。 Flutter 基于自研的 Skia 引擎实现了跨平台高性能渲染,但其独立的渲染层带来了与 Android 混合开发的技术挑战。经过几年的演进,

    2024年02月14日
    浏览(35)
  • flutter getx 简单使用教程

    所以Flutter使用GetX真的很不错 为什么说什么GetX好用呢? 1、依赖注入 GetX是通过依赖注入的方式,存储相应的XxxGetxController;已经脱离了InheritedWidget那一套玩法,自己手动去管理这些实例,使用场景被大大拓展 2、跨页面交互 这绝对是GetX的一个优点!对于复杂的生产环境,跨

    2024年02月08日
    浏览(53)
  • Flutter——最详细(AppBar)使用教程

    Material Design 应用栏(标题栏) 顶部标题栏包括一些常用的菜单按钮 属性 作用 leading 左边工具视图 automaticallyImplyLeading 左边图标的颜色 title 标题视图 actions 右边菜单按钮 flexibleSpace 其高度将与应用栏的整体高度相同 bottom 左侧底部文本内容 elevation 底部阴影 scrolledUnderElevation 左

    2024年02月05日
    浏览(47)
  • Flutter——最详细(NavigationRail)使用教程

    一个 Material Design 小部件,旨在显示在应用程序的左侧或右侧,以便在少量视图(通常在三到五个视图之间)之间导航。 通过Row属性,左侧或右侧菜单栏按钮 属性 作用 onDestinationSelected 选择索引回调监听器 selectedIndex 目前选定目的地的索引 destinations 存放菜单按钮 backgroundC

    2024年02月16日
    浏览(41)
  • Flutter——最详细(CustomScrollView)使用教程

    创建一个 [ScrollView],该视图使用薄片创建自定义滚动效果。 [SliverList],这是一个显示线性子项列表的银子列表。 [SliverFixedExtentList],这是一种更高效的薄片,它显示沿滚动轴具有相同范围的子级的线性列表。 [SliverGrid],这是一个显示子项 2D 数组的薄片。 [SliverPadding],这是

    2024年01月22日
    浏览(38)
  • Flutter——最详细(NavigationBar)使用教程

    Material 3 导航栏组件! 导航栏提供了一种持久且便捷的方式来在应用程序的主要目的地之间进行切换。 底部菜单栏模块 属性 作用 onDestinationSelected 选择索引回调监听器 selectedIndex 目前选定目的地的索引 destinations 存放菜单按钮 backgroundColor 导航栏背景色 elevation 海拔高度 heigh

    2024年02月15日
    浏览(36)
  • Flutter——最详细(TextField)使用教程

    文本输入框,拥有复杂的属性。可指定控制器、文字样式、装饰线、行数限制、游标样式等。监听输入框变动事件。 搜索框,输入账号密码等 属性 作用 controller 输入框监听器 decoration 输入框装饰属性 textAlign 内容对齐方式 textAlignVertical 文本垂直对齐 textDirection 文字方向 ma

    2024年02月13日
    浏览(40)
  • Flutter——最详细(Map)使用教程

    键值对的集合,您可以使用其关联的键从中检索值。 普通的 HashMap 是无序的(不保证顺序), LinkedHashMap 按键插入顺序迭代,而像 SplayTreeMap 这样的排序映射按排序顺序迭代键。 1,添加元素 addEntries() 2,更新组元素 update() 3,更新所有元素的值 updateAll() 4,删除指定的元素

    2024年02月06日
    浏览(35)
  • Flutter——最详细(Scaffold)使用教程

    相当于界面的主体(类似于安卓最外层PhoneWindow),组件的展示都必须依附于它。 每一个界面都是脚手架,通过它来进行架构实现,优美的布局效果。 属性 作用 appBar 顶部的标题栏 body 显示整体布局 floatingActionButton 右下角按钮 floatingActionButtonLocation 按钮的位置 floatingActionB

    2024年02月06日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包