从 Python + Flet 的诸多不便,到拥抱 Dart + Flutter 的焕然一新,再到与新框架的“斗智斗勇”,重写“卦灵·云缨-道家小六壬APP”这款“道家小六壬”的辅助工具,可谓是一段痛并快乐着的旅程。如果你也曾对 Flet 的“全平台”承诺心动过,又或者正在 Flutter 的学习路径上,那么我踩过的这些坑,或许能为你照亮前路。
初衷:为何告别 Flet?
最初选择 Python + Flet,主要是看中了其“一套代码,全平台打包”的宣传。然而,理想很丰满,现实却骨感。Flet 带来的问题远超预期:
- 环境配置噩梦: 安装 Android Studio、Flutter SDK 等一系列依赖,过程繁琐,劝退指数极高。
- 臃肿的打包体积: 一个功能相对简单的工具类APP,APK 包体竟然接近 90MB,EXE 文件亦然。实际运行起来,也谈不上特别流畅。
- 打包强依赖网络: 每次打包都需要稳定且快速的“科学上网”环境,因为它需要从 GitHub 下载模板。网络稍有波动,就可能前功尽弃。
- 代码“裸奔”: 打包生成的应用代码竟然是明文!多次尝试对 Python 代码进行混淆加密,结果要么打包失败,要么应用无法正常运行,安全性堪忧。
既然 Flet 本质上也是 Flutter 的一层封装,何不直接拥抱原生 Flutter 呢?于是,我决定使用 Dart 语言配合 Flutter 框架重写整个应用。尽管我对 Dart 语言完全陌生,但在 AI 的辅助下,应用的复现速度远超预期。然而,新的“坑”也接踵而至……

