FrameFilm

FrameFilm Ark · Flutter

Flutter 共用界面、Android BLE 桥接与 film / 固件 Wi-Fi Direct 传输。使用 Flutter widgets,不使用 WebView;先在电脑 Web 检查功能和交互,功能集中完成后再编译 Android 并验收实机无线链路,最后统一手机与网页的主题细节。

当前范围

App 统一 WiFi 上传(当前开发)

Android App 的文件上传统一使用 Wi-Fi Direct:Frame(含批量)、Film 和动画使用既有 film 直传,固件升级使用 WiFi OTA,通行证位图及 JSON 使用新增的指定路径文件直传。BLE 保留连接、控制、状态查询与资料回读。ForFilm 网页上传保持 BLE,未增加 WiFi 上传入口。

通行证要求固件 0x59 能力 bit1;不支持时提示先升级固件,不自动退回 BLE。App 依次上传 app/pass/profile.bin、app/pass/profile.json,逐个等待设备保存与网络清理,再回读 JSON 核对。两文件不是原子事务;中断会显示部分完成状态,“重试上次上传”使用缓存从第一份文件重传。临时文件在替换、成功或退出后释放,进程重启清理遗留缓存。编译与模拟测试不代表真实 WiFi/SD/屏幕验收。

本轮验证:通行证取消、重试和清理未确认时的恢复入口共 3 项 Flutter 测试通过;通行证上传与 Film/OTA 页面隔离测试通过;原始文件 HTTP 字节及路径 host probe 通过;ESP-IDF 5.5.2 固件构建通过。Android 使用当前 Flutter Gradle wrapper 检查 arm64 Kotlin 编译,未打包或安装 APK。实机仍需同时更新 App 与固件后验证两文件上传、取消与重试。

结构与复用

Android 9 兼容性

最低 Android 9(API 28)。Android 9 使用公开旧版 createGroup(channel, listener),读取系统生成的名称和密码;系统不提供强制指定或查询组频段的公开 API,若当前 5GHz Wi-Fi 使 Ark 无法连接,请先断开该 Wi-Fi 后重试。Android 10 及以上使用可明确指定 2.4GHz 的接口。蓝牙扫描和旧版直连需要定位授权,部分系统还需要开启定位服务。

直传准备阶段不再发送切换图片 app 的命令,避免先重放旧图。固件保存时按帧数归入图片/动画目录;已处在相应内容页时由固件已有保存事件刷新,其他页面保持原画面。Android 9 尚需对应系统的实机验证,当前连接手机报告 Android 17。

参考:Android Wi-Fi Direct API、API 29 起支持指定频段。

工具链与命令

本轮使用 Flutter stable 3.47.6 / Dart 3.13.5。Android compile/target SDK 35、minSDK 28(Android 9)、JVM 17;Release 包名 org.framefilm.ark.flutter;显式 debug 构建包名 org.framefilm.ark.flutter.dev。Release/AOT APK 使用独立发行签名,本机配置在 D:\FrameFilm-signing\key.properties,可通过 FRAMEFILM_SIGNING_PROPERTIES 覆盖路径。密钥与密码不进入代码仓库,需安全备份;本机和 GitHub Actions 使用同一密钥。旧 debug 签名正式包无法直接覆盖升级,开发包可并行保留。配置方式见 自动构建说明。

本机大型依赖与构建目录已经迁到 D 盘,原 C 盘入口保留 Windows 目录联接(junction)。没有更改系统 PATH,也没有迁移整个 .codex/worktrees:其他工作树仍有正在运行的程序和未提交内容。

内容 本机实际位置
Flutter SDK D:\dev-tool\FrameFilm-toolchains\flutter
Android SDK / NDK D:\dev-tool\Android\Sdk
Gradle 缓存与分发包 D:\dev-tool\gradle-home
Dart Pub 缓存 D:\dev-tool\pub-cache
当前 Flutter 构建输出 D:\dev-tool\FrameFilm-build\flutter
本构建入口的临时文件 D:\dev-tool\FrameFilm-build\temp
当前 Ark 固件 build D:\dev-tool\FrameFilm-build\firmware-ark

从仓库根目录使用入口脚本。它为本次命令设置 SDK、缓存与 TEMP/TMP,命令结束后恢复进程环境;自动维护忽略的 local.properties。执行 clean 删除 build 联接后,下次使用入口会重建联接,防止输出重新落到 C 盘。

