Dart FFI使用 示例

2021-12-31 17:24:27 浏览数 (1)

是什么

Dart FFI(官方地址)是可以在Dart Native平台上运行的Dart移动、命令行和服务器应用上通过Dart FFI来调用C代码的一个技术。简单来说,就是Dart与C互相调用的一种机制。Dart FFI是Dart2.12.0版本后(同时包含在 Flutter 2.0 和以后的版本里),才作为稳定版本发布。

说到底,Dart语言也是因为Flutter使用了它才火起来的,所以Dart FFI技术在Flutter应用中更能发挥它更强大的作用

解决的问题

  1. 可以同步调用C API,不像Flutter Channel一开始就是异步
  2. 调用C语言更快,不像之前需要通过Native中转(或者改Flutter引擎代码)
  3. 还可以封装替换Flutter Channel达到更快和支持同步的目地

简单使用

为了只看FFI的特性,我先不在Flutter平台上使用,仅仅用命令行Dart应用的方式来讲解。 本人工程环境:

运行环境 MacOS 10.15.6 GCC 12.0.0 cmake 3.20.1 make 3.81 dart 2.14.2

1. 创建项目

由于项目结构简单,直接手动创建项目

1). 创建pubspec.yaml文件

2). 创建bin/main.dart文件

3). 创建C环境,创建librarylibrary/build文件夹

4). 创建library/sample.clibrary/sample.hlibrary/sample.defCMakeLists.txt文件

目录结构如下

代码语言:javascript复制
|_ bin
    |_ main.dart
|_ library
    |_ build
    |_ CMakeLists.txt
    |_ sample.c
    |_ sample.h
    |_ sample.def
|_ pubspec.yaml
复制代码

2. pubspec.yaml引入FFI

pubspec.yaml文件中的dependencies中加入ffipath

pubspec.yaml

代码语言:javascript复制
name: ffi_sample
version: 0.0.1
description: 使用ffi及ffigen的例子

publish_to: none

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  path: ^1.7.0
  ffi: ^1.1.2
复制代码

3. 编译C代码

sample.h中写简单的一个函数

sample.h

代码语言:javascript复制
void hello_world();
复制代码

sample.c中实现

sample.c

代码语言:javascript复制
#include <stdio.h>
#include <stdlib.h>
#include "sample.h"
void hello_world()
{
    printf("Hello Worldn");
}
复制代码

sample.def中简单导出

代码语言:javascript复制
LIBRARY   sample
EXPORTS
   sample
复制代码

写编译使用的CMakeLists.txt文件

代码语言:javascript复制
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(sample_library VERSION 1.0.0 LANGUAGES C)
add_library(sample_library SHARED sample.c sample.def)
add_executable(sample_test sample.c)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)

set_target_properties(sample_library PROPERTIES
    PUBLIC_HEADER sample.h
    VERSION ${PROJECT_VERSION}
    SOVERSION 1
    OUTPUT_NAME "sample"
    XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Hex_Identity_ID_Goes_Here"
)
复制代码

3. 编译C文件

现在所有文件都准备就绪,就可以编译C代码了。

1). 命令行进入到library/build文件夹下

2). 执行cmake ..生成编译所需文件

3). 执行make编译

代码语言:javascript复制
cd library/build
cmake ..
make
复制代码

如果在library/build文件夹下生成了libsample.1.0.0.dylib文件,那么说明编译成功了。

4. 写Dart通信代码

bin/main.dart中调用C

代码语言:javascript复制
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'dart:io' show Platform, Directory;

import 'package:path/path.dart' as path;

void main() {
  void main() {
  // 初始化互调框架
  var libraryPath =
      path.join(Directory.current.path, 'ibrary', 'build', 'libsample.so');
  if (Platform.isMacOS) {
    libraryPath = path.join(
        Directory.current.path, 'library', 'build', 'libsample.dylib');
  }
  if (Platform.isWindows) {
    libraryPath =
        path.join(Directory.current.path, 'library', 'Debug', 'libsample.dll');
  }
  final dylib = DynamicLibrary.open(libraryPath);

  // *************** 1. Dart调用C方法 **************
  final Pointer<T> Function<T extends NativeType>(String symbolName)
      _lookup;
    _lookup = dylib.lookup;

  late final _hello_worldPtr =
      _lookup<NativeFunction<Void Function()>>('hello_world');
  late final _hello_world = _hello_worldPtr.asFunction<void Function()>();
  // 调用C方法(无参)
  _hello_world();
}
复制代码

5. 运行代码

现在,在命令行的项目根目录下运行

代码语言:javascript复制
dart run bin/main.dart
复制代码

如果输出

代码语言:javascript复制
Hello World
复制代码

说明调用成功

总结

上面就是Dart FFI简单的示例了,后面我会继续更新,详细介绍Dart FFI使用,欢迎关注。上面的代码我都打包放到Github了,Github地址

0 人点赞