Android Wear packaging

Daniele is the local horologist at Novoda. GDE for wearable technologies and IoT, he likes to experiment with the whole Android ecosystem, from AOSP to Google Cast and Android TV.

Android Wear 2.0 will be released to the public in 2017, but at the moment there are a lot of smartwatches still running Wear 1.x and for a big part of them there is no guarantee at all that they will receive the update.
For this reason it's very important to keep supporting the publishing mechanism used by Wear 1.x devices.

With Android Wear 2.0, apps can be distributed as standalone and installed directly from the watch. This requires the creation of a dedicated APK for the watch to be uploaded on the Play Store developer console using the multiple APK approach. Doing so, both the mobile and wearable APKs are independent versions of the application, each one targeting a different category of devices but sharing the same application listing on the Play Store.

With the previous Wear version though, the wearable APK needs to be embedded into the phone APK.
When creating a release build for our mobile app, we can configure Gradle to automatically add the Wear APK into the mobile one raw resources, as described in the official documentation.
What the documentation is really lacking is how to tune the build config in order to take into consideration some real-world scenarios. Let’s have a look at some of these.

Multi-dimensions flavors

In many apps we need to specify different environments, for example for development and production, each one with different configurations for several components like analytics, endpoints, etc. Usually this is done specifying a productFlavors closure in the mobile build.gradle containing the definition and different configuration for each environment flavor.

Another use of flavors is to provide different versions of the apps with or without Play Services. I know it seems difficult to believe, but there are devices out there not including them and even markets that reject every submitted app using any API provided by Play Services. In order to maintain compatibility with these markets and devices, it’s a good practice to create two different flavors of the app, with or without Play Services dependency.

In order to make these two requirements coexist, we can define the so called flavorDimensions inside the productFlavors closure and associate every flavor with one specific dimension.
For every combination of flavors a specific task will be automatically created.

Here’s an example of the described product flavors:

productFlavors {  
    flavorDimensions 'environment', 'playServices'

    noPlayServices {
        dimension 'playServices'
    }

    playServices {
        dimension 'playServices'
    }

    development {
        dimension 'environment'
    }

    production {
        dimension 'environment'
    }
}

Signing

The automatic packaging task will add the Wear APK to the mobile one only if they are both signed with a release (non-debug) key.
Also, the Package Manager will check that the two APKs (the mobile and the Wear ones) keys are the same when installing on the smartwatch.

To implement this, we extracted the signing config into a shared Gradle file which is referenced by both the mobile and wear build.gradle with

apply from: rootProject.file('shared-config/android-signing.gradle')  

Build types

In a real project, different build types are used when developing, for release and for testing.
Each build type can have a different configurations, for example regarding signing, API keys, or even different package ids. An important thing to remember is that Package Manager expects the two mobile and wear APKs to have the same package id. So if your app has different package ids for different build types on mobile, you need to have the same structure in wear module.

As mentioned before, we want the Wear APK to be embedded only when building for Play Services-enabled devices, and only for release builds.
To limit the combinations of build types and flavors which will contain the Wear APK, we specify a list of configurations in the mobile build.gradle and and specify the relative configuration from the Wear module fo be used as dependency.

configurations {  
    developmentPlayServicesReleaseWearApp
    productionPlayServicesReleaseWearApp
    developmentPlayServicesQaWearApp
    productionPlayServicesQaWearApp
}

dependencies {  
    developmentPlayServicesReleaseWearApp project(path: ':wear', configuration: 'developmentRelease')
    productionPlayServicesReleaseWearApp project(path: ':wear', configuration: 'productionRelease')
    developmentPlayServicesQaWearApp project(path: ':wear', configuration: 'developmentQa')
    productionPlayServicesQaWearApp project(path: ':wear', configuration: 'productionQa')
}

The Wear APK is not embedded in the noPlayServices variant of the app. Android Studio Analyze APK tool is a great way to check if the APK has been included or not.

I created a simple demo app which shows how to integrate a Wear module into a project with the requirements we just saw. You can find the full demo source code at https://github.com/novoda/android-demos/tree/master/WearBuildConfig

About Novoda

We plan, design, and develop the world’s most desirable Android products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.

Let’s get in contact