Last updated:
0 purchases
flutter3 ffi
flutter3_ff1 #
2024-04-30
提供Uint8List<->ffi.Pointer<Vec_uint8_t>的方法.
提供String<->ffi.Pointer<Vec_uint8_t>的方法.
参考 #
https://dart.dev/interop/c-interop
使用safer_ffi生成c绑定的头文件.h.
使用ffigen将.h头文件生成flutter bindings.
safer_ffi #
https://github.com/getditto/safer_ffi
在rust工程中引入safer_ffi. #
[lib]
crate-type = [
"staticlib", # Ensure it gets compiled as a (static) C library
"cdylib", # If you want a shared/dynamic C library (advanced)
#"lib", # For `generate-headers`, `examples/`, `tests/` etc.
]
#在写代码阶段,可以注释掉这个部分
#[[bin]]
#name = "generate-headers"
#required-features = ["headers"] # Do not build unless generating headers.
[dependencies]
# Use `cargo add` or `cargo search` to find the latest values of x.y.z.
# For instance:
# cargo add safer-ffi
# https://crates.io/crates/safer-ffi
safer-ffi.version = "0.1.7"
safer-ffi.features = [] # you may add some later on.
[features]
# If you want to generate the headers, use a feature-gate
# to opt into doing so:
headers = ["safer-ffi/headers"]
copied to clipboard
在lib.rs文件中加入 #
#[test]
#[cfg(feature = "headers")] // c.f. the `Cargo.toml` section
pub fn generate_headers() -> std::io::Result<()> {
safer_ffi::headers::builder()
.to_file("rust_headers.h")?
.generate()
}
copied to clipboard
在api.rs文件中加入需要导出的接口 #
/// 测试输入一个字符串, 返回对应的字符串
#[ffi_export]
fn test_string(str: &safer_ffi::String) -> safer_ffi::String {
//let rust_str = str.to_string();
//let safer_str = safer_ffi::String::from(result);
format!("Hello, {}", str).into()
}
/// 测试输入一个字节数组, 返回对应的字节长度
#[ffi_export]
fn test_bytes(bytes: &safer_ffi::Vec<u8>) -> usize {
//let safer_vec = safer_ffi::Vec::from(result);
//let rust_data = data.to_vec();
bytes.len()
}
copied to clipboard
对象的导出:
/// A `struct` usable from both Rust and C
#[derive_ReprC]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Point {
x: f64,
y: f64,
}
/* Export a Rust function to the C world. */
/// Returns the middle point of `[a, b]`.
#[ffi_export]
fn mid_point(a: &Point, b: &Point) -> Point {
Point {
x: (a.x + b.x) / 2.,
y: (a.y + b.y) / 2.,
}
}
/// Pretty-prints a point using Rust's formatting logic.
#[ffi_export]
fn print_point(point: &Point) {
println!("{:?}", point);
}
copied to clipboard
生成 #
使用命令生成对应的头文件.
cargo test --package rust --lib generate_headers --features headers
copied to clipboard
ffigen #
https://pub.dev/packages/ffigen
使用flutter创建一个ffi工程, 就会自动依赖ffigen
ffigen.yaml #
创建一个yaml配置文件
# Run with `flutter pub run ffigen --config ffigen.yaml`.
name: FfigenSaferFfiDemoBindings
description: |
Bindings for `src/ffigen_safer_ffi_demo.h`.
Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`.
output: 'lib/ffigen_safer_ffi_demo_bindings_generated.dart'
headers:
entry-points:
- 'src/ffigen_safer_ffi_demo.h'
- 'rust/rust_headers.h'
include-directives:
- 'src/ffigen_safer_ffi_demo.h'
- 'rust/rust_headers.h'
- '*.h'
preamble: |
// ignore_for_file: always_specify_types
// ignore_for_file: camel_case_types
// ignore_for_file: non_constant_identifier_names
comments:
style: any
length: full
copied to clipboard
生成 #
使用命令生成对应的flutter绑定文件
@echo off
rem 通过.h文件生成dart 绑定代码
rem flutter pub run ffigen --config ffigen.yaml
dart run ffigen --config ffigen.yaml
copied to clipboard
Vec_uint8_t String Uint8List 转换 #
/// [test_string]
String? testString(String str) {
final bytes = utf8.encode(str);
final Pointer<Uint8> bytesPtr = calloc.allocate<Uint8>(bytes.length);
final Uint8List nativeBytes = bytesPtr.asTypedList(bytes.length);
nativeBytes.setAll(0, bytes);
final ptr = calloc<Vec_uint8_t>();
ptr.ref.len = bytes.length;
ptr.ref.cap = bytes.length;
ptr.ref.ptr = bytesPtr;
try {
final resultVec = _bindings.test_string(ptr);
final result = resultVec.ptr;
final reversedBytes = result.asTypedList(resultVec.len);
final reversedString = utf8.decode(reversedBytes);
return reversedString;
} catch (e) {
print(e);
return null;
} finally {
calloc.free(ptr);
calloc.free(bytesPtr);
}
}
/// [test_bytes]
int testBytes(Uint8List bytes) {
final watchGenerate = Stopwatch()..start();
final Pointer<Uint8> bytesPtr = malloc.allocate<Uint8>(bytes.length);
final Uint8List nativeBytes = bytesPtr.asTypedList(bytes.length);
nativeBytes.setAll(0, bytes);
watchGenerate.stop();
print("allocate: ${watchGenerate.elapsedMilliseconds}ms");
final ptr = malloc<Vec_uint8_t>();
ptr.ref.len = bytes.length;
ptr.ref.cap = bytes.length;
ptr.ref.ptr = bytesPtr;
try {
final watchBinding = Stopwatch()..start();
final result = _bindings.test_bytes(ptr);
watchBinding.stop();
print("bindings: ${watchBinding.elapsedMilliseconds}ms");
return result;
} catch (e) {
print(e);
return 0;
} finally {
malloc.free(ptr);
malloc.free(bytesPtr);
}
}
copied to clipboard
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.