[Feature] 没有 App 更新通道:版本号无处可见、不检查更新,而缺陷模板却要求必填版本

Closed
#166 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
dart, flutter, github

Research direction

Start with the settings page and its search and section persistence, then read lib/net/ for the existing HttpTransport abstraction and release.yml for version injection. Run the relevant Dart tests and flutter analyze; add coverage for version comparison, update-check failures, and 24-hour throttling. Done means the settings show the injected version and update states, automatic checks are opt-in and do not block startup, and analysis and existing tests pass.

Written by the indexing model from the issue text.

Description

feature needs-human-triage P2 · 中 区域: 凭证与网络 区域: 本地存储 隐私与合规

现状与问题(已核实)

全仓没有任何更新通道,也没有任何地方显示版本号。

  1. lib/ 内不存在版本常量、版本展示或更新检查:检索 版本 / version / update / 升级 / latest 只命中抖音协议的 webcast_sdk_version、updateOverlaySize、以及「我的主题」的 updateMyTheme(#147),没有一处与 App 自身版本有关。
  2. 依赖里也没有可用件:pubspec.yaml 只有 flutter_js / web_socket_channel / crypto / flutter_screen_overlay(本地内联)/ path_provider / flutter_secure_storage,没有 package_info_plus、url_launcher、http。
  3. 版本唯一来源是 pubspec.yaml 的 version: 0.1.0,发布 tag 强校验等于 v + 该值(AGENTS.md 第 7 节、release.yml:59-88);Android 侧 versionName = flutter.versionName(android/app/build.gradle.kts:42),与 pubspec 一致。
  4. 发布产物其实很完整:DanmuFloat-<tag>-arm64-v8a.apk、DanmuFloat-<tag>-universal.apk + SHA256SUMS.txt(release.yml:138-152),Release Notes 由 git-cliff 生成(cliff.toml)。

问题在于这些信息到不了用户:

  • 用户装完 0.1.0 之后,除了自己想起来去 GitHub Releases 页面翻,没有任何通道告诉他「有新版了、修了什么」。而近期合入的恰恰是「悬浮窗菜单白底白字、文字看不见」(#146)、「设置页改样式看不到效果」(#143)、「首页行内信息被按钮挤到只剩 80dp」(#148)这类直接决定能不能用的修复——卡在旧版的用户会一直撞在这些缺陷上,且不会知道已经修了。
  • 反向缺口同样存在:.github/ISSUE_TEMPLATE/bug_report.yml:31-38 把「App 版本」列为必填项,但 App 内任何地方都不显示版本号(设置页 12 个分区里没有「关于」)。报障者只能去系统「应用信息」里翻,或者干脆乱填——这会直接削弱缺陷报告的可分诊性。

期望行为(分三层,按风险递增)

第一层(建议本次做):版本可见 + 检查更新,纯 Dart、零新权限
  1. 设置页新增「关于」分区(放在「诊断」附近,并让 #143 的搜索能命中「版本 / 更新 / 关于」):显示当前版本号、检查更新 按钮、上次检查时间。
  2. 手动检查:GET https://api.github.com/repos/ASDW51/DanmuFloat/releases/latest,读 tag_name / name / published_at / body / html_url / assets[];与当前版本比较;三态结果:
    • 已是最新(显示当前版本);
    • 有新版本(版本号 + 发布时间 + 可滚动的更新说明 + 下载方式);
    • 检查失败(原因 + 重试按钮)。
  3. 自动检查(默认关闭,用户显式开启):低频(建议 ≥24h),落盘 lastUpdateCheckAt;失败静默、不重试风暴;绝不阻塞启动——#86 的教训是启动链路任何异常都必须能走到界面,这里同理:检查挂在首帧之后 unawaited,AppEntry 的加载态与免责声明/引导分流一行不改。
  4. 提醒节流:同一版本只提示一次(落盘 lastNotifiedVersion),用户忽略后不再打扰;「已是最新」不弹窗。
第二层(需先定取舍):怎么把用户带到新版
  • 方案 A(零新依赖,推荐起步):把 APK 下载地址与 SHA256SUMS.txt 地址做成可复制文本,用户自己去浏览器下载。
  • 方案 B(+1 个插件):用 url_launcher 直接打开 Release 页,体验最好;它是纯插件(Android 代码在包内,仓库侧无原生改动),但会新增一个 pub 依赖。
  • 两者都不需要新权限。
第三层(明确不做 / 需单独立项):应用内下载并安装

需要 REQUEST_INSTALL_PACKAGES 权限 + FileProvider + 原生 Intent + 下载进度 + 落盘前 SHA256 校验(crypto 已有)。但本仓库 CI 只跑 Dart(#100「CI 增加 Android/Gradle 编译门禁」至今未落地),原生改动零门禁——这与 UX-24 / UX-25 / UX-26 被否决的理由完全一致。建议先不做,等 #100 落地后再单独评估。

必须先定的实现口径(这条最容易做错)

  1. 版本号从哪来:App 运行时读不到 pubspec.yaml。两条路:
    • 推荐:CI 注入 --dart-define=DANMU_APP_VERSION=<version_name>(release.yml:59-88 已经解析出 version_name,直接传即可),代码用 const String.fromEnvironment('DANMU_APP_VERSION', defaultValue: 'dev');零新依赖,且与 tag 天然一致。同时在 CI 加一条断言「dart-define 必须等于 pubspec 的 version」,防止漂移。
    • 备选:package_info_plus 读 APK 的 versionName(与 manifest 完全一致),代价是多一个依赖 + 平台通道,测试要加替身。
    • 禁止在 Dart 里手写一份版本常量当真相源——AGENTS.md 第 7 节要求 pubspec 是唯一来源,手写常量必然漂移(这正是本轮 #146 那种「规格与实现各说各话」的温床)。
  2. 版本比较:必须处理 v 前缀、+n 构建号(AGENTS.md 规定 tag 去掉 +n)、预发布(1.0.0-beta 应小于 1.0.0)。抽成纯函数,单测覆盖。
  3. 隐私(本项目合规基调下的硬要求):检查更新会向 github.com 发起请求,暴露 IP 以及「有人装了 DanmuFloat」这一事实。考虑到免责声明、#93(禁系统备份外流)、#94(导出二次确认)确立的基调,自动检查必须默认关闭,开关说明里要写明「会访问 github.com」;手动检查首次点击时给一次性说明。
  4. GitHub API 限流:未认证 60 次/小时/IP,日级检查完全够用;403 限流 / 404 / 超时 / 畸形 JSON 一律静默 + debugPrint,不弹窗、不重试。

验收标准

  • 纯函数 compareAppVersions(a, b):0.1.0 < 0.1.1、0.1.0 < 0.2.0、v0.1.0 == 0.1.0、0.1.0+5 == 0.1.0、1.0.0-beta < 1.0.0、垃圾输入不抛。
  • UpdateChecker:注入仓库既有的 HttpTransport(lib/net/ 已有抽象,单测无需真网络)——200 + 合法 JSON 返回 ReleaseInfo;404 / 500 / 超时 / 畸形 JSON / 非 UTF-8 一律返回 null 并记日志、不抛(对齐 #109 的容错口径)。
  • 节流:shouldCheckForUpdate(lastCheckedAt, now, enabled) 纯函数,≥24h 才为真;失败也写时间戳,避免弱网下反复重试。
  • 设置页:显示注入的版本号;检查更新 进行中禁用并显示进度;三态结果各自可达;自动检查开关默认关闭且文案写明会访问 github.com。
  • 启动不阻塞:检查在首帧之后 unawaited 触发;AppEntry 的加载态 / 免责声明 / 引导分流零改动(#86 的回归护栏继续成立)。
  • 零新权限;若采用方案 B 才允许新增 url_launcher,且测试里必须有替身。
  • flutter analyze 保持 No issues found;既有用例零回归。

风险 / 依赖

  • 与 #100(Android 编译门禁)相关但可完全独立:第一层是纯 Dart。
  • 国内网络访问 GitHub 不稳定是常态 → 「失败静默」是硬要求,不能因为查不到更新影响任何主流程或让用户误以为 App 出错。
  • 与 #143(设置页分区折叠 + 搜索)同文件:新分区要能被搜索命中,且折叠状态落盘口径与其它分区一致。
  • 若将来做第三层,需要先有 #100 的 Android 门禁,否则又是一个「原生改动零验证」的黑洞。
Dominant language
Dart
Stars
0
Forks
0
Avg merge
11m
Merged PRs (30d)
127

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ASDW51/DanmuFloat

All issues in ASDW51/DanmuFloat

Similar issues

More Dart issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.