Skip to content

Commit 54a599b

Browse files
committed
docs: add AGENTS.md — release checklist requires R8 minify install verification before tag
1 parent e2147a5 commit 54a599b

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# GSYGithubAppKotlin 项目协作规约
2+
3+
供 AI Agent / 协作开发者执行任务时遵循。本文件随项目演进持续维护。
4+
5+
---
6+
7+
## 1. 发布流程(强制)
8+
9+
> **核心原则:R8 编译通过 ≠ 运行时安全。任何 release tag 推送之前,必须装机回归核心路径。**
10+
11+
### 1.1 发版前置条件
12+
13+
发起一次正式版本发布(推送 `vX.Y.Z` tag)之前,**必须**全部满足:
14+
15+
1. **版本号已升级**:在 [app/build.gradle](file:///d:/workspace/project/GSYGithubAppKotlin/app/build.gradle#L20-L21) 同步升级 `versionCode``versionName`,不允许只改其中一个。
16+
2. **CI 编译通过**`master` 上最近一次 push 的 CI / Release workflow 已绿(含 R8 minify、shrinkResources、签名)。
17+
3. **Release APK 已装机回归**(见 1.2)。
18+
4. **变更说明已就绪**:commit 信息或 release notes 清晰描述本次变更,特别是 ProGuard 规则、依赖、`targetSdk`、签名、`<queries>` 等敏感面变更。
19+
20+
### 1.2 装机回归 Checklist(必跑)
21+
22+
从 GitHub Release(或 CI artifact)拉到 release 签名版 APK 后,在真机上至少完成以下 5 项:
23+
24+
| # | 场景 | 验证点 |
25+
|---|---|---|
26+
| 1 | 冷启动 | `topResumedActivity` 落到 `MainActivity`;logcat 无 `FATAL` / `AndroidRuntime` 异常;无 `NoClassDefFoundError` / `Init provider failed` |
27+
| 2 | 推荐 / 趋势 Tab | 仓库卡片、头像渲染正常(验证 Retrofit + OkHttp + Glide 在 minify 下工作) |
28+
| 3 | 仓库详情页 | ARouter 跳转可达,4 tab(详情/动态/文件/Issues)切换不崩;fork/watch/star 按钮可响应 |
29+
| 4 | "我的"页面 | 用户信息 + 贡献热力图渲染(验证 SimpleXML / HTML 解析路径) |
30+
| 5 | 侧边栏「版本更新」→ 浏览器跳转 | 能正确拉起浏览器到 [releases/latest](https://github.com/CarGuo/GSYGithubAppKotlin/releases/latest)(验证 [AndroidManifest.xml](file:///d:/workspace/project/GSYGithubAppKotlin/app/src/main/AndroidManifest.xml#L13-L24)`<queries>``targetSdk` 36 下生效 + [browse()](file:///d:/workspace/project/GSYGithubAppKotlin/app/src/main/java/com/shuyu/github/kotlin/common/compat/AnkoCompat.kt#L25-L45) 健壮性) |
31+
32+
只要任一项失败,**禁止打 tag**;先修代码 / 调 ProGuard,重新过 CI 后回到本流程。
33+
34+
### 1.3 装机回归操作流程(命令模板)
35+
36+
```powershell
37+
# 1. 拉 Release APK(或从 workflow artifact)
38+
$env:GH_TOKEN = "<PAT>"
39+
gh release download vX.Y.Z -R CarGuo/GSYGithubAppKotlin -p "app-release.apk" -D build/release-test --clobber
40+
41+
# 2. 装机
42+
adb uninstall com.shuyu.github.kotlin
43+
adb install -r build/release-test/app-release.apk
44+
45+
# 3. 启动 + 抓 FATAL
46+
adb logcat -c
47+
adb shell am start -n com.shuyu.github.kotlin/.module.StartActivity
48+
Start-Sleep -Seconds 6
49+
adb logcat -d *:E | Select-String -Pattern "AndroidRuntime|FATAL|Caused by|com\.shuyu\.github"
50+
51+
# 4. 确认前台 Activity
52+
adb shell dumpsys activity activities | Select-String "topResumedActivity"
53+
54+
# 5. 截图回归(核心 5 个页面)
55+
adb exec-out screencap -p > build/release-test/screen-XX.png
56+
```
57+
58+
### 1.4 Tag 推送规则
59+
60+
- 一次 tag 对应一个**已经装机验证过的**构建。
61+
- **禁止** force-update 已发布 release 对应的 tag(`git push -f origin vX.Y.Z`)。如果发现已发布的 tag 对应 APK 有问题:
62+
- 优先选择**新增 patch 版本**(如 `1.4.0``1.4.1`),而不是覆盖原 tag。
63+
- 原因:覆盖 tag 不会自动重新触发 GitHub Release Action 的 "Create Release" 步骤(已存在会 422),还会让用户已下载的旧 APK 与 tag 不一致,调试困难。
64+
- Tag 命名:`vMAJOR.MINOR.PATCH`(带 `v` 前缀,与 [.github/workflows/release.yml](file:///d:/workspace/project/GSYGithubAppKotlin/.github/workflows/release.yml) 的触发规则一致)。
65+
66+
---
67+
68+
## 2. ProGuard / R8 规约
69+
70+
> 本项目 release 构建启用 `minifyEnabled true` + `shrinkResources true`。AGP 9 自带 R8 9.0+ 默认 **full mode**,比 legacy mode 更激进。
71+
72+
### 2.1 反射目标必须显式 keep
73+
74+
R8 full mode **不做 transitive 父类查找**,以下写法在本项目曾导致运行时崩溃:
75+
76+
```proguard
77+
# ❌ 不可靠:自定义 Fragment 多隔一层基类时推断不到
78+
-keep class com.shuyu.github.kotlin.module.** extends androidx.fragment.app.Fragment { *; }
79+
```
80+
81+
正确做法(见 [app/proguard-rules.pro](file:///d:/workspace/project/GSYGithubAppKotlin/app/proguard-rules.pro#L449-L458)):
82+
83+
```proguard
84+
# ✅ 全量 keep 业务模块(ARouter Class.forName 反射目标)
85+
-keep class com.shuyu.github.kotlin.module.** { *; }
86+
-keepnames class com.shuyu.github.kotlin.module.**
87+
-keep @com.alibaba.android.arouter.facade.annotation.Route class * { *; }
88+
```
89+
90+
### 2.2 `-dontwarn` 仅消除编译警告,不保护运行时
91+
92+
历史教训:v1.4.0 仅靠 `-dontwarn javax.lang.model.**` / `-dontwarn javax.xml.stream.**` 通过了 R8 编译,但 Application `onCreate``Postcard.navigation` 立刻崩 `androidx.fragment.app.i0: Init provider failed!`
93+
94+
**任何新增 `-dontwarn` 都必须配套装机验证**,确认对应的反射 / SPI 调用路径在运行时不会被混淆裁剪。
95+
96+
### 2.3 新增依赖的 ProGuard 自检流程
97+
98+
引入新依赖(特别是带反射 / 注解处理 / SPI 的:ARouter、Retrofit、SimpleXML、Room、Glide、RxJava、kotlinx.serialization)后:
99+
100+
1. 优先看依赖自带的 `consumer-rules.pro`(一般已合规)。
101+
2. 跑一次 `:app:assembleRelease`,注意 R8 的 `Missing classes` 报告。
102+
3. 装机跑核心路径(参考 1.2)。
103+
104+
---
105+
106+
## 3. 浏览器 / Intent 跳转规约(targetSdk 30+)
107+
108+
Android 11 起 package visibility 收紧,必须在 [AndroidManifest.xml](file:///d:/workspace/project/GSYGithubAppKotlin/app/src/main/AndroidManifest.xml#L13-L24) 显式声明 `<queries>` 才能 resolve 到外部应用。
109+
110+
- 任何 `Intent.ACTION_VIEW` 跳转 `http(s)` 的代码必须:
111+
1. Manifest 中已声明 `<queries>` 含对应 scheme + `CATEGORY_BROWSABLE`
112+
2. 调用前 `intent.resolveActivity(packageManager) != null` 预检。
113+
3. 异常路径有用户感知(toast / 提示),禁止静默 catch。
114+
115+
参考实现:[AnkoCompat.browse()](file:///d:/workspace/project/GSYGithubAppKotlin/app/src/main/java/com/shuyu/github/kotlin/common/compat/AnkoCompat.kt#L25-L45)
116+
117+
---
118+
119+
## 4. 工作环境注意
120+
121+
- 本机(Windows)当前 JDK 17,**不能本地跑** `:app:assembleRelease`
122+
- dataBinding parser 要 JDK 24(class file 65.0),JDK 17 只到 61.0。
123+
- 国内网络拉 `gradlePluginPortal` 偶发 SSL 握手失败。
124+
- **release 构建一律走 CI 验证**。本地只跑 `:app:assembleDebug` 和单元测试。
125+
- 调试 release 流程时,提交后用 `gh run list` / `gh run view --log-failed` 拉远程日志,不要在本机硬复现。
126+
127+
---
128+
129+
## 5. 代码风格
130+
131+
- 不主动添加注释(除非用户要求)。
132+
- 不主动新建 `*.md` / README(除非用户要求)。
133+
- 修改文件前先 `Read` 确认最新内容,避免基于旧上下文编辑。
134+
- 引用文件 / 函数 / 行号统一使用绝对路径 markdown 链接:`[name](file:///abs/path#Lstart-Lend)`
135+
136+
---
137+
138+
## 6. 历史 Pitfall 索引
139+
140+
| 版本 | 问题 | 修复 |
141+
|---|---|---|
142+
| v1.4.0 | R8 minify 后 ARouter `Class.forName` 反射目标被裁,首屏 `Init provider failed!` | proguard 改用 `-keep class com.shuyu.github.kotlin.module.** { *; }`,新发 v1.4.1 |
143+
| v1.4.0 | R8 编译报 Missing class `javax.lang.model.element.Element`(ARouter)| `-dontwarn javax.lang.model.**` |
144+
| v1.4.0 | R8 编译报 Missing class `javax.xml.stream.**`(SimpleXML)| `-dontwarn javax.xml.stream.**` |
145+
| v1.4.0 | 「检查更新」跳 `releases` 列表而非 `releases/latest` | [MainDrawerController.RELEASE_PAGE_URL](file:///d:/workspace/project/GSYGithubAppKotlin/app/src/main/java/com/shuyu/github/kotlin/module/main/MainDrawerController.kt#L52-L54) 改为 `releases/latest` |
146+
| v1.4.0 | targetSdk 36 下 `Intent.ACTION_VIEW` 无浏览器可解析 | Manifest 加 `<queries>` + `browse()``resolveActivity` 预检 |

0 commit comments

Comments
 (0)