1️⃣ 项目结构(先创建这些文件)
my_ffi_app/
├── lib/
│ ├── main.dart # Flutter 主界面
│ └── native_add.c # C 语言代码(FFI 调用的核心)
├── android/
│ └── app/
│ └── build.gradle # Android 配置
└── ios/
└── Runner.xcworkspace # iOS 自动配置(Xcode 管理)
2️⃣ C 代码:lib/native_add.c
#include <stdint.h> // 引入标准整数类型(如 int32_t)
// 告诉编译器:按C风格编译(Dart只能调C风格函数)
extern "C" {
// 标记函数为"可见"(防止被编译器优化删除)
__attribute__((visibility("default")))
// 标记函数为"被使用"(确保链接时保留)
__attribute__((used))
// 定义一个加法函数(返回 int32_t,参数为 x, y)
int32_t native_add(int32_t x, int32_t y) {
return x + y; // 最简单的加法!
}
}
3️⃣ Android 配置:android/app/build.gradle
android {
defaultConfig {
// ... 其他配置
externalNativeBuild {
cmake {
path "../CMakeLists.txt" // 指定 CMake 配置文件路径
}
}
}
}
👉 新建 android/app/CMakeLists.txt
(文件名固定!):
cmake_minimum_required(VERSION 3.6) # 要求 CMake 最低版本
add_library( # 编译一个动态库(Android 叫 .so)
native_add # 库名(随便起)
SHARED # 类型:动态库
../../lib/native_add.c # C 文件路径(从项目根目录算)
)
4️⃣ iOS 配置(自动!)
✅ 无需额外配置!Xcode 会自动识别 ios/Runner
下的 .c
文件。
5️⃣ Dart 代码:lib/main.dart
import 'package:flutter/material.dart';
import 'dart:ffi'; // FFI 核心库
import 'dart:io'; // 用于判断平台(Android/iOS)
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: FutureBuilder(
future: _calculate(), // 异步执行 FFI 调用
builder: (ctx, snapshot) => Text("1+2=${snapshot.data}"),
),
),
),
);
}
Future<int> _calculate() async {
// 第一步:加载动态库(Android 和 iOS 方式不同)
final dylib = Platform.isAndroid
? DynamicLibrary.open("libnative_add.so") // Android 库名
: DynamicLibrary.process(); // iOS 直接读进程
// 第二步:查找 C 函数符号(按名称找函数)
final nativeAdd = dylib.lookupFunction<
Int32 Function(Int32, Int32), // C 函数签名(输入输出类型)
int Function(int, int) // Dart 函数签名(自动转换类型)
>("native_add"); // 要查找的函数名
// 第三步:像普通 Dart 函数一样调用!
return nativeAdd(1, 2); // 输出 1+2=3
}
}
6️⃣ 运行说明
- Android:直接
flutter run
- iOS:先打开
ios/Runner.xcworkspace
,用 Xcode 添加native_add.c
文件(右键 Runner → Add Files)
🧠 核心概念解释(小学生版)
关键词 | 作用 | 类比 |
---|---|---|
FFI | 让 Dart 和 C 语言互相通话的“翻译官” | 会说两国语言的机器人 |
DynamicLibrary | 加载 C 编译好的动态库(.so 或 .dylib ) |
打开一本外文书 |
lookupFunction | 在书里查找指定的函数(按函数名) | 翻到书的第 XX 页 |
extern "C" | 告诉 C++ 编译器:“别用复杂语法,用简单的 C 风格写!” | 用小学生词汇写说明书 |