Flutter 中使用 C/C++ 的全面指南——第一章本指南适用于希望将 C/C++ 代码集成到 Flutter 应用
Flutter 是由 Google 创建的开源 UI 软件开发工具包。与其他跨平台 UI 开发工具包相比,它的核心优势在于使用了自己的渲染引擎,最初基于 Chrome 的 Skia。目前,在 iOS 和 Android 平台上引入了一个名为 Impeller 的新引擎。凭借自有的渲染引擎,Flutter 能够控制所有平台设备(包括移动设备和桌面平台)上的每一个像素,消除了这些平台之间在 UI 实现上的差异。
Flutter 和 Dart 在 UI 方面表现出色,但对于生产中的商业业务应用程序,通常会涉及到依赖目标平台操作系统提供的其他硬件或组件的业务逻辑。Dart 编程语言被设计用于构建令人愉悦的 UI,但并不适合访问硬件 I/O 和本地系统组件、多线程编程或高性能计算。因此,我们需要使用 C/C++ 等“低级”编程语言来处理这些任务。这些语言不仅能够直接与硬件交互,无需抽象层,还能够在所有平台上高效运行。
本指南适用于希望将 C/C++ 代码集成到 Flutter 应用中的移动/桌面开发者。内容涵盖了配置构建工具的最佳实践、在移动和桌面平台上进行调试、使用 Dart FFI 进行双向同步和异步调用、处理复杂数据结构、性能优化建议、在 C/C++ 端监听 Dart VM 重要回调以及 Windows 平台的一些重要提示。
初始化 Flutter 项目
Flutter 命令包含了一个用于将 C/C++ 与 Dart FFI 示例一起使用的内置模板项目。
flutter create --template=plugin_ffi demo_library --platforms android,ios,macos,windows,linux
此命令创建了一个 Flutter 插件包,其中包含了将 C/C++ 源代码添加到 Flutter 包中的基本构建脚本。
在 Windows、Linux 和 Android 上,C/C++ 代码通过 CMake 进行配置和编译,并且运行良好。然而,在 iOS 和 macOS 上,它是通过 CocoaPods 直接配置和编译的。
对于更复杂的 C/C++ 项目,管理两个构建系统在生产环境中并不可行。因此,我们需要修改 src/CMakeLists.txt 文件,以生成静态库并将 CocoaPods 的构建系统链接到 iOS 和 macOS 平台的 CMake。
使用 CMake 配置 macOS 的静态链接构建
首先,我们需要更新 src/CMakeLists.txt 文件,并将构建目标更改为静态库,以生成静态归档库:
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
add_library(demo_library STATIC
"flutter_native_example.c"
)
else()
add_library(demo_library SHARED
"flutter_native_example.c"
)
endif()
当构建目标为 macOS 或 iOS 平台时,我们将库类型设置为静态库。
然后,添加以下名为 build_macos.sh 的 shell 脚本来构建我们的静态库:
# 定义用于 macOS 构建的函数
build_macos() {
BUILD_TYPE="${1:-Debug}"
echo "Building for macOS in $BUILD_TYPE mode"
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G "Unix Makefiles" -B $BASEDIR/cmake-build-macos -S $BASEDIR/
cmake --build $BASEDIR/cmake-build-macos
}
build_macos "$@"
运行以下命令:./build_ios_macos.sh macos Release
或 ./build_ios_macos.sh macos Debug
以进行调试。
➜ src ./build_macos.sh Release
Building for macOS in Release mode
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/andycall/workspace/flutter_native_example/src/cmake-build-macos
[ 50%] Building C object CMakeFiles/demo_library.dir/flutter_native_example.c.o
[100%] Linking C static library libdemo_library.a
[100%] Built target demo_library
可以看到 libdemo_library.a
已生成在 <project>/src/cmake-build-macos/libdemo_library.a
。
在 macOS 上将 CMake 与 CocoaPods 链接
现在,打开 <project>/macos/flutter_native_example.podspec
并添加一个“脚本阶段”,以便在用户执行 flutter run
或 flutter build
命令时自动调用 CMake 命令。
s.prepare_command = 'bash build_macos.sh'
s.script_phase = {
:name => 'Trigger Native Build',
# First argument is relative path to the `rust` folder, second is name of rust library
:script => 'ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/build_phony"',
:execution_position=> :before_compile,
:input_files => ['${BUILT_PRODUCTS_DIR}/build_phony'],
:output_files => [__dir__ + "/../src/cmake-build-macos/libdemo_library.a"],
}
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'OTHER_LDFLAGS' => '-force_load ' + __dir__ + '/../src/cmake-build-macos/libdemo_library.a',
}
移除 CocoaPods 中包含的 C++ 源文件
不要忘记删除 <project>/macos/Classes/flutter_native_example.c
中的所有内容,以避免重复符号编译错误。
使用 flutter run 命令测试
现在是测试我们修改的构建脚本并查看是否一切正常的时候了。
cd example && flutter run -d macos
迁移到 iOS 平台支持
iOS 的构建配置与 macOS 构建非常相似。
在 macOS 上为 iOS 平台构建需要额外的步骤来配置交叉编译工具链。
在项目根目录下使用以下命令获取 ios-cmake 项目并使用 CMake 编译 iOS 目标:
git subtree add --prefix src/ios-cmake https://github.com/leetal/ios-cmake.git master --squash
添加构建 iOS 静态库的 Shell 脚本
# 定义用于 iOS 构建的函数
build_ios() {
BUILD_TYPE="${1:-Debug}"
echo "Building for iOS with $BUILD_TYPE mode"
cmake -DPLATFORM=OS64COMBINED -DCMAKE_TOOLCHAIN_FILE=$BASEDIR/ios-cmake/ios.toolchain.cmake -G "Xcode" -B $BASEDIR/cmake-build-ios -S $BASEDIR/
cmake --build $BASEDIR/cmake-build-ios --config $BUILD_TYPE
}
运行以下命令:./build_ios.sh ios Release
或 ./build_ios.sh ios Debug
以进行调试。
静态库将在 <project>/src/cmake-build-ios/Debug-iphoneos
目录下生成 Debug 构建版本,在 <project>/src/cmake-build-ios/Release-iphoneos
目录下生成 Release 构建版本。
在 iOS 上将 CMake 与 CocoaPods 链接
现在是修改 <project>/ios/flutter_native_example.podspec
,添加构建阶段并将我们的脚本与 CocoaPods 构建连接起来的时候了。
s.prepare_command = 'bash build_ios.sh'
s.script_phase = {
:name => 'Trigger Native Build',
# First argument is relative path to the `rust` folder, second is name of rust library
:script => 'ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/build_phony"',
:execution_position=> :before_compile,
:input_files => ['${BUILT_PRODUCTS_DIR}/build_phony'],
:output_files => [__dir__ + "/../src/cmake-build-ios/$CONFIGURATION-iphoneos/libdemo_library.a"],
}
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
'OTHER_LDFLAGS' => '-force_load ' + __dir__ + '/../src/cmake-build-ios/$CONFIGURATION-iphoneos/libdemo_library.a',
}
移除 CocoaPods 中包含的 C++ 源文件
不要忘记删除 <project>/ios/Classes/flutter_native_example.c
中的所有内容,以避免重复符号编译错误。
使用 flutter run 命令测试
现在是测试我们修改的构建脚本并查看是否一切正常的时候了。
cd example && flutter run -d <device_id>
为 Android、Linux 和 Windows 平台编译
Flutter 的模板项目已经很好地配置了用于 Android、Linux 和 Windows 的动态库加载构建。
查看演示并亲自尝试
本文中的所有代码都位于此 GitHub 仓库中:
下一章节
在下一章节中,我们将重点讨论如何在多个平台的 Flutter 应用中调试 C/C++ 代码。我们将介绍使用 Xcode、Visual Studio、Android Studio 和 CLion 等多种开发集成环境(IDE)来进行调试的技巧与实践。
转载自:https://juejin.cn/post/7407489781440446527