Android Continuous Integration and Deployment Tutorial

Enter Semaphore

Prerequisites

How to finish this tutorial in 1 minute

Configuring CI/CD on Semaphore from scratch

The final Android continuous integration and deployment pipeline

Continuous integration: the safety net for your Android project

Agent: where your code runs

agent:
machine:
type: e1-standard-2
os_image: ubuntu1804
containers:
- name: main
image: semaphoreci/android:29

Global job configuration

global_job_config:
env_vars:
- name: ADB_INSTALL_TIMEOUT
value: "10"
secrets:
- name: android_keys
prologue:
commands:
- checkout
- mv ~/release-keystore.jks ~/$SEMAPHORE_GIT_DIR/app/release-keystore.jks
- cache restore gradle-wrapper
- cache restore gradle-cache
- cache restore android-build
  • release-keystore.jks: the keystore file used to sign our release builds;
  • RELEASE_KEYSTORE_PASSWORD: our keystore password;
  • RELEASE_KEY_ALIAS: our keystore key alias;
  • RELEASE_KEY_PASSWORD: our keystore key password;
  • service-account-key.json: the service account key, used to deploy the demo app to the Play Store.

Pipeline blocks

Build Block

- name: 'Build'
skip:
when: "(branch != 'master' OR branch != 'dev') AND pull_request !~ '.*'"
task:
jobs:
- name: 'Build Project'
commands:
- ./gradlew bundle
epilogue:
on_pass:
commands:
- cache clear
- cache store gradle-wrapper ~/.gradle/wrapper
- cache store gradle-cache ~/.gradle/caches
- cache store android-build ~/.android/build-cache

Verification Block

- name: 'Verification'
skip:
when: "pull_request !~ '.*'"
task:
jobs:
- name: 'Analyze Code'
commands:
- ./gradlew lint
- name: 'Unit Tests'
commands:
- ./gradlew test
- name: 'Integration Tests'
commands:
# Install the required tools and the emulator itself
- sdkmanager "platform-tools" "platforms;android-29" "build-tools;30.0.0" "emulator"
# Install system images for the emulator
- sdkmanager "system-images;android-29;google_apis;x86"
# Create an emulator with the installed system images
- echo no | avdmanager create avd -n test-emulator -k "system-images;android-29;google_apis;x86"
# Start the emulator with no audio, boot animation, window, and with GPU acceleration off
- emulator -avd test-emulator -noaudio -no-boot-anim -gpu off -no-window &
# Wait for the emulator to boot completely
- adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'
# Dismiss the emulator lock screen and wait 1 second for it to settle
- adb shell wm dismiss-keyguard
- sleep 1
# Disable window and transition animations. This is required to run UI tests correctly
- adb shell settings put global window_animation_scale 0
- adb shell settings put global transition_animation_scale 0
- adb shell settings put global animator_duration_scale 0
- ./gradlew connectedAndroidTest
epilogue:
always:
commands:
- artifact push job --expire-in 2w --destination reports/ app/build/reports/
  • ./gradlew lint runs the Android Lint that analyzes the code to check if there’s any problems.
  • ./gradlew test will run all the Unit Tests on our project.
  • ./gradlew connectedAndroidTest will run the Integration Tests, after setting up the emulator.

Promotions

promotions:
- name: Internal Deploy
pipeline_file: deploy-internal.yml
auto_promote:
when: "result = 'passed' AND branch = 'dev'"
- name: Beta Deploy
pipeline_file: deploy-beta.yml
auto_promote:
when: "result = 'passed' AND branch = 'master'"
The Continuous Integration pipeline

Continuous deployment: you can do it with Android too!

Deployment Block

- name: 'Internal Deployment'
task:
jobs:
- name: "Deploy to Play Store - Beta Track"
commands:
- ./gradlew publishReleaseBundle --track beta

On to you

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Semaphore

Semaphore

Supporting developers with insights and tutorials on delivering good software. · https://semaphoreci.com