从 Python + Flet 的诸多不便,到拥抱 Dart + Flutter 的焕然一新,再到与新框架的“斗智斗勇”,重写“卦灵·云缨-道家小六壬APP”这款“道家小六壬”的辅助工具,可谓是一段痛并快乐着的旅程。如果你也曾对 Flet 的“全平台”承诺心动过,又或者正在 Flutter 的学习路径上,那么我踩过的这些坑,或许能为你照亮前路。

初衷:为何告别 Flet?

最初选择 Python + Flet,主要是看中了其“一套代码,全平台打包”的宣传。然而,理想很丰满,现实却骨感。Flet 带来的问题远超预期:

  1. 环境配置噩梦: 安装 Android Studio、Flutter SDK 等一系列依赖,过程繁琐,劝退指数极高。
  2. 臃肿的打包体积: 一个功能相对简单的工具类APP,APK 包体竟然接近 90MB,EXE 文件亦然。实际运行起来,也谈不上特别流畅。
  3. 打包强依赖网络: 每次打包都需要稳定且快速的“科学上网”环境,因为它需要从 GitHub 下载模板。网络稍有波动,就可能前功尽弃。
  4. 代码“裸奔”: 打包生成的应用代码竟然是明文!多次尝试对 Python 代码进行混淆加密,结果要么打包失败,要么应用无法正常运行,安全性堪忧。

既然 Flet 本质上也是 Flutter 的一层封装,何不直接拥抱原生 Flutter 呢?于是,我决定使用 Dart 语言配合 Flutter 框架重写整个应用。尽管我对 Dart 语言完全陌生,但在 AI 的辅助下,应用的复现速度远超预期。然而,新的“坑”也接踵而至……

Flutter 的光芒:重写后的显著优点

尽管过程曲折,但 Flutter 带来的提升是实实在在的:

  1. 极致的包体优化: 同样的应用,使用 Flutter 打包后,APK 体积骤降至不足 20MB,EXE 文件也大幅缩小。在真机上运行,如丝般顺滑。
  2. 美观简洁的UI: Flutter 带来的界面美感远超 Flet,整体风格更为现代和专业。
  3. 自带代码混淆: 打包时 Flutter 会自动进行代码混淆,虽然对于顶尖高手来说反编译仍有可能,但相比之前的明文代码,安全性已有了质的飞跃。

Flutter 的“另一面”:那些不得不面对的缺点

当然,Flutter 也并非完美无瑕:

  1. 依赖“全家桶”依旧: Android Studio、Flutter SDK、特定版本的 JAVA……这些依赖一个都不能少,环境配置依然是个不小的挑战。好在之前折腾 Flet 时已经装过一遍,算是“经验复用”。
  2. 网络依赖依旧强烈: 打包过程很大程度上仍需稳定的“科学上网”环境,否则可能耗时极长,甚至因各种网络错误导致打包失败。
  3. 应用中文名修改“劝退”: 想要给应用设置一个优雅的中文显示名称?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 字段,特别是 FileDescriptionInternalNameOriginalFilenameProductName

// ... (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 开发和部署效率。