How to deal with the pace of changing the Android SDK?
In the modern day of mobile development, where everything is modular, and the updates is shipped rapidly, you can easily be lost in the process of manual updates of your dependencies. While there exists solutions like [Renovate] and [Dependabot], the best application of these solutions are to maintain the external dependencies and libraries. But how can we make sure, that if Android compileSDK and targetSDK are up-to-date, if the application logic is not shifting that often, as the SDK'-s? Well, today we would like to share our journey with this, welcome aboard!
Determining the source of truth for Android SDK versions
Upon deep investigation and the Android source code, our team have found, that SDKManager is fetching data from https://dl.google.com/android/repository/repository2-1.xml. This XML contains a lot of information, but the most important to us is "Android SDK Platform XX", where XX - is the Android SDK version. Exactly this information we will need to determine if our application is behind the official SDK's provided by Android development team. For ease of use, there's a docker image already with necessary steps done: ghcr.io/fallenangel97/android-fetcher:master
Process of bumping the SDK'-s in the application code
Now, when we know, where to look at the most up-to-date Android SDK version,
we need to find a way how to specify the logic to update necessary API's.
In order to do that, we will create scripts
folder inside the root folder of the
necessary Android application. Now, whenever the docker image will detect versions of Android SDK,
it will send them to that folder as an arguments, so that we can read them and
construct the logic for updating necessary files.
Example of such script can look like this:
#!/bin/sh
# filename: <project-root>/scripts/bump-android-version.sh
base_path=$(dirname -- "$0")
node $base_path/js/bump-version.js $1
const { execSync } = require('child_process');
const { readFileSync, writeFileSync } = require('fs');
const path = require('path');
const [,,remoteVersions] = process.argv;
const parsedVersions = JSON.parse(remoteVersions);
const latestAndroidVersion = Math.max(...parsedVersions);
const fileContents = readFileSync(path.join(__dirname,'../../app/build.gradle')).toString();
const targetSdkRegex = /targetSdkVersion ([0-9]+)/;
const compileSdkRegex = /compileSdkVersion ([0-9]+)/;
const match = targetSdkRegex.exec(fileContents);
if (match.length > 0) {
const [,version] = match;
if (parseInt(latestAndroidVersion) > parseInt(version)) {
console.log('Replacing the android version...');
const newText = fileContents
.replace(targetSdkRegex, "targetSdkVersion " + latestAndroidVersion)
.replace(compileSdkRegex, "compileSdkVersion " + latestAndroidVersion);
writeFileSync(path.join(__dirname, '../../app/build.gradle'), newText);
execSync('git add .');
execSync(`git checkout -b bump-android-${latestAndroidVersion}`);
execSync(`git commit -m 'Bumped targetSdkVersion and compileSdkVersion to ${latestAndroidVersion}'`);
execSync(`git push -o merge_request.create -o merge_request.merge_when_pipeline_succeeds origin HEAD`);
} else {
console.log('The version is up to date, exiting');
}
}
Of course, you should adjust the scripts up to your requirements.
Putting everything together as a periodic task
We'll use a wonderful docker-cron project in order to connect our pieces together. Let's run our process for bumping Android version every 8 hours, so we can define the logic for swarm-cronjob like this:
version: "3.8"
services:
android_sdk_bumper:
image: "ghcr.io/fallenangel97/android-fetcher:master"
healthcheck:
disable: true
environment:
- REPOSITORIES="<path-to-your-git-repo>"
volumes:
- "/root/.ssh:/root/.ssh"
deploy:
mode: replicated
replicas: 0
labels:
- "swarm.cronjob.enable=true"
- "swarm.cronjob.schedule=0 */8 * * *"
restart_policy:
condition: none
Make sure, that you have generated SSH keys and added them in your Git service in order for the "git clone" to work properly, otherwise it might fail
You are welcome to create a PR for the project here: https://github.com/FallenAngel97/android-list-fetcher Photo by Jan Kopřiva on Unsplash