ffi简介
FFI(Foreign Function Interface)是用来与其它语言交互的接口,在有些语言里面称为语言绑定(language bindings),Java 里面一般称为 JNI(Java Native Interface) 或 JNA(Java Native Access)。由于现实中很多程序是由不同编程语言写的,必然会涉及到跨语言调用,比如 A 语言写的函数如果想在 B 语言里面调用,这时一般有两种解决方案:一种是将函数做成一个服务,通过进程间通信(IPC)或网络协议通信(RPC, RESTFul等);另一种就是直接通过 FFI 调用。前者需要至少两个独立的进程才能实现,而后者直接将其它语言的接口内嵌到本语言中,所以调用效率比前者高。

rust代码

  1. 创建一个文件夹,如flutter-ffi-rust,然后进入flutter-ffi-rust文件夹执行:cargo new rust_ffi
  2. 进入rust_ffi执行:cargo run,确保创建的rust项目可以执行
  3. 在Cargo.toml文件中添加代码如下:
[lib]
name = "casher"
crate-type = ["cdylib"]
  1. 将mian.rs改为lib.rs,将如下代码粘贴进去:
use std::io::Write;
use std::ffi::CStr;
use std::os::raw::c_char;

#[no_mangle]
pub extern "C" fn play_once(ptr: *const c_char) -> u32 {
    let cstr = unsafe { CStr::from_ptr(ptr)};
    let a = cstr.to_str().unwrap();

    let mut file = std::fs::File::create("data.txt").expect("create failed");
    file.write_all("简单测试121212".as_bytes()).expect("write failed");
    file.write_all("\n简单编程".as_bytes()).expect("write failed");
    println!("data written to file" );
    println!("data written to file----{}",a);

    let return_num = 10;
    return_num
}

#[no_mangle]
pub extern "C" fn play_once_test(ptr: *const c_char) -> u32 {
    let cstr = unsafe { CStr::from_ptr(ptr)};
    let a = cstr.to_str().unwrap();
    println!("data written to file-----------{}",a);

    let mut file = std::fs::File::create("datatest.txt").expect("create failed");
    file.write_all("简单教程测试".as_bytes()).expect("write failed");
    file.write_all("\n简单编程测试".as_bytes()).expect("write failed");
    println!("data written to file" );
    let s = 11;
    s
}
  1. 执行cargo build,然后target/debug下面会出现一个ibcasher.dylib文件,注意:在Linux上会创建*.so文件,在MacOSX上会创建*.dylib文件,在Windows上会创建*.dll文件,我是macos,所以会生成dylib文件

dart代码

  1. 在flutter-ffi-rust文件夹下创建flutter项目,执行dart create flutter_ffi
  2. 进入flutter_ffi里面执行dart run,确保创建的flutter项目正确,然后执行 dart pub add ffi 或者在pubspec.yaml 安装 ffi: ^1.2.1
  3. 将如下代码粘入bin/flutter_ffi.dart里面:
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';

typedef playOnceFunc = ffi.Void Function(ffi.Pointer<Utf8>);
typedef PlayOnce = void Function(ffi.Pointer<Utf8>);

void main() {
  final ffi.DynamicLibrary dylib = ffi.DynamicLibrary.open('libcasher.dylib');

  // final PlayOnce play_once = dylib
  //     .lookup<ffi.NativeFunction<playOnceFunc>>('play_once')
  //     .asFunction();

  // final PlayOnce play_once_test = dylib
  //     .lookup<ffi.NativeFunction<playOnceFunc>>('play_once_test')
  //     .asFunction();

  const String file_name = '用来测试传递参数';

  // Convert a Dart [String] to a Utf8-encoded null-terminated C string.
  final ffi.Pointer<Utf8> charPointer = file_name.toNativeUtf8();

  var result = dylib.lookupFunction<ffi.Pointer<Utf8> Function(ffi.Pointer<Utf8>),ffi.Pointer<Utf8> Function(ffi.Pointer<Utf8>)>('play_once_test',isLeaf:true);

  // play_once(charPointer);
  var s = result(charPointer).address;
  print("==============");
  print(s);
  
  // play_once_test();
}
  1. 将生成的*.dylib文件放入flutter_ffi文件夹下
  2. 执行dart run,看调用rust的结果,会生成data.txt文件并写入数据
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