fortunto2/solo-factory/android-release
Claude Code and agent skill by fortunto2/solo-factory
- community
Checking that the SKILL.md file is still in the repository.
Ship an Android app to testers or to Google Play, or push an update to an app already listed there. Use when the user says "make the Android app available to testers", "internal/open testing link", "publish to Play", "release the APK/AAB", "Play Console", "upload a new version", wants install attribution set up (Play referrer UTMs, Install Referrer API, an in-app counter and the matching Data safety form), or hits a Play policy deadline ("app doesn't meet target API level requirements"). Leads with the MINIMAL tester-link workflow (fastest), then the FULL production listing, then UPDATE for an existing app. Carries the exact Play Console browser steps, signing/keystore setup, the testing-track comparison, required assets, and the gotchas (lintVitalRelease crash, 16 KB alignment, target API deadline) so you don't re-learn them.
Install
npx vskill@latest install fortunto2/solo-factory/android-releaseSKILL.md
android-release — ship Android to testers, then to Play
Start with MINIMAL (a working tester link in minutes). Do FULL only when the user wants the public Play listing. Sibling skill: `ios-release` for iPhone/TestFlight.
Golden rules:
- Never hit final publish/"Send for review" without the user's OK — it's outward-facing. Filling
drafts is fine; an internal-testing rollout is low-risk + reversible, so a prior "set it all up" covers it — but state what you did.
- Back up the keystore + password — losing it = can't update the same Play listing.
- Browser work: the user logs in (never touch their password/2FA); you drive the forms after.
Playwright MCP runs its own persistent Chromium profile, NOT the user's Chrome — a Chrome that is "already logged in" is invisible to it, and you can't attach unless it was started with --remote-debugging-port (check curl -s localhost:9222/json/version before promising anything). So: open the Google sign-in page, hand the window over, wait. The login then sticks for later sessions.
- The app may live in someone else's developer account (client/agency who granted you access).
play.google.com/console/developers shows a "Choose developer account" list — one Google login can hold several. Before concluding "the app isn't here", check every developer account in that list, not just the app list of the first one. Newly granted access appears there after a reload.
Which track? (who can use the link)
| Track | Who can install via link | Setup needed | |
|---|---|---|---|
| Internal testing | only Google accounts on your list (≤100) | almost none — no review | |
| Closed testing | accounts on a list or a Google Group | + content rating, data safety | |
| Open testing | anyone with the link | + full store listing, content rating, target audience, data safety, review | |
| GitHub APK (sideload) | literally anyone, no Google account | none — but "unknown sources" prompt |
Most "available to testers" asks → Internal testing (fast) or the GitHub APK link (instant, zero-restriction). "Anyone with a link, via Play" → Open testing (heavier: listing + review).
A. MINIMAL — get a tester link
A1. Fastest: sideload APK via a GitHub Release (no Play account, ~2 min, works for anyone)
A2. Play Internal Testing (opt-in link, installs via Play, no review). Signed AAB required (:composeApp:bundleRelease). Browser steps (Playwright — user logs in first):
play.google.com/console→ Create app: name (≤30), packagecom.…, Check availability,
App, Free, tick both declarations (Program Policies + US export laws) → Create app.
- Testing → Internal testing → Create new release.
- Leave Play App Signing on ("Releases are signed by Google Play").
- Upload the
.aab(click Upload →browser_file_uploadwith the absolute path). Wait for
"optimized for distribution". Release name auto-fills; add notes inside <en-US>…</en-US>.
- Next → Save and publish (confirm dialog). Benign warnings: "no deobfuscation file", "no
native debug symbols", "no testers yet".
- Testers tab → tick an email list (or Create email list + paste emails) → Save →
track flips to Active. Copy the link: https://play.google.com/apps/internaltest/<trackId>. Testers open it signed into a listed Google account, tap "Become a tester", install from Play.
A3. Upgrade internal → open later: Testing → Open testing → Promote release (or create a new open release). Requires the FULL section below (listing + content rating) + review before it goes live.
B. FULL — production / open-testing listing
Complete before "Send for review":
- Store listing: app name, short desc (≤80), full desc (≤4000), app icon 512×512,
feature graphic 1024×500, ≥2 phone screenshots (1080×1920..2160; longer side ≤ 2× shorter).
- App content (all required): Privacy policy URL, Ads, App access, Content rating
(questionnaire), Target audience & children, Data safety, plus Government/Financial/Health if relevant.
- Countries/regions + Free/Paid.
- Production (or Open testing) track → create release → upload AAB → Send for review (confirm first).
- New personal accounts: Google may require ≥12 testers for 14 days on closed testing before
production access — plan for that.
Order that actually unblocks "Send app for review" (Publishing overview)
The Send app for review button stays locked until the Dashboard "Set up your app" checklist is 100%. Complete, in this order:
- Store listing (Grow users → Store presence → Store listings): name, short/full desc, upload
icon 512 + feature 1024×500 + ≥2 phone screenshots. (Tablet-screenshot slots show * but are NOT required for a phone app.)
- Store settings (Store presence → Store settings) — EASY TO MISS, it's a separate checklist
item "Select an app category and provide contact details" that needs THREE things, all required to mark it complete: App category + ≥1 Tag (Manage tags — NOT optional; a missing tag silently keeps the whole task incomplete and "Send app for review" locked, with no obvious error) + a contact Email. Verify each value persists after save (a filled-looking field can save blank).
- App content (Policy and programs → App content → overview) — do every "Start declaration":
Privacy policy URL · App access (Sign-in details) · Ads · Content ratings (IARC questionnaire) · Target audience · Data safety · Advertising ID · Government apps · Financial features · Health. Yes/No order is NOT consistent across pages — read each before clicking.
- Open testing track: Countries/regions (select all → Save) → Create release → Add bundle
from library (reuse the internal AAB) → notes → Next → Publishing overview → Send app for review.
Content rating (IARC) — for a utility/"All Other App Types" app
Category "All Other App Types"; email for the certificate. Answer content questions No (violence/ sex/language/drugs/gambling). If the app has user-posted content (photos/notes shared with others), "User Content Sharing" = Yes → then the sub-questions (nudity/violence/block/report/moderation) are all No for a benign app; rating stays Everyone/PEGI 3.
Data safety — the long one
Q1 collects data? Yes → encrypted in transit Yes → account creation method (anonymous app = "My app does not allow users to create an account") → external login No → data-deletion request: Yes needs a "Delete data URL" (use the privacy-policy URL) or answer No (it's Optional). Pick data types (Location→Precise, Photos, Personal info→Name/Email/User IDs, App activity→Other UGC), then per type open its modal: Collected (your backend is not "Shared" with third parties) → not ephemeral → optional ("users can choose") → purpose App functionality → Save.
⚠️ A counter in the app changes these answers. Any analytics means Q1 is Yes and App activity → App interactions is collected. Declare it in the same release that ships the counter, not after — see Analytics. Play suspends over a Data safety form that disagrees with the app's behaviour, and the form is the easier thing to fix.
Browser-automation gotchas (Playwright on Play Console)
- Angular Material radios/checkboxes ignore JS `.click()` — must use a real
browser_click. Target
them by the accessibility ref, or question:has-text("<unique question text>") >> role=radio[name="No"]. Radio labels ("Yes"/"No") are sibling text, so role=radio[name=...] often has an EMPTY name — click by the visible label text or the ref instead.
- Sticky footer / overlay panes intercept clicks on library-Upload / "Add" / "Create release"
buttons → click via page.evaluate(() => document.querySelector('button[debug-id="..."]').click()) (debug-ids: upload-button, add-to-content-button, create-android-release-button).
- File upload: side-panel Upload button →
browser_file_uploadwith the absolute path → the asset
lands in the library → select it → click Add (footer-intercepted; JS-click it).
- Text fields: type with
slowly/pressSequentially and VERIFYinput.valuebefore Save — a filled-
looking field can be empty (wrong element), leaving "Save" disabled or saving blank (bit me on the contact email — took two tries).
- Direct URLs to `/app-content/*` sub-pages redirect to Home on hard-navigation; reach them by
clicking the in-app "App content → overview" link (SPA nav), or navigate to /app-content/overview. Deep track URLs (/tracks/app-bundle-explorer, /tracks/<id>/releases/…) are worse — a cold load dies with "An unexpected error has occurred (64146155)". Land on /app-dashboard or /test-and-release, then click through the SPA nav. Handy trick: document.querySelectorAll('a[href]') on /test-and-release dumps every track URL incl. the numeric closed-testing track id.
- Read the page with `browser_evaluate`, not full snapshots — Console pages are enormous. Grab
document.body.innerText sliced around an anchor phrase, or map [role="row"] → innerText, and wrap it in new Promise(res => setTimeout(…, 4000-6000)) because the SPA renders after navigation reports done. Cheap, and it survives the re-renders that invalidate accessibility refs.
- Refs go stale constantly (Console re-renders, plus
?pli=1redirects on first load). Prefer
text-based selectors (button:has-text("Save")) or find-by-innerText + .click() inside browser_evaluate over refs captured more than one action ago.
- "Send app for review" locked with everything seemingly filled? It's almost never a UI lag —
a required sub-field is silently blank. The dashboard task name understates its requirements (e.g. "Select an app category…" also needs Tags). When a checklist item won't turn green, open it and fill EVERY field, including the ones that look optional, before assuming it's a glitch.
C. UPDATE — new version of an app already on Play
The common ask (policy deadline, bugfix, new build). Nothing from section B is re-done — listing and declarations are already approved. Order:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/android-release/SKILL.md
Popularity
- Repository stars
- 18
- Repository forks
- 3
- 7-day trend score
- 15
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/fortunto2/solo-factory/android-release)