Flutter 与 NDK 集成实现
Flutter 可以通过 Platform Channels 与原生代码(包括使用 NDK 编写的 C/C++ 代码)进行交互。以下是实现 Flutter 与 NDK 集成的步骤:
基本步骤
1. 创建 Flutter 项目
bash
flutter create flutter_ndk_example
cd flutter_ndk_example
2. 添加 Android NDK 支持
在 android/app/build.gradle
中添加 NDK 配置:
gradle
android {
// ...
defaultConfig {
// ...
externalNativeBuild {
cmake {
cppFlags "-std=c++17"
}
}
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
3. 创建 CMakeLists.txt 文件
在 android/app
目录下创建 CMakeLists.txt
:
cmake
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
)
find_library(
log-lib
log
)
target_link_libraries(
native-lib
${log-lib}
)
4. 创建 C++ 源文件
在 android/app/src/main/cpp
目录下创建 native-lib.cpp
:
cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_flutterndkexample_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
5. 创建 Method Channel 接口
在 lib/main.dart
中:
dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const platform = MethodChannel('com.example.flutterndkexample/channel');
Future<String> _getNativeString() async {
try {
return await platform.invokeMethod('getNativeString');
} on PlatformException catch (e) {
return "Failed to get string: '${e.message}'.";
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flutter NDK Example')),
body: Center(
child: FutureBuilder<String>(
future: _getNativeString(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else if (snapshot.hasError) {
return Text("Error: ${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
),
);
}
}
6. 实现 Android 端的 Method Channel
在 android/app/src/main/kotlin/.../MainActivity.kt
中:
kotlin
package com.example.flutterndkexample
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.flutterndkexample/channel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getNativeString") {
result.success(stringFromJNI())
} else {
result.notImplemented()
}
}
}
external fun stringFromJNI(): String
companion object {
init {
System.loadLibrary("native-lib")
}
}
}
更复杂的 NDK 功能示例
1. 添加数学计算函数
在 native-lib.cpp
中添加:
cpp
extern "C" JNIEXPORT jint JNICALL
Java_com_example_flutterndkexample_MainActivity_addNumbers(
JNIEnv* env,
jobject /* this */,
jint a,
jint b) {
return a + b;
}
2. 更新 Kotlin 代码
kotlin
external fun addNumbers(a: Int, b: Int): Int
// 在 MethodCallHandler 中添加
if (call.method == "addNumbers") {
val a = call.argument<Int>("a") ?: 0
val b = call.argument<Int>("b") ?: 0
result.success(addNumbers(a, b))
}
3. 更新 Dart 代码
dart
Future<int> _addNumbers(int a, int b) async {
try {
return await platform.invokeMethod('addNumbers', {'a': a, 'b': b});
} on PlatformException catch (e) {
print("Failed to add numbers: '${e.message}'.");
return 0;
}
}
iOS 平台的 NDK 实现(使用 Objective-C/Swift 调用 C++)
对于 iOS,Flutter 可以直接与 Objective-C/Swift 交互,后者可以调用 C++ 代码:
- 在
ios/Runner
目录下创建 C++ 文件 - 创建对应的头文件
- 在
AppDelegate.swift
中实现 Method Channel
最佳实践
- 尽量减少平台通道的调用次数(批量处理数据)
- 对于性能敏感的操作使用 NDK
- 错误处理要完善
- 考虑不同 Android ABI 的兼容性
- 对于复杂的 C++ 代码,考虑使用 FFI(Dart 2.12+ 支持)
通过以上步骤,你可以成功地将 Flutter 应用与 NDK 编写的原生代码集成,实现高性能的计算或访问特定的原生功能。