Flutter 的光芒:重写后的显著优点
尽管过程曲折,但 Flutter 带来的提升是实实在在的:
- 极致的包体优化: 同样的应用,使用 Flutter 打包后,APK 体积骤降至不足 20MB,EXE 文件也大幅缩小。在真机上运行,如丝般顺滑。
- 美观简洁的UI: Flutter 带来的界面美感远超 Flet,整体风格更为现代和专业。
- 自带代码混淆: 打包时 Flutter 会自动进行代码混淆,虽然对于顶尖高手来说反编译仍有可能,但相比之前的明文代码,安全性已有了质的飞跃。
Flutter 的“另一面”:那些不得不面对的缺点
当然,Flutter 也并非完美无瑕:
- 依赖“全家桶”依旧: Android Studio、Flutter SDK、特定版本的 JAVA……这些依赖一个都不能少,环境配置依然是个不小的挑战。好在之前折腾 Flet 时已经装过一遍,算是“经验复用”。
- 网络依赖依旧强烈: 打包过程很大程度上仍需稳定的“科学上网”环境,否则可能耗时极长,甚至因各种网络错误导致打包失败。
- 应用中文名修改“劝退”: 想要给应用设置一个优雅的中文显示名称?Flutter 会让你体验到什么叫“麻烦”。
“坑”中求生:我的 Flutter 避坑指南
接下来,详细说说我遇到的一些典型问题以及对应的解决方案。
1. Gradle 镜像配置:为国内开发者续命
Flutter 项目在构建 Android 应用时,需要通过 Gradle 下载大量依赖。官方默认的下载服务器位于国外,国内访问速度缓慢,甚至无法连接,导致构建失败是家常便饭。配置国内镜像是提升构建效率的关键。
注意: 以下修改方法适用于 Flutter 3.29.0 以下版本,更高版本可能存在差异。另外,强烈不推荐使用某些不够稳定的镜像源,以免遭遇不明原因的下载封禁,例如 Python pip 清华安装源被封禁下载 。
Gradle,作为 Android 项目中广泛使用的构建自动化工具,其依赖管理和下载机制对构建速度有直接影响。
1.1 修改 android/build.gradle
进入项目根目录下的 android/build.gradle 文件,在 allprojects -> repositories 中添加国内镜像源。请务必保留 google() 和 mavenCentral() 作为备用,因为部分依赖可能镜像源尚未同步。
allprojects {
repositories {
// 添加国内镜像,例如阿里云
maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/spring/'}
maven { url 'https://maven.aliyun.com/repository/google/'}
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/'}
maven { url 'https://maven.aliyun.com/repository/spring-plugin/'}
maven { url 'https://maven.aliyun.com/repository/grails-core/'}
maven { url 'https://maven.aliyun.com/repository/apache-snapshots/'}
maven { url 'https://storage.flutter-io.cn/download.flutter.io' } // Flutter 官方中国镜像
google()
mavenCentral()
}
}
// 以下内容通常已存在,确认即可
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
1.2 修改 android/gradle/wrapper/gradle-wrapper.properties
打开 android/gradle/wrapper/gradle-wrapper.properties 文件,修改 distributionUrl 的值为国内镜像地址。关键点: 替换后的 gradle-X.X-all.zip 版本号必须与替换前保持一致。
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
// 例如,使用腾讯云的 Gradle 镜像,确保 gradle-8.5-all.zip 是你项目当前需要的版本
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.5-all.zip
1.3 修改 android/settings.gradle
打开 android/settings.gradle 文件,在 pluginManagement -> repositories 中同样添加国内镜像源。
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
// 国内镜像源
maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://storage.flutter-io.cn/download.flutter.io' } // Flutter 官方中国镜像
// 原始源备用
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
// 注意:这里的 com.android.application 和 org.jetbrains.kotlin.android 版本可能需要根据你的项目调整
id "com.android.application" version "8.1.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}
include ":app"
重要提示:
- 即便配置了国内镜像,构建过程中 Flutter 仍可能尝试连接 Google 服务器下载一些资源(约100MB+),具体内容待查。这意味着完全离线或网络不佳时仍可能遇到问题。
- Java 版本与 Gradle 版本之间存在严格的对应关系,务必查阅 Gradle 官方文档,确保二者兼容,否则构建必定失败!
2. 应用图标与多平台显示名称定制
Flutter 默认使用内置图标,且应用名称取自根目录 pubspec.yaml 文件中的 name 属性。此 name 属性有格式限制(通常是小写英文字母+下划线),直接修改为中文会导致错误。
2.1 修改应用图标
推荐使用 flutter_launcher_icons 插件来方便地生成各平台图标。
首先,在 pubspec.yaml 文件中添加依赖:
name: yun_ying_xiao_liu_ren # 项目名称,保持英文+下划线
description: "A DaoJia Xiaoliuren project."
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ^3.5.4 # 根据你的 Flutter SDK 版本调整
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
intl: ^0.20.2 # 你项目中可能用到的其他依赖
chinese_lunar_calendar: ^1.0.4 # 你项目中可能用到的其他依赖
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter_launcher_icons: "^0.14.3" # 添加图标生成器依赖
flutter_launcher_icons:
# 安卓图标路径
image_path_android: "assets/images/icon-710x599-android.png"
# iOS 图标路径
image_path_ios: "assets/images/icon-1024x1024.png"
android: true # 为 Android 生成图标
ios: true # 为 iOS 生成图标
# Android 8.0+ 适应性图标设置
adaptive_icon_background: "assets/images/adaptive_icon_background.png" # 替换为你的背景图路径
adaptive_icon_foreground: "assets/images/adaptive_icon_foreground.png" # 替换为你的前景图路径
adaptive_icon_foreground_inset: 16
# Android 13+ 单色图标
adaptive_icon_monochrome: "assets/images/icon-monochrome-432x432.png"
min_sdk_android: 21
remove_alpha_ios: true
background_color_ios: "#ffffff"
# Web 图标设置
web:
generate: true
image_path: "assets/images/icon-1024x1024.png"
# background_color: "#hexcode" # 可选
# theme_color: "#hexcode" # 可选
# Windows 图标设置
windows:
generate: true
image_path: "assets/images/icon-1024x1024.png"
icon_size: 48 # 可选 48-256
# macOS 图标设置
macos:
generate: true
image_path: "assets/images/icon-1024x1024.png"
flutter:
uses-material-design: true
# 确保你的图标资源已添加到 assets 并在 pubspec.yaml 中声明
assets:
- assets/images/ # 假设你的图标都在这个目录下
修改 pubspec.yaml 后,在项目根目录运行以下命令来获取依赖并生成图标:
flutter pub get
dart run flutter_launcher_icons
注意: 如果后续更换了图标文件,务必重新运行 dart run flutter_launcher_icons 命令,否则新图标不会生效。
2.2 修改 APK 显示名称 (Android)
进入项目目录 android/app/src/main/AndroidManifest.xml 文件。
找到 <application> 标签,修改其中的 android:label 属性值。这里的值将决定应用在安装过程和安装后在手机上显示的名称。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="卦灵·云缨-道家小六壬" <!-- 修改这里为你想要的中文名称 -->
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon"> <!-- launcher_icon 通常由 flutter_launcher_icons 生成 -->
<!-- ... 其他配置 ... -->
</application>
<!-- ... 其他配置 ... -->
</manifest>
2.3 修改 Windows 版本显示名称及 .exe 文件属性
- 窗口标题:
进入项目目录 windows/runner/main.cpp 文件。
找到类似以下代码片段,将 L"" 中的内容修改为你想要的中文名称:
if (!window.Create(L"卦灵·云缨-道家小六壬", origin, size)) { // 修改这里的 L"" 中的内容
return EXIT_FAILURE;
}
巨坑警告: 直接修改并保存 main.cpp 后,如果包含中文字符,在编译时很可能会因为文件编码问题导致失败。解决方案: 使用支持多种编码的编辑器(如 VS Code, Notepad++)打开 main.cpp 文件,将其另存为 UTF-8 编码格式,然后再进行编译打包。
- EXE 文件属性:
进入项目目录 windows/runner/Runner.rc 文件 (这是一个资源脚本文件)。
找到 BLOCK "StringFileInfo" 部分,修改其中的 VALUE 字段,特别是 FileDescription、InternalName、OriginalFilename、ProductName。
// ... (VS_VERSION_INFO 等内容保持不变) ...
BEGIN
BLOCK "StringFileInfo"
BEGIN
// 语言代码和字符集,040904e4 代表美国英语,UTF-16。
// 如果主要面向中文用户,理论上可以研究使用中文对应的代码页,
// 但通常保持默认,通过修改字符串值即可。
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "Rewrite.Zeroth" "\0" // 你的公司或组织名
VALUE "FileDescription", "卦灵·云缨-道家小六壬" "\0" // 文件描述
VALUE "FileVersion", VERSION_AS_STRING "\0" // 版本号,通常自动管理
VALUE "InternalName", "卦灵·云缨-道家小六壬" "\0" // 内部名称
VALUE "LegalCopyright", "Copyright (C) 2025 Rewrite.Zeroth. All rights reserved." "\0"
VALUE "OriginalFilename", "卦灵·云缨-道家小六壬.exe" "\0" // 原始文件名
VALUE "ProductName", "卦灵·云缨-道家小六壬" "\0" // 产品名称
VALUE "ProductVersion", VERSION_AS_STRING "\0" // 产品版本
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252 // 0x0409 = English (United States), 1252 = Windows Latin-1
END
END
其他平台(如 iOS、Linux、macOS)的打包部署,待我后续有需求实践后再进行补充。
总结
从 Flet 迁移到 Flutter,就像是从一条满是石子的小路拐进了一条铺设更好的柏油路,虽然路面平整了不少,但偶尔还是会遇到减速带和需要绕行的小坑。Dart + Flutter 带来了性能、体积和UI上的显著提升,但也对开发环境和网络环境提出了新的要求。希望我趟过的这些坑,能为后来者提供一些参考,让大家的 Flutter 之旅更加顺畅。
Flutter 常用更新与打包命令一览
在日常的 Flutter 开发中,以下命令会经常用到:
获取/更新项目依赖:
flutter pub get
当你修改了 pubspec.yaml 文件中的依赖项,或者需要拉取最新的依赖包时执行此命令。
检查过时依赖与升级:
flutter pub outdated # 检查哪些依赖有新版本flutter pub upgrade # 升级所有依赖到兼容的最新版本
清理构建产物:
flutter clean
当遇到一些莫名其妙的构建问题时,尝试清理旧的构建缓存可能会有帮助。
运行应用 (调试模式):
flutter run
此命令会在连接的设备或模拟器上以调试模式运行你的应用,支持热重载 (Hot Reload) 和热重启 (Hot Restart)。
重新生成应用图标 (如果使用了 flutter_launcher_icons):
dart run flutter_launcher_icons
修改图标配置或源文件后,务必执行此命令。
构建 Android 发布版 APK:
flutter build apk --release
这会生成一个用于发布的、经过优化和签名的 APK 文件 (如果配置了签名)。默认输出路径为 build/app/outputs/flutter-apk/app-release.apk。
对于需要增强代码安全性的发布,可以使用以下命令进行代码混淆并分离调试信息:
flutter build apk --obfuscate --split-debug-info=/outputs/symbols/android
--obfuscate: 对 Dart 代码进行混淆,增加反编译难度。
--split-debug-info=<输出目录>: 将调试信息(用于符号化堆栈跟踪)分离到指定目录,减小 APK 体积,同时保留事后分析 Crash 的能力。请确保将 <输出目录> 替换为你期望存放调试符号的路径。
构建 Android App Bundle (AAB):
flutter build appbundle --release
AAB 是 Google Play 推荐的发布格式,可以优化应用大小。输出路径为 build/app/outputs/bundle/release/app-release.aab。
同样,你也可以对 AAB 进行代码混淆和调试信息分离:
flutter build appbundle --obfuscate --split-debug-info=/outputs/symbols/android_bundle
构建 Windows 发布版 EXE:
flutter build windows --release
这会生成一个用于 Windows 平台的发布版本。输出内容在 build/windows/x64/runner/Release 目录下。 对于需要增强代码安全性的 Windows 发布,可以使用以下命令:
flutter build windows --obfuscate --split-debug-info=build/windows/runner/symbols
--obfuscate: 对 Dart 代码进行混淆。
--split-debug-info=<输出目录>: 将调试信息分离到指定目录。请确保将 <输出目录> 替换为你期望存放调试符号的路径。
查看可构建的平台和更多构建选项:
flutter build --help
此命令会列出所有可用的构建目标 (如 ios, linux, macos, web 等) 以及相关的构建参数。
熟练掌握这些命令,将大大提升你的 Flutter 开发和部署效率。
Comments NOTHING