Framework
Native Android CI/CD you can self-host
Gradle wrapper validation, signed app bundles, and Play track uploads — with your upload keystore imported rather than regenerated.
The pipeline, step by step
android/bootstrapwrapper validation and dependency resolutionandroid/builda signed AAB or APKandroid/testJUnit, and Espresso on an emulatorandroid/bundletooluniversal APK extraction from a bundledistribute/playa track upload, with staged rollout
Every one of these is in the step library, with the credentials it can ask for and whether it may run on a fork’s pull request — generated from the file the server itself reads.
The keystore is imported, never generated
Under Play App Signing, replacing an upload key requires Google’s reset process. A tool that generates a new keystore when it cannot find one has locked you out of your own listing — so Conductor imports the one you have and refuses to invent a replacement.
Emulator images match their host
An x86_64 system image does not boot on Apple silicon and an arm64-v8a image does not boot on an Intel Mac. The architecture is matched to the runner rather than hardcoded, which sounds obvious until you meet a fleet with one of each.
Staged rollout, and the ability to stop it
Play supports a real staged rollout and a real halt, and both are exposed — including the rollout percentage on the dashboard, so “what is actually live” is a thing you can see rather than a thing you go and check.
What a build produces
AAB, APK, mapping.txt, and native debug symbols.
Symbol files are collected on every build rather than on the ones somebody remembers to configure. A crash report that arrives three weeks later resolving to a memory address is a crash report nobody can act on, and the difference is a build-time decision that cannot be made retroactively.