From common-skills
Gradle build 完 Android 包之后,主动提出把 APK 推到 adb 连接的设备(真机或模拟器)并拉起。TRIGGER whenever the user asks to build/compile/package an Android app, runs assembleDebug/assembleRelease, 说 '打 android 包' / '编译 android' / 'build apk' / '跑到手机上' / '装到模拟器' / 'deploy 到设备', 或者任何基于 Gradle 的 Android 构建任务 —— 即使用户没明说 adb 或部署也要触发。构建成功后主动向用户确认是否部署;若用户一开始就说了 'build 完部署' 类指令则跳过询问直接部署。设备选择: 上下文里有最近一次用过的 serial 就复用, 单设备直接用, 多设备向用户确认。部署 = adb install -r + 用 monkey 拉起 launcher activity。
How this skill is triggered — by the user, by Claude, or both
Slash command
/common-skills:adb-installThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
把"build Android → 安装到真机/模拟器 → 启动 app"这段肌肉记忆固化下来,让用户只说 "帮我 build 一下 android" 就能完成整条链路,不用每次重复交代 `assembleDebug` / `adb install -r` / `am start`。
把"build Android → 安装到真机/模拟器 → 启动 app"这段肌肉记忆固化下来,让用户只说 "帮我 build 一下 android" 就能完成整条链路,不用每次重复交代 assembleDebug / adb install -r / am start。
核心价值不是"跑 adb 命令",而是主动提醒部署——用户经常 build 完忘了 push,或者懒得手动选设备。这个 skill 的存在感就是:build 一出 BUILD SUCCESSFUL,立刻问一句"要部署吗"。
只要用户的话里出现下面任意一类意图,本 skill 就应该被激活:
build android、编译 android、打 android 包、assembleDebug、./gradlew :app:assembleDebugbuild 完装到手机、编译然后 push 到设备、跑一下看看把这个 apk 装上、推到模拟器、adb installbuild androidApp、打 android target不触发的场景:
整件事拆成 5 步,任何一步失败都立即停下,不要盲目往下走。
assembleDebug:app / :androidApp / :composeApp / :mobile 等。KMP 项目常见的是 :composeApp 或 :androidApp。如果 settings.gradle(.kts) 里只有一个 android 模块,直接用它./gradlew <module>:<task>(或 Windows 下 gradlew.bat)BUILD SUCCESSFUL:
构建成功后,检查用户最初的指令里是否已经表达了部署意图:
有明确部署意图(build 完装到手机、编译然后推到设备、跑起来看看 之类) → 跳过询问,直接 Step 3
只说了构建,没提部署 → 主动向用户确认,大概是:
Android 构建成功,APK 在
<apk 路径>。要部署到 adb 设备吗?
- 是,推到设备并启动
- 否,只构建就好
这一步是本 skill 的灵魂 —— 用户就是因为懒得每次手动 adb install 才让你主动问的。不要沉默跳过。
如果用户选"否",skill 到此结束,不要继续后面的 step。
构建产物在 <module>/build/outputs/apk/<variant>/**/*.apk,常见具体路径:
app/build/outputs/apk/debug/app-debug.apkcomposeApp/build/outputs/apk/debug/composeApp-debug.apkapp/build/outputs/apk/<flavor>/debug/app-<flavor>-debug.apk定位策略:
ls -t / find 在构建出的 build/outputs/apk/ 子树里找最新修改的 .apk(构建完就是刚写出来的那个)设备选择的优先级顺序(高到低):
adb -s <serial> 或类似操作,直接复用。用户不想每次重选。唯一例外:用户这轮明确说了"这次换一台"/"装到另一台"/"用模拟器"/"用真机",忽略上下文,走 2adb devices 输出里只有一台 device 状态的,直接用它device 状态的设备让用户选。列表里要包含 serial 和设备型号(adb devices -l 有 model:xxx),真机和模拟器都要标清楚(模拟器 serial 一般形如 emulator-5554)adb devices 过滤规则(重要):
只保留 State == device 的条目,排除:
offline —— 设备断开中,直接用会报错unauthorized —— 真机没点"允许 USB 调试",提示用户到手机上点确认no permissions —— 一般是 Linux udev 配置问题,提示用户手动修过滤后一台都不剩 → 停下,告诉用户没有可用设备,列出原始 adb devices -l 输出让用户自己判断。不要试着 adb kill-server / adb start-server 瞎折腾,那是用户的决策。
拿到 <apk> 和 <serial> 后,按顺序跑:
# 1. 从 APK 提取 package name (用来启动)
PKG=$(aapt2 dump packagename <apk>)
# 如果 aapt2 不在 PATH,找 Android SDK build-tools:
# AAPT2="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$HOME/Library/Android/sdk}}/build-tools/$(ls -1 ${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$HOME/Library/Android/sdk}}/build-tools 2>/dev/null | sort -V | tail -1)/aapt2"
# PKG=$("$AAPT2" dump packagename <apk>)
# 实在没 aapt2,退路: 从 build.gradle(.kts) 的 applicationId + applicationIdSuffix 推断;再不行问用户
# 2. 安装 (-r 允许覆盖同签名已安装版本)
adb -s <serial> install -r <apk>
# 3. 用 monkey 拉起 launcher activity (不用知道 MainActivity 全名)
adb -s <serial> shell monkey -p "$PKG" -c android.intent.category.LAUNCHER 1
为什么用 monkey 而不是 am start -n <pkg>/.MainActivity: monkey 不需要知道主 Activity 的全类名,只要包名就能拉起默认 launcher intent。对本 skill 足够用,且少一个出错点。
install 的常见失败处理:
| 错误 | 原因 | 处理 |
|---|---|---|
INSTALL_FAILED_UPDATE_INCOMPATIBLE | 已装版本签名不一致 | 提示用户,让用户决定是否 adb -s <serial> uninstall <pkg> 后重装 —— 不要自作主张卸载,用户本地数据可能重要 |
INSTALL_FAILED_VERSION_DOWNGRADE | 新 versionCode 比已装的低 | 提示用户,建议 -d(允许降级)或先 uninstall |
INSTALL_FAILED_INSUFFICIENT_STORAGE | 设备空间不足 | 告诉用户清空间,不要重试 |
device offline | 设备中途断了 | 告诉用户,回到 Step 4 重选 |
启动后报告两件事给用户,一句话足够:
已安装并启动
<pkg>到<设备型号> (<serial>)。
build 没过 → 只报告构建错误,绝不进入部署流程。不要因为"反正 APK 可能已经在上次构建的位置"就去装旧的,那是惊喜型 bug。
上下文没有明确的设备 + 多设备 → 必须向用户确认。不要"选第一个"或"选模拟器优先"之类的启发式,这类决策成本低(用户点一下)、错了代价高(装错设备)。
遇到签名冲突、降级这类需要 uninstall 的场景,必须先问用户。用户机器上的那个应用可能有开发中的数据、账号登录态,贸然 uninstall 全没了。
adb kill-server / adb root / adb reboot这些命令影响面超出"装个包跑起来"的职责范围。遇到需要的场景,报告给用户让用户决定。
一次对话里一旦选定了设备 serial,后续所有 adb 命令都带 -s <serial>,别临时再 adb devices 重查 —— 费时且如果此时有新设备插入会引入歧义。
adb 相关的调试操作(logcat、shell、screenrecord、input 模拟)—— 这些以后可能拆成 adb-logcat 等独立 skill,本 skill 不要 scope creep场景 A: 一句话搞定
User: 帮我 build 一下 android 跑到手机上
Assistant: [跑 ./gradlew :composeApp:assembleDebug]
[构建成功,用户指令里已有部署意图,跳过询问]
[adb devices → 只有一台 Pixel 7]
[aapt2 dump packagename → com.example.app]
[adb -s ... install -r]
[adb -s ... shell monkey -p com.example.app ...]
已安装并启动 com.example.app 到 Pixel 7 (12345ABCDE)。
场景 B: 只说构建,skill 主动问
User: 编译一下 android
Assistant: [跑 assembleDebug → 构建成功]
构建成功,APK 在 composeApp/build/outputs/apk/debug/composeApp-debug.apk。
[向用户确认: 要部署到 adb 设备吗?]
User: 要
Assistant: [进入部署流程]
场景 C: 多设备
User: build 完装上
Assistant: [构建成功]
[adb devices -l → Pixel 7 + emulator-5554]
[向用户确认: 部署到哪台? 1) Pixel 7 (12345ABCDE) 2) emulator-5554 (Pixel_6_API_34)]
User: 模拟器
Assistant: [用 emulator-5554 完成 install + launch]
npx claudepluginhub sampeng87/skills --plugin common-skillsCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.