第1章 混合工程
1.1 Flutter 工程体系
1.1.1 混合工程研发体系介绍
工程研发体系的关键点包括:
- 混合工程下的Flutter 研发结构。在混合工程中,一个全局视角的研发结构是什么样的。
- 工程结构。已有的Native 工程如何引入Flutter,工程结构如何组织,如何管理Flutter 环境,如何编译构建和集成打包等。
- 构建优化。如何针对Flutter 的工具链(flutter_tools、IntelliJ 插件等)进行调试与优化。
- Native 启动下的Flutter 调试。不同于Flutter 启动下的一体化调试,这种Native 启动(Xcode、Android Studio 启动,或点击图标打开应用)下的Flutter 调试,我们称为分离式调试。分离式调试可以简化flutter_tools 带来的复杂度,提高调试的稳定性和灵活性。
- Native 启动下的Flutter 热重载。
- 联合调试。同时调试Flutter 和Android/iOS。
- 持续集成。混合环境下的Flutter 构建与持续集成。
1.1.2 混合工程下的Flutter 研发结构
如图1-1 所示,在这个工程研发体系中,基于Flutter 的官方仓库,开发者可以获取引擎依赖,进行适当修改,以满足定制化场景下的需求。开发完毕各模块后发布到私有Pub 仓库,再通过pubspec.yaml 被业务代码依赖和集成。在构建时,首先将Dart 代码编译成产物(App.framework 或Snapshot),再通过标准的Pod(iOS)依赖或者Gradle(Android)依赖集成到IPA(iOS)和APK(Android)中去。对于Native 开发人员,无须关注Flutter 部分的细节;对于Flutter 开发人员,可以通过启动Flutter 工程调试,也可以在Native 工程启动后打开Flutter 页面(Observatory 开始监听),利用Dart 远程连接的方式实现调试。
图1-1
1.1.3 工程结构
这部分的核心逻辑是如何在最小改动已有iOS 或Android 工程的前提下运行Flutter。可以将Flutter 部分理解为一个单独的模块,通过Pod 库(iOS)或AAR 库(Android)的方式,由CocoaPods 和Gradle 引入主工程,如图1-2 所示。
图1-2
1.1.4 构建优化
问题:Android 在由Flutter 启动时构建缓慢。
原因: 在Flutter 工具链( flutter_tools ) 的逻辑中, 当未找到android/app/build.gradle 时,会运行gradle build,从而执行多个编译配置的构建,而不是gradle assembleDebug。
解法:重构Android 工程,使工程应用Module 对应的build.gradle 位于android/app 下,从而符合flutter_tools 的逻辑。
flutter_tools 的调试方法如下。
(1)修改flutter_tools.dart,使之可打印参数。
import 'package:flutter_tools/executable.dart' as executable;
void main(List<String> args) {
print('[KWLM]:${args.join(' ')}');
executable.main(args);
}
(2)删除flutter/bin/cache/fluttertools.stamp,使得fluttertools 可以被重建。
# Invalidate cache if:
# * SNAPSHOT_PATH is not a file, or
# * STAMP_PATH is not a file with nonzero size, or
# * Contents of STAMP_PATH is not our local git HEAD revision, or
# * pubspec.yaml last modified after pubspec.lock
if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$STAMP_PATH" || "$(cat
"$STAMP_PATH")" != "$revision" || "$FLUTTER_TOOLS_DIR/pubspec.yaml"
-nt "$FLUTTER_TOOLS_DIR/ pubspec.lock" ]]; then
rm -f "$FLUTTER_ROOT/version"
touch "$FLUTTER_ROOT/bin/cache/.dartignore"
"$FLUTTER_ROOT/bin/internal/update_dart_sdk.sh"
VERBOSITY="--verbosity=error"
echo Building flutter tool...
if [[ "$CI" == "true" || "$BOT" == "true" ||
"$CONTINUOUS_INTEGRATION" == "true" || "$CHROME_HEADLESS" == "1" ]];
then
PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_bot"
VERBOSITY="--verbosity=normal"
fi
export PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_install"
if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then
export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}"
fi
retry_upgrade
"$DART" $FLUTTER_TOOL_ARGS --snapshot="$SNAPSHOT_PATH"
--packages= "$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH"
echo "$revision" > "$STAMP_PATH"
fi
(3)从Flutter 运行构建,获取其入口参数。
Building flutter tool...
[KWLM]:--no-color run --machine --track-widget-creation
--device-id= GWY7N16A31002764 --start-paused lib/main.dart
Running "flutter packages get" in hello_world...
0.4s
Launching lib/main.dart on MHA AL00 in debug mode...
Initializing gradle...
Resolving dependencies...
(4)用IntelliJ(或Android Studio,下同)打开flutter_tools 工程,新建Dart Command Line App,并基于步骤(3)获得的入参来配置“Program arguments”,如图1-3 所示。
图1-3
(5)开始flutter_tools 调试,如图1-4 所示。
图1-4