The problem we solved
In day-to-day mobile app development, distributing builds for testing teams in order to verify new features or bug fixes becomes a hassle over time. There are a few possibilities on how to handle this process manually. The Dev team could, for example, build an apk file and share it with the testing team. The testing team would then install the apk manually on all of the testing devices used. Another approach would be to rely on the testing team to check-out the latest code from source control, build an apk file and install it on the devices. All of the manual approaches for build distribution require somebody to install the builds manually on the devices – when there are multiple devices, this takes up a lot of time which could better be spent testing, developing or drinking coffee.
Jenkins and Crashlytics/Beta
When the number of devices increases, the in-house distribution process needs to be automated. For build automation, the tool of choice is Jenkins. As for the mobile distribution process, Crashlytics and Beta are handy. Crashlytics provides great crash reporting and insight and Beta will be used for the distribution process.
The flow for the automated app distribution is simple. A Jenkins job checks out the latest code that should be tested and builds an apk from that code version. As part of the build process, tests can be executed freely. When the apk is successfully built, it gets uploaded to Beta with optional release notes for the testing team. The test devices are notified, and the new build can be installed to a device just by clicking a button in the Beta client app. Using the client app, a testing team member can view the release notes and build a history for the application being tested.
The application
The Crashlytics installation process (see here) via Gradle is fairly simple. The kit needs to be added via Gradle to the Android project, with the API Key provided in the AndroidManifest.xml. Beta is bundled with Crashlytics so there are no additional steps required to add Beta to a project.
It is crucial to complete the whole installation process and run the app with Crashlytics installed. After that, the Fabric dashboard can be accessed, from where the build secret can be retrieved. This secret is required for Beta to be able to upload the apk and distribute it to the testing team. A fabric.properties file with a single key-value entry apiSecret=<api_secret> needs to be added in the project root for the upload process to be enabled.
All that is left is to create a distribution for the testing team (see here).
One of the ways to specify a distribution email is to add ext.betaDistributionEmails=”[email protected], [email protected]” to the buildTypes object in build.gradle. To specify release notes for a build ext.betaDistributionReleaseNotes can be provided in the same file.
When distribution emails and release notes have been added, invoke gradle with one of the Crashlytics tasks. For example:
gradle assembleDebug crashlyticsUploadDistributionNoGPlayDebug
This command will build the app, upload it to Beta and notify all the testers added with the distribution emails.
The infrastructure
An AWS EC2 instance with Ubuntu was used as a Jenkins build node. The EC2 instance needs to have Java (JDK) and the Android SDK installed in order to automate the build process. The easiest way to install JDK is to use Ubuntu’s package manager APT and install OpenJDK:
sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-get update sudo apt-get install openjdk-8-jdk
When used for developing Android applications, Android SDK is usually installed with Android Studio on desktop machines. As this is an Ubuntu server with no GUI and not a development machine, Android Studio won’t be necessary. Android SDK can be installed by downloading and extracting the SDK CLI tools from here. For example:
wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
The downloaded zip file needs to be extracted to a destination directory (in this case android-sdk:
unzip sdk-tools-linux-3859397.zip -d android-sdk
In order to make the CLI tools available from any location on the machine, entries to ~/.bashrc need to be added:
export ANDROID_HOME=/path/to/dir/android-sdk export ANDROID_SDK=$ANDROID_HOME PATH=$PATH:$ANDROID_HOME/build-tools PATH=$PATH:$ANDROID_HOME/platform-tools PATH=$PATH:$ANDROID_HOME/tools PATH=$PATH:$ANDROID_HOME/tools/bin
In order to build an app, we need to install the appropriate packages for that application. The packages are installed with sdkmanager (bundled with the installed Android SDK). In most cases build-tools, platform-tools, android support repository and google APIs are needed to build an app. For example, to install the build-tools execute:
The Jenkins job
The Jenkins job pulls the latest code from the remote repository and executes a shell script on the build node which builds and distributes the application with gradle. The shell script summarizes release notes to be added to the build and finally distributes the app.
In the Source Code Management section of a Jenkins job, provide the URL and credentials to your repository. The specified branch to build is going to be monitored for changes.
In the Build Triggers section, check the Poll SCM checkbox and provide a cron entry. For example, insert H/5 * * * * to poll SCM every 5 minutes for changes. If there are changes that have not been built previously, the job will get triggered.
In the Build section, add a “Execute shell” build step. Here is where the app is going to be built and distributed:
#!/bin/bash echo "BUILT AT:" > releasenotes echo `date` >> releasenotes echo ${BRANCH_NAME} >> releasenotes git log -1 >> releasenotes ./gradlew --no-daemon assembleDebug crashlyticsUploadDistributionDebug
This shell script creates a releasenotes file with information that can be relevant (build date and time, branch name, git commit hash and message, author etc). All of this is going to be listed in the release notes for a build in Beta. After that, gradle is invoked to build and distribute the app.