Imported from Youfysoon/EasyCompressAssistant (
AGENTS.md). Install upstream withnpx skills add Youfysoon/EasyCompressAssistant. Copyright stays with the author.
Easy Compress Assistant — Agent Guide
本文档供 AI 开发助手阅读。它总结了项目的技术栈、代码结构、构建/测试方式、开发约定和已知限制,帮助助手在不了解项目背景时也能快速进入工作状态。
1. 项目概述
Easy Compress Assistant(极速压缩助手) 是一个基于 Flutter 的跨平台压缩/解压小工具(当前版本 1.2.0,见 pubspec.yaml)。已实现 Android 和 Windows 桌面端的核心功能,iOS/macOS/Linux 目录已生成但功能完善度较低。
核心功能包括:
- 压缩:选择文件或目录生成 ZIP 归档。
- 解压:选择 ZIP 归档解压到指定目录。
- 归档浏览:新建/打开 ZIP,在树形目录中增删文件、创建目录、保存/另存为。
- 快速压缩(Android Only):通过系统分享入口一键压缩并发送,压缩在后台前台 Service 中执行并显示进度通知。
- 快速解压(Android Only):通过系统打开方式解压 ZIP 并回到主程序。
- 多语言:支持简体中文和英文,默认中文。
- 设置:缓存管理、自动清理、语言切换、日志查看、关于与开源许可证。
项目采用 BSD 3-Clause License 开源。
2. 技术栈
2.1 运行环境与工具链
| 项目 | 版本/说明 |
|---|---|
| Flutter | 3.38.7 stable |
| Dart | 3.10.7 |
| SDK 约束 | ^3.10.7(见 pubspec.yaml) |
| Android Gradle Plugin | 8.11.1 |
| Kotlin | 2.2.20 |
| Java | 17(sourceCompatibility / targetCompatibility / jvmTarget) |
| CMake(Windows) | >= 3.14 |
| CMake(Linux) | >= 3.13 |
| macOS 最低版本 | 10.15(macos/Podfile) |
2.2 主要依赖(pubspec.yaml)
fluent_ui: 4.13.0:WinUI 3 风格 UI 组件库,项目主要视觉风格来源。archive: ^3.4.10:Dart 端 ZIP 压缩/解压核心库。path_provider: ^2.1.1、path: ^1.8.3:跨平台路径与目录管理。file_selector: ^1.0.3:桌面端文件/目录选择器。permission_handler: ^11.0.1:Android 存储权限申请。shared_preferences: ^2.2.2:本地配置持久化(语言、自动清理缓存等)。flutter_local_notifications: ^17.2.1:系统通知。url_launcher: ^6.2.5:打开外部链接(GitHub)。desktop_drop: ^0.4.4:桌面端文件拖拽。window_manager: ^0.5.1:桌面端窗口管理(大小、居中、标题)。flutter_launcher_icons: ^0.14.4:生成各平台图标。flutter_lints: ^6.0.0(dev):Dart/Flutter 静态检查规则。
2.3 字体与资源
- 应用字体:
MiSans(assets/fonts/MiSans-Regular.ttf)。 - 图标源:
assets/icon/icon.png,由flutter_launcher_icons.yaml配置生成。 - 二维码资源:
assets/images/qr_code.png(用于设置页赞助对话框)。
3. 项目结构
H:/EasyCompressAssistant/easy_compress_assistant
├── android/ # Android 原生代码与配置
│ ├── app/build.gradle.kts
│ └── app/src/main/kotlin/com/youfy/easy_compress_assistant/
│ ├── MainActivity.kt # 注册各 MethodChannel 插件
│ ├── FilePickerPlugin.kt # 文件选择 MethodChannel
│ ├── SharePlugin.kt # 分享/保存 MethodChannel
│ ├── QuickCompressPlugin.kt # 快速压缩 MethodChannel
│ ├── QuickCompressActivity.kt # 系统分享入口 Activity
│ ├── QuickCompressService.kt # 快速压缩前台 Service(进度通知+取消)
│ └── QuickExtractActivity.kt # 系统打开方式入口 Activity
├── ios/ # iOS 工程(未充分验证)
├── macos/ # macOS 工程(AppDelegate.swift 含 file_icon_plugin 处理)
├── linux/ # Linux 工程(未充分验证)
├── windows/ # Windows 工程(CMake + runner)
│ └── plugins/file_icon_plugin/ # 系统文件图标 C++ 插件
├── lib/ # Flutter 主工程代码
│ ├── main.dart # 应用入口、主题、导航、语言状态
│ ├── Pages/ # 页面层(Page Widgets)
│ │ ├── home_page.dart
│ │ ├── compress_page.dart
│ │ ├── decompress_page.dart
│ │ ├── quick_extract_page.dart
│ │ ├── archive_browser_page.dart
│ │ ├── result_page.dart
│ │ ├── settings_page.dart
│ │ ├── logs_page.dart
│ │ └── license_page.dart
│ ├── services/ # 业务服务层
│ │ └── archive_service.dart
│ ├── utils/ # 工具与数据层
│ │ ├── compression_util.dart # ZIP 压缩/解压核心
│ │ ├── archive_browser_backend.dart # 归档浏览状态与 IO 管理
│ │ ├── archive_browser_controller.dart # 页面间命令控制器
│ │ ├── archive_tree.dart # 归档树结构构建
│ │ ├── archive_formats.dart # 归档格式枚举与文件名工具
│ │ ├── app_config.dart # 缓存/配置目录路径
│ │ ├── app_data_util.dart # 存储权限与目录辅助
│ │ ├── storage_settings.dart # 缓存设置管理
│ │ ├── language_settings.dart # 语言设置管理
│ │ ├── native_file_picker/ # 跨平台文件选择封装
│ │ ├── file_selector_util.dart
│ │ ├── file_icon_provider.dart # 系统图标获取(Windows/macOS)
│ │ ├── quick_compress_util.dart
│ │ ├── notification_util.dart
│ │ ├── logging.dart
│ │ └── utils.dart # 导出 Barrel 文件
│ ├── models/ # 数据模型
│ │ └── archive_entry.dart
│ ├── widgets/ # 可复用 UI 组件
│ │ ├── responsive_navigation.dart
│ │ └── file_icon_widget.dart
│ ├── l10n/ # 本地化
│ │ └── app_localizations.dart
│ └── assets/fonts/ # 字体(资源声明在 pubspec.yaml)
├── test/ # 测试
│ ├── utils/compression_util_test.dart
│ ├── utils/sanitize_test.dart
│ └── widget_test.dart
├── pubspec.yaml
├── analysis_options.yaml
├── flutter_launcher_icons.yaml
├── devtools_options.yaml
├── README.md
├── AGENT.md # 项目现状说明(另一份参考文档,中文)
├── archiveBrowser.md # 归档浏览页设计意图(中文)
├── AndroidDirResearch.md # Android 目录机制调研笔记
├── FlutterSharedPreferences.md
└── issue # 临时问题记录(FileIconProvider 报错日志)
4. 架构与分层
项目按以下分层组织,目标是让页面尽量只负责交互,业务/文件/压缩逻辑下沉:
- 页面层(
lib/Pages/):展示 UI、收集用户输入、触发操作。通过InfoBar进行反馈。 - 业务服务层(
lib/services/):将页面意图封装为可复用行为。ArchiveService是压缩/解压的轻量封装。 - 工具与数据层(
lib/utils/):处理文件系统、压缩格式、路径清理、配置、通知等基础逻辑。 - 数据模型层(
lib/models/):ArchiveEntry描述归档中的文件/目录条目。
4.1 关键协作关系
MainApp使用ResponsiveNavigation组织首页、设置页、归档浏览页(宽屏左侧导航、窄屏底部导航)。- 首页通过
ArchiveBrowserController向ArchiveBrowserPage发出“新建归档”或“打开归档”命令。 ArchiveBrowserPage只负责 UI/交互,实际文件系统与压缩 IO 由ArchiveBrowserBackend(ChangeNotifier 单例)管理。ArchiveBrowserBackend调用ArchiveService->CompressionUtil完成压缩/解压。- 文件选择在移动端走
MethodChannel调用原生FilePickerPlugin;桌面端使用file_selector。 - Android 端
QuickCompressActivity接收系统分享 intent 后,把压缩工作交给QuickCompressService(前台 Service,dataSync类型)执行,压缩完成后弹出分享;QuickExtractActivity处理系统“打开方式”解压 intent。
5. 构建、运行与测试命令
5.1 常用命令
# 获取依赖
flutter pub get
# 静态分析
flutter analyze
# 运行测试
flutter test
# 运行到当前平台(默认)
flutter run
# 运行到 Windows
flutter run -d windows
# 运行到 Android
flutter run -d android
# 构建 Windows 发布包
flutter build windows --release
# 构建 Android APK
flutter build apk --release
# 构建 Android App Bundle
flutter build appbundle --release
# 生成图标(修改 flutter_launcher_icons.yaml 后执行)
flutter pub run flutter_launcher_icons
5.2 验证状态(截至 2026-07-21)
flutter analyze:No issues found。flutter test:全部通过(共 7 个测试)。
注:当前 Flutter 版本为
3.38.7。如果升级 SDK,请先运行flutter analyze和flutter test,因为依赖版本锁定在pubspec.lock中,升级可能引入破坏性变更。
6. 代码风格与开发约定
6.1 静态检查
analysis_options.yaml仅包含include: package:flutter_lints/flutter.yaml。- 请保持
flutter analyze零警告。新增代码若必须抑制警告,应在相关行上方明确说明原因。
6.2 命名与语言
- Dart 文件使用
snake_case。 - 类名使用
PascalCase。 - 私有成员/变量使用
_前缀。 - 常量使用
k...或全大写SCREAMING_SNAKE_CASE。 - 注释以英文为主,但允许在复杂逻辑处使用中文补充说明。现有代码中存在中英混合注释(常见“英文注释 + 中文翻译”成对出现),新增代码应保持与周围一致。
6.3 文件组织
- 页面放
lib/Pages/,工具类放lib/utils/,模型放lib/models/,服务放lib/services/,可复用 UI 放lib/widgets/。 - 使用
utils.dart作为 barrel 导出文件,但不要循环依赖。 - 不要把文件系统 IO 或压缩逻辑直接写到 Page 里,应下沉到
utils/或services/。
6.4 本地化
- 项目使用手写
AppLocalizations(lib/l10n/app_localizations.dart),未使用flutter gen-l10n生成.arb文件。 - 新增界面文案必须同时补充
zh和en两套映射,避免硬编码。 - 通过
context.l10n.tr('key')访问。不要在 UI 中直接写死中文或英文。 - 当前已知缺失键:
settings_view_logs、settings_view_logs_desc(logs_page.dart与settings_page.dart引用但AppLocalizations未定义)。
6.5 状态管理
- 当前主要使用
StatefulWidget+ChangeNotifier(ArchiveBrowserBackend、ArchiveBrowserController)。 - 页面间少量数据通过
ModalRoute.arguments或共享单例传递。 - 没有使用
Provider、Riverpod或Bloc,除非确有需求,否则不要引入新的状态管理库。
7. 测试策略
7.1 现有测试
test/utils/compression_util_test.dart:验证compressFile/compressFiles与extractArchive的往返正确性,以及空列表抛异常。test/utils/sanitize_test.dart:验证路径清理与compressEntries的归档路径归一化(反斜杠转正斜杠)。test/widget_test.dart:仅包含sanitizeFilePath基础用例。
7.2 测试命令
flutter test
7.3 建议补充的测试方向
- 归档树构建(
ArchiveTree)对嵌套目录、空列表、重复路径的处理。 ArchiveBrowserBackend的新建/打开/保存/删除状态流转(可结合临时目录隔离)。- 路径清理对 Windows 非法字符、跨平台分隔符的处理。
- 加密 ZIP 的密码提示分支(当前通过异常字符串判断,容易受库版本影响)。
- 大文件/大目录下 UI 不卡顿的异步行为(可通过 mock 或控制数据量测试)。
8. 安全与权限注意事项
8.1 文件路径安全
CompressionUtil._sanitizeFilePath会清理归档内路径中的非法字符(< > : " | ? *)和尾部点/空格,防止解压到 Windows 非法文件名。- 不要信任用户提供的归档内容,所有解压路径都经过
sanitizeFilePath处理。 - 避免直接将外部传入的
archivePath作为文件名写入,应使用p.basename或ArchiveFileName.ensureExtension。
8.2 Android 权限
- AndroidManifest 声明了
READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE、MANAGE_EXTERNAL_STORAGE(minSdkVersion=30)、POST_NOTIFICATIONS(minSdkVersion=33)、FOREGROUND_SERVICE和FOREGROUND_SERVICE_DATA_SYNC(minSdkVersion=34,快速压缩前台 Service 需要)。 - 主入口通过
AppDataUtil.requestStoragePermission()请求运行时权限,并请求通知权限(Android 13+)。 - 在 Android 10+ 上应继续遵循 Scoped Storage 最佳实践,原生
FilePickerPlugin已使用 SAF(ACTION_OPEN_DOCUMENT/ACTION_OPEN_DOCUMENT_TREE)并将选中文件复制到应用缓存,避免直接操作外部 URI。 QuickCompressActivity对超过 1GB 的选中文件会拒绝压缩,避免 ANR。
8.3 原生 MethodChannel 安全
FilePickerPlugin、SharePlugin、QuickCompressPlugin在MainActivity.configureFlutterEngine中注册。- 参数校验已在原生端进行(如空路径、空文件列表),Flutter 侧调用前同样要做防御性检查。
FileIconProvider通过MethodChannel('file_icon_plugin')获取系统图标:Windows 端由windows/plugins/file_icon_plugin/(C++)实现,macOS 端在macos/Runner/AppDelegate.swift中处理getFileIcon。但仓库根目录的issue文件仍记录有运行时LateInitializationError: Field '_cacheDir' has not been initialized报错(见 11.1)。
8.4 通知
flutter_local_notifications在 Android 上需要通知权限(Android 13+)。初始化失败被捕获为debugPrint,不会阻断应用启动。- Android 14+ 使用
dataSync类型前台 Service 必须声明FOREGROUND_SERVICE_DATA_SYNC权限(已声明)。
9. 平台特定说明
9.1 Android
- 包名:
com.youfy.easy_compress_assistant,当前versionCode=12、versionName=1.2.0(AndroidManifest 与 pubspec 同步维护)。 - 启用 core library desugaring(
flutter_local_notifications需要)。 - 额外依赖:
androidx.documentfile:documentfile:1.0.1(SAF 支持)、com.android.tools:desugar_jdk_libs:2.1.4。 QuickCompressActivity和QuickExtractActivity作为系统外部入口,必须保持exported=true(均设excludeFromRecents/noHistory)。QuickCompressService为exported=false的前台 Service,foregroundServiceType="dataSync",负责在后台执行压缩、显示进度通知并支持取消。- 通过
FileProvider(${applicationId}.fileprovider)分享生成的归档。 - 图标生成后位于
android/app/src/main/res/mipmap*/launcher_icon.png。
9.2 Windows
- 可执行文件名为
easy_compress_assistant.exe。 - 使用
window_manager设置默认窗口大小1000x800、最小500x400、居中。 - 文件图标通过
FileIconProvider+FileIconWidget获取,原生实现位于windows/plugins/file_icon_plugin/(C++),在windows/runner/CMakeLists.txt与flutter_window.cpp中接入;失败时回退到FluentIcons.document。 - 分享按钮在 Windows 上显示为“不支持”。
9.3 iOS / macOS / Linux
- 目录已生成,但尚未作为主力平台验证。
- macOS
Podfile指定platform :osx, '10.15';AppDelegate.swift中处理了file_icon_plugin的getFileIcon。 - iOS
Podfile未指定全局 platform(注释状态),默认跟随 Flutter 模板。 - Linux 依赖 GTK 3 和 PkgConfig。
10. 部署与发布流程
目前项目没有 CI/CD 工作流(.github/ 目录仅有图片资源),发布为手动流程:
- 更新
pubspec.yaml中的version,并同步android/app/src/main/AndroidManifest.xml的versionCode/versionName。 - 运行
flutter pub get。 - 运行
flutter analyze和flutter test,确保无问题。 - 如需更新图标:修改
flutter_launcher_icons.yaml后执行flutter pub run flutter_launcher_icons。 - 构建目标平台:
- Android:
flutter build apk或flutter build appbundle - Windows:
flutter build windows - macOS:
flutter build macos - Linux:
flutter build linux
- Android:
- Android 发布前需要配置正式签名(当前
release使用 debug signingConfig,见android/app/build.gradle.kts)。 - Windows 发布包位于
build/windows/x64/runner/Release/(默认路径)。
11. 已知限制与维护建议
11.1 当前已知限制
- 多语言未完全统一:部分硬编码字符串(如
archive_browser_backend.dart的错误提示、快速压缩相关 Kotlin 文案“一键打包并分享”)尚未全部进入AppLocalizations;settings_view_logs、settings_view_logs_desc键缺失。 - 归档浏览页仍有 UI 逻辑耦合:树形渲染和选择交互仍在
ArchiveBrowserPage内,后续可进一步拆分为独立 widget。 - FileIconProvider 运行时异常:虽然 Windows(C++)与 macOS(Swift)已提供
file_icon_plugin实现,但仓库根目录的issue文件记录了LateInitializationError: Field '_cacheDir' has not been initialized的运行时报错(macOS 沙盒环境),说明_cacheDir初始化时机仍有 bug。 - 解压格式有限:虽然
ArchiveFormat枚举了 7z/tar/rar 等,但当前CompressionUtil实际只支持 ZIP。 - 加密 ZIP 判断脆弱:通过捕获异常并检查
e.toString().toLowerCase()是否包含encrypted/password/unsupported来触发密码输入,容易受archive库版本影响。 - 桌面端未实现系统分享:Windows 分享按钮显示“不支持”,macOS 仅调用
open -R定位文件。 - 大文件压缩:Android 一键压缩超过 1GB 会被拒绝;超大压缩包仍可能触发 ANR,需要流式/异步优化。
- 响应式设计尚未完善:部分强制横屏的竖屏 Android 设备在强制横屏后页面被“压扁”而不是切换为横屏布局(见 README 已知问题)。
11.2 维护建议
- 优先保持跨平台一致性:路径处理、权限、文件选择、拖拽、外部打开行为。
- 继续将页面逻辑下沉到
utils//services/,避免 Page 直接操作文件系统。 - 新增功能前先补充对应测试,尤其是归档树、路径清理、错误路径。
- 统一错误提示:使用
InfoBar+ 本地化键,不要直接写死英文或中文错误文案。 - 考虑将
AppLocalizations迁移到.arb+flutter gen-l10n,以便更好的翻译管理。
12. 快速参考:改动前检查清单
在提交任何改动前,请确认:
-
flutter pub get成功。 -
flutter analyze无错误、无警告。 -
flutter test全部通过。 - 新增 UI 文案已补充
zh和en本地化。 - 涉及文件系统/压缩/权限的改动在 Android 与桌面端都进行了考虑。
- 如修改原生 Kotlin 代码,需同步检查
AndroidManifest.xml权限与 intent filter。 - 不要提交
build/、.dart_tool/、pubspec.lock的无关变更(除非确实升级了依赖)。
最后更新:2026-07-21。若项目结构、依赖或构建方式发生重大变化,请及时更新本文件。
