As part of my goal to decrease my smartphone addiction, I recently bought a Unihertz Jelly phone, which could be a good compromise between a smartphone and a dumbphone. The phone has a multi-purpose function button. You can assign it to specific pre-defined actions or launch any application. As I regularly use the phone screen in grayscale mode, I decided to assign the button to an application that would toggle this mode. I searched and couldn't find a simple app to toggle it when launching. So I decided to write my own. However, this previous background could be a post on its own.
As I've been trying to leverage GitHub actions for manual tasks, I searched GitHub and found many actions that could do this for me. I tried with a couple of them, and they didn't work. One of the issues is that the actions are using obsolete dependencies, and I spent way more time trying to make them run than I wanted.
I decided to make it work without a pre-built action and write all of the required steps in a GitHub workflow, which, in the end, was very simple. Here's the action. I will do a walk-through so you can use it in your projects.
name: Release APK
on:
push:
tags:
- '*'
This workflow will run when pushing a tag to a repository.
jobs:
Gradle:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v3
This is the standard step to checkout the code. It can run with the latest checkout action (v3).
- name: setup jdk
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'temurin'
Then, we need to set up the JDK. Again, using the latest setup-java action (v3). I set the Java version to 17, which is the one that my Android Project uses. You can adjust the distribution, too. Refer to setup-javas documentation.
Now, to sign the released APK, we'll need to load the Keystore (you can read how to generate it on Android's official documentation).
- name: Load keystore
run: |
echo "${{ secrets.KEYSTORE_FILE_CONTENTS }}" | base64 -d > keystore.jks && \
The secret KEYSTORE_FILE_CONTENTS, contains the base64 encoded content of the keystore.jks file you generated. You can get the text for the secret by running cat keystore.jks | base64 -w0.
cat <<EOL > local.properties
storeFilePath=$PWD/keystore.jks
storePassword=${{ secrets.RELEASE_STORE_PASSWORD }}
keyAlias=${{ secrets.RELEASE_KEY_ALIAS }}
keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }}
EOL
The rest of the secrets are the ones you entered when configuring your keystore.
Next, we'll build the APK:
- name: Build Release APK
run: ./gradlew assembleRelease
env:
GRADLE_USER_HOME: ./gradle-config
And set the current directory as a safe repository, as this is a known issue with actions/checkout@v3. And because we'll later use github-cli to do the release, I didn't want it to complain that it couldn't read the repository.
- name: Set current directory as a safe repository
run: git config --global --add safe.directory /github/workspace
- uses: ButterCam/setup-github-cli@master
Finally, release the APK and upload it to the repository's releases page.
- name: Release using github cli
run: gh release create ${GITHUB_REF##*/} ./app/build/outputs/apk/release/**.apk
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
You'll need to generate a token with repo access for this to work. For some reason, using the default repository's GITHUB_TOKEN won't work.
And here's the full YAML in case you want to copy-paste it. You can also check it in my repository.
name: Release APK
on:
push:
tags:
- '*'
jobs:
Release:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v3
- name: setup jdk
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'temurin'
- name: Load keystore
run: |
echo "${{ secrets.KEYSTORE_FILE_CONTENTS }}" | base64 -d > keystore.jks && \
cat <<EOL > local.properties
storeFilePath=$PWD/keystore.jks
storePassword=${{ secrets.RELEASE_STORE_PASSWORD }}
keyAlias=${{ secrets.RELEASE_KEY_ALIAS }}
keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }}
EOL
- name: Build Release APK
run: ./gradlew assembleRelease
env:
GRADLE_USER_HOME: ./gradle-config
- name: Set current directory as a safe repository
run: git config --global --add safe.directory /github/workspace
- uses: ButterCam/setup-github-cli@master
- name: Release using github cli
run: gh release create ${GITHUB_REF##*/} ./app/build/outputs/apk/release/**.apk
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
There's still one thing that needs configuration to sign the APK properly. You'll need to edit your app/build.gradle.kts file so we can feed the properties from GitHub secrets to the assmbleRelease task. Kudos to Willi Metzel's Stack Overflow answer. Inside android in app/build.gradle.kts add:
signingConfigs {
create("release") {
val properties = Properties().apply {
load(File("local.properties").reader())
}
storeFile = File(properties.getProperty("storeFilePath"))
storePassword = properties.getProperty("storePassword")
keyPassword = properties.getProperty("keyPassword")
keyAlias = properties.getProperty("keyAlias")
}
}
Then, add signingConfig = signingConfigs.getByName("release") to release inside buildTypes. It should look something like:
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("release")
}
}
See here for a complete reference to my app/build.gradle.kts.
Credits to r0adkll for his previous work; without it, building this would have been more difficult.
You can follow me at GitHub (@ivanvc). And check the repository (and source code for my grayscale switching app) if you're interested.
Top comments (4)
Auto build means , automatically sent to internal testing to Google play console?
No, currently, it only uploads the generated APK to GitHub releases. I plan on doing that later.
This is super helpful! 🙌 I'm trying to build a simple game APK—do you think this GitHub Actions setup would work for games too, or is the process different for game engines like Unity or Godot?
Some comments may only be visible to logged-in visitors. Sign in to view all comments.