Automated delivery and publication of apps using FDroid and GitLabCI

In my spare time I develop applications on Android. I also “maintain” F-Droid repository for some of my public projects. I wanted to automatically publish each build after:

  1. Compilation passed
  2. Test on a connected device passed
  3. Signed build completed

So I made a simple setup with help of GitLabCI and own F-Droid repository. This post does not describe how to configure F-Droid repository or configuration of GItLabCI-runner, because official documentation is much better than I could write it. This post just describes how I use both services to automate boring deployment.

GtiLabCI is run on your own hardware, so it can have access to your files, configuration etc. It’s an advantage over Travis, as you can run any custom command, like testing on connected device or on pre-configured emulator, connected to remote hosts where CI slave is on a trusted machine.

On my setup, I created a user FDroid, used ssh-copy-id to login on the remote user, changed password to something pseudo-random, so I never login there again using password, only by ssh-keys. The user has F-Droid repo exposed by web server, and that’s pretty much it on the server side.

GitLabCI has the following config:

# This file is generated by GitLab CI
Clean, check, build:
  - "gradle connectedAndroidTest"
  - "gradle installDebug"
  - "gradle assembleRelease -S"
  - "bash"
  - tags

Slave will execute next command only if previous command passed (it’s like set -e in bash), if any of the command fails, you will see failed build in your GitLab repository.

The fdroid script is nothing like production ready, but it works for me and my purpose:

#! /usr/bin/bash
cp app/build/outputs/apk/APP_NAME-release*.*.apk /home/agilob/Projects/fdroid/repo
cd /home/agilob/Projects/fdroid
./fdroid update 
./fdroid publish
rsync -a -e 'ssh -p 3022' --progress repo

When gradle assembleRelease -S is completed, it will put a signed file in app/build/outputs/apk/, the .apk should contain -release in that case, you don’t want to expose debug .apks in your repository.
/home/agilob/Projects/fdroid/repo – is where my local copy of FDroid repository is and it contains standard F-Droid repo scrips that build repo index, so F-Droid client can find and download them.

The following commands build the index and publish it:

./fdroid update 
./fdroid publish

The following command just copies files from local FDroid repo to the remote server, but copies only files that changed like index.xml, new .apks, etc.

rsync -a -e 'ssh -p 3022' --progress repo

How is that useful to me?
Each time I push to master branch or build it, I can automatically update my FDroid repo from trusted source. Signing keys are kept on my local machine, so I can quickly deploy any hot-fixes. I find this quite a good and flexible solution for solo-android development :)