$env:JAVA_HOME = 'C:/Program Files/Java/jdk-25' # 本机安装路径;其他电脑使用自己的兼容 JDK
./app/flutter_app/tool/flutter.ps1 pub get
./app/flutter_app/tool/flutter.ps1 analyze --no-pub
./app/flutter_app/tool/flutter.ps1 test --no-pub test/widget_test.dart
./app/flutter_app/tool/flutter.ps1 build web --debug --no-pub
./app/flutter_app/tool/flutter.ps1 build apk --release --target-platform android-arm64 --no-pub

这组 D 盘路径是当前电脑的开发配置,不是项目运行依赖。其他电脑可以按标准 Flutter 命令构建;也可以用 FRAMEFILM_DEV_ROOT 指定同结构存储目录。不同 checkout 应使用独立存储根目录,避免共享构建输出。已有非联接的 build 目录需要先迁移,脚本不会自动删除。Ark 的 build 联接如被 fullclean 删除,也需要重新创建或用 idf.py -B <D盘目录> 指定输出位置。

浏览器预览从 build/web 启动静态服务,本机地址 http://127.0.0.1:8770/。默认仅查看界面;点击“进入模拟设备演示”,或直接打开 http://127.0.0.1:8770/?preview=1,可使用同一份页面操作内存模拟设备。Android 默认不会进入模拟模式。

./app/flutter_app/tool/flutter.ps1 build web --debug --no-pub
python -m http.server 8770 --bind 127.0.0.1 --directory D:/dev-tool/FrameFilm-build/flutter/web

模拟模式顶部始终显示“模拟设备 / 演示数据,不会连接或修改真实设备”。连接页扫描并连接模拟 Ark 后,在 Film 页选择演示文件并直传,或到设置页选择演示固件并检查升级;无需连接手机或 Ark。

演示文件仅为内存元信息,不读取本地文件,不发送真实 BLE/WiFi/OTA 命令。模拟验证用于页面与状态交互,不代表硬件功能通过;真实文件解析、权限、蓝牙、Wi-Fi Direct 和 Flash 升级仍需 Android 构建及实机验收。动画编辑和高级图片算法仍是后续功能。GitHub 在线固件功能见下节。

验证记录(2026-10-08)

第二阶段:film 直传与 CI

保存故障定位补充(2026-10-08)

当前结论:WiFi 保存错误已在下述 PSRAM 修复版实机复测通过。以下先保留定位过程的历史记录,最终结果见本节末尾。

最终修复:WiFi 接收缓冲避开 RTC FAST

实体显示验收(2026-10-08)

WiFi 固件 OTA(本地开发,未推送)

下一步

  1. 继续完成功能后,再按现有网页统一手机 UI。
  2. 完成通行证头像、代号、编号、所属、签名与 SD 读写,增加草稿持久化。
  3. 迁移图片转换与高级动画功能;后台保持、进程恢复与长时间稳定性另行验证。

可交互 Web 演示验证(2026-10-08)

GitHub 在线固件(2026-10-08,本地实现)

设置 → 固件升级 → 检查 GitHub 发布。客户端无登录访问固定公开仓库 kirmisaki/FrameFilm(下载地址兼容旧 Rafael-Ikaros/FrameFilm、Rafael-ban/FrameFilm),在最近20个正式发布中选择包含精确 frame_film_ark.bin 的最新发布时间;忽略草稿和预发布,不比较版本字符串大小。没有适用发布、403/429、网络失败都显示可重试状态,不伪造“有更新”。

Android 点击“下载并校验”后流式保存到临时缓存,显示进度并可取消。限制4MiB及声明长度,若资产提供 SHA256则核对,再复用 ArkFirmware.inspect 检查原始ESP32-S3应用镜像和Ark项目身份。成功才替换导入文件;失败、取消和关闭会清理临时副本,保留原导入。下载完成不会自动刷机,仍需连接Ark并点击“检查并升级”,由原流程比对ELF指纹。下载需手机能够访问GitHub,后续手机至Ark仍使用WiFi直传,无需设备接入路由器。

Web真实查询可用,普通Web不提供原生下载与刷机。模拟设备模式独立提供“演示在线固件”,演示下载、取消、失败后重新下载及完成导入;持续模拟标识仍保留。真实查询返回空列表不会自动替换成演示发布。

设备设置与页面状态隔离(2026-10-09)

C5 早期简化转换记录(已由下方 C6 迁移实现替代)

Frame → 选择图片 → 调整构图与色彩 → 生成 film。转换使用 Flutter/Dart 的同一份实现,Web 下载的文件与 Android 导入传输的文件使用相同编码。

以 ForFilm 为基准的迁移状态(2026-10-09,C7)

Flutter 按 tools/ForFilm 的页面职责迁移,原网页不变。Frame 保留拾光、定影、一言、批量四入口;Film 保留图片处理、预览与输出。WiFi 直传、取消重试、OTA 与构建指纹、GitHub 固件获取、通行证和设备设置继续保留。

功能 当前实现 验证边界与差异
Frame 四入口、自动增强、相机、在线/自定义一言、批量转换发送 批量仍经现有 WiFi 逐张显示;不是旧 BLE 静默整批上传
Film 原图构图、拖动缩放、四方向旋转、输出命名、下载/发送;桌面左参数/输出、右预览 保留 MonoFast、亮度与铺满扩展选项
高级算法 自适应、55 色 ColorFast、46 色 ColorQual、SZ 增强、Atkinson SZ 校色 使用原版算法与色板;自适应缩略图采用双线性,浏览器 medium 采样边界可能导致候选差异
动画工坊 图片/GIF/相机、帧复制删除排序、逐帧构图与同步、画笔/橡皮/填充/取色/撤销、镜像与洋葱皮、设备色预览、多帧 film 导出发送、播放参数 48 帧;发送上限 2.5 MiB。原生相机逐张拍摄、自由画布不同于原 Web 常驻相机流与低分辨率像素格
设备文件 读取当前目录、图片/动画目录切换、显示、删除确认、错误与空态 目录切换通过 app 切页实现,有明确提示;协议不支持任意目录;ID 回读不表示屏幕已刷新
主题 原 ForFilm 奶油底/硬边/彩色卡片,Ark 黑灰方形面板/黑白按钮;跨页面统一控件、导航及连接入场 Flutter 字体与原生控件不保证逐像素相同;连接后自动主题规则保持
保存 Web 下载;Android ACTION_CREATE_DOCUMENT 导出到用户选择位置 Android 源码接入,未重新构建 APK 或执行本轮真机验证

算法工具:node app/flutter_app/tool/sync_forfilm_lut.cjs 生成增强 LUT;sync_forfilm_palettes.cjs 生成实测色板;sync_forfilm_sz.cjs 从原 JS AST 生成纯 Dart SZ 数值流程;forfilm_algorithm_fixtures.cjs 生成原 JS 对照测试样例。SZ 不依赖 WebView/JS 引擎。生成器与生成文件一起提交。

46/55 色输出 Film 2.0 8bpp(Format 3/2),预览与文件共享颜色索引;所有格式保留已经实机确认的竖屏逻辑坐标到 720×480 物理排布。动画复用同一转换器,仅拼接主体与更新总字节数/帧数。关闭抖动时,46/55 色仍使用对应色板。

SZ 使用计算时间片控制让出,避免每 32 像素强制 timer 导致 Web 调度延迟。完整 480×720、dart2js O0 独立浏览器验证约 5.9 秒,最大事件循环间隔约 80ms;不是 Android 性能承诺。

本阶段只构建 Web debug。算法源 JS 对照、GIF/多帧编码、绘图填充和设备文件状态使用最小定向测试;Web 模拟连接与真实文件生成分开验收。Android 相机/导出、BLE 文件命令与动画参数下发留到集中 APK 构建和真机验收;不能把 Web 模拟完成称为设备验收。

设置、关于与 App 更新(2026-10-09,C8)

应用内下载入口(2026-10-16)

设置 → 应用更新 → 检查更新 → 应用内下载更新 → 打开系统安装器。Android 复用已有 AppUpdateManager 下载 APK,无需跳转 GitHub 网页;下载显示百分比与 MiB,支持取消及从头重试。下载/校验期间暂停检查更新,防止界面上的发布信息与当前下载任务混淆。

Web ?preview=1 的“体验下载流程”提供明确标注的本地演示安装包,可在没有正式 Release 时检查进度、取消、重试、准备安装界面;不会进行真实 APK 下载或安装。真实更新仍须仓库 Release 提供 APK 与 JSON 元数据,且安装包签名与当前 App 兼容。Android 系统安装确认不能由网页模拟验收代替。