Android Studio doesn't automatically include dynamic feature modules when building signed release APKs. But universal APKs can be created via the bundletool and signed later.
The gradle wrapper has a task for this already. This makes creating universal APKs easier since APK creation and signing are executed with one command and no separate download of bundletool
is required.
You can use packageReleaseUniversalApk
with the name of your base application module (e.g.: app
) to create a universal APK:
./gradlew :app:packageReleaseUniversalApk
This will however only create an unsigned APK unless you specify the signing informations in your gradle file or pass the information through the command line as shown below.
Leaving the information in gradle is considered bad practice due to security concerns.
The command in buildUniversalApk.sh
passes the information as parameters to the gradlew task in order to make it easily usable in a CI environment.
The path to your keystore must be absolute. In my case it looks like this on macOS:
-Pandroid.injected.signing.store.file=/Users/farbklex/workspace/my_app
The password fields should be enclosed in '
in order to escape characters inside.
If you publish app bundles to the play store, you might ask yourself why we still need APKs in our CI. My reasons for this are:
- Sharing an APK for testing is easier. Services like Appcenter Dsitribute, Firebase App distribution or direct sharing via email are still simpler than using play store's internal sharing which requires entering the play store accounts of all receipients. Unfortunately, Appcenter and Firebase only support APKs right now.
- App bundles aren't supported by all stores. If you intend to publish your app on alternative app stores (e.g. f-droid), you still need an APK.
I found that having signing configs in build.gradle did not generate signed apk when running
packageReleaseUniversalApk
. It only worked by including signing configs along as CL arguments.Thanks for this.