Android
The whole Android flow, from an app that has never used OverPush to a fix running on your users' phones. Your normal Flutter installation is all you need.
Before you start
- A Flutter app that builds in release mode for Android, on a Mac, Windows or Linux computer.
- The OverPush CLI, installed and logged in. See Getting started.
- An app created in the console. The same app id is used for Android and iOS.
- For trying builds on your own phone: a phone with USB debugging on, and Android Studio installed (it brings the Java that previews need).
1. Set up the project
-
Add the package
$ flutter pub add overpush -
Connect the project
From the project root, the folder with
pubspec.yaml:$ overpush init --app-id cp_your_app_idThis writes
overpush.yamland stores a project key in.overpush/key, which is added to.gitignorefor you. It also adds theINTERNETpermission toAndroidManifest.xmlif your app doesn't have it yet.You don't change
main.dart,MainActivity, or any Gradle file. Your app's own signing setup is used as it is.
2. Ship a release
-
Build the release
$ overpush release androidThis builds an app bundle (
.aab), the format the Play Store takes, and records the release so it can be patched. It covers every Android phone Flutter runs on: 64-bit and 32-bit ARM, and x86_64.Distributing outside the Play Store? Build an APK instead. It also covers every phone:
$ overpush release android --artifact apkPatches only reach phones running a build made by
overpush release. A build from plainflutter buildruns normally but never receives patches. -
Try it on your phone first
With a phone connected over USB:
$ overpush preview androidThis installs exactly the build your users get, the same way the Play Store does, and opens it. The first preview downloads a small tool from Google, once.
-
Upload it to the Play Store
The CLI prints where the file is:
build/app/outputs/bundle/release/app-release.aab(an APK goes tobuild/app/outputs/flutter-apk/app-release.apk). It's signed with your app's own release key fromandroid/key.properties. Then, in Play Console:- Open your app and go to Test and release.
- Pick a track: Internal testing is a good first stop, Production for everyone.
- Click Create new release and upload
app-release.aab. - Add release notes, click Next, then save and roll it out. On Production, Play sends it for review first.
There's nothing else to run:
overpush release androidalready saved the release to your account, so any computer or CI runner logged in to it can patch it.Raise
versionCodefor every upload. Play Console rejects a bundle whose version code it has seen before.
Testing on another phone with an APK
To hand the app to a tester, or try it on a phone that isn't connected to your computer, build an APK:
$ overpush release android --artifact apk
The APK is at build/app/outputs/flutter-apk/app-release.apk. Get it onto the phone either way:
- Over USB:
adb install -r build/app/outputs/flutter-apk/app-release.apk, oroverpush preview android, which also opens the app. - Without a cable: send the file by WhatsApp, Drive or email, open it on the phone and tap Install. Allow installs from that app when the phone asks.
Then patch it like any release:
$ overpush patch android
Open the app, wait a few seconds, close it fully and open it again: the patch runs.
The APK is its own release. overpush patch android patches the newest release, so after building the APK it targets the APK, not the bundle you uploaded to Play. To patch the Play Store build, name it: overpush patch android --release-version 1.7.0+66. The console's Releases tab shows both.
If the phone already has your app from the Play Store, installing the APK fails with a signature error unless the APK is signed with the same key. Uninstall the store version first.
3. Publish a patch
-
Change some Dart
Fix the bug, change a screen, add a new one. Anything in Dart can go out as a patch. See what a patch can change.
-
Check it first (optional)
$ overpush patch android --dry-runBuilds and checks the patch without publishing anything.
-
Publish
$ overpush patch androidThe CLI builds the patch for the newest release, checks that it really changed something and that nothing outside Dart changed, and publishes it. To start with a share of users:
$ overpush patch android --rollout-percent 10 -
See it on the phone
Open the app. A few seconds after it starts, it downloads the patch in the background. Close the app fully and open it again, and the patched code runs.
-
Watch it in the console
The release page in the console shows each patch with its installs and failures, and the app's overview charts patch installs and failures. When it looks healthy, widen the rollout:
$ overpush patches rollout 1 --percent 100 # everyone $ overpush patches revoke 1 --reason "wrong total" # stop it everywhere
If the project also has iOS releases, add
--platform android. Both are also in the console's patch menu, along with rolling a patch forward again. See Rollouts & rolling back.
What a patch can change
| Change | As a patch? |
|---|---|
| Dart code: logic, widgets, layouts, text, new screens, new classes | ✅ Yes |
| Pure-Dart packages (no native code) | ✅ Yes |
Kotlin or Java, AndroidManifest.xml, Gradle files | ❌ Needs a store release |
| Adding, removing or upgrading a plugin with native code | ❌ Needs a store release |
| Images, fonts and other assets | ❌ Needs a store release |
Before publishing, the CLI compares the project with the release. If anything in the second half of this table changed, it stops and says what. If you're sure the change doesn't matter to the patch, such as a comment in a Gradle file, --allow-native-diffs and --allow-asset-diffs publish anyway.
Shipping a new store version
When you need a store update, bump the version in pubspec.yaml and run overpush release android again. Phones that install the new version start clean: patches made for the old version are removed automatically, and new patches go to the new release.
Obfuscation
Add obfuscate: true to overpush.yaml and release again. Patches for that release are obfuscated the same way, with nothing extra to pass. See Configuration.
What to expect
| Speed | Patched apps run at the same speed as the original release. |
| Patch size | Only the difference from your store release. A small fix is usually under a megabyte. It downloads in the background and only once per patch. |
| When it applies | On the next cold start after the download finishes. |
| Store updates | When a user installs a new version from the store, patches for the old version are removed automatically. |
| Devices | Every Android phone Flutter runs on: 64-bit and 32-bit ARM, and x86_64. App bundles and APKs both cover all of them. |
| A bad patch | If a patch stops the app from starting, the phone removes it and runs the store build again on its own. See Automatic rollback. |
Checking a device
OverPush logs what it does at startup. If a patch doesn't seem to apply, check the device log with the phone connected over USB:
$ adb logcat | grep OverPush
| Log line | Meaning |
|---|---|
patch loader installed | OverPush is active in this build. Printed on every launch. |
applied patch N; it loads on the next cold start | Patch N was downloaded and verified. |
booting patched Dart code | This launch is running the patch. |
the APK changed since this patch was applied | A new store version was installed, so the old patch was removed. |
If you only ever see patch loader installed, check that the installed build came from overpush release android and that the device is inside the patch's rollout.
Common problems
"The phone has your app signed with a different key"
Shown by overpush preview android when the phone already has your app from the store, which is signed with your release key. Uninstall it from the phone, or keep your release key in android/key.properties (Flutter's standard setup) so previews are signed the same way.
"Install canceled by user"
Some phones, Xiaomi and Redmi among them, ask on screen before installing over USB. Keep the phone unlocked and tap Install when it asks, or turn on Install via USB in the phone's developer options.
"This build is byte-identical to the release"
The patch build came out the same as the release, so there's nothing to send. Check that your edit is in Dart code under lib/, and saved.
More in Troubleshooting.