Skip to content

Build all flavors

Build all flavors #57

name: Build all flavors
on:
schedule:
# Gotta wait until contributors.json is updated
- cron: '0 0 * * 0' # Every Sunday at 0AM
# Allow manual trigger
workflow_dispatch:
# Prevent multiple jobs from running at the same time
concurrency:
group: 'weekly-deploy'
cancel-in-progress: false # Don't cancel any in-progress runs in this group
jobs:
build_time:
name: Capture current time
runs-on: ubuntu-latest
# Set date as a variable
outputs:
date: ${{ steps.date.outputs.date }}
steps:
- name: Get date
id: date
# Output of "October 2 2024" will be "20241002"
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
versioning:
name: Extract version
runs-on: ubuntu-latest
# Set versions as a variable
outputs:
# Current version in repository
downstream: ${{ steps.downstream.outputs.version }}
# Current version code in repository
code: ${{ steps.downstream.outputs.code }}
# Latest build's version
upstream: ${{ steps.upstream.outputs.version }}
env:
GITHUB_REPOSITORY: ${{ github.action_repository }}
steps:
- uses: actions/checkout@v4.2.1
with:
submodules: true
- name: Get downstream (local) version
id: downstream
# Output is current version located inside composeApp/build.gradle.kts
# android {
# defaultConfig {
# versionName = "..."
# }
# }
run: |
echo "version=$(grep -E '^\s*versionName\s*=' composeApp/build.gradle.kts | awk -F '"' '{print $2}')" >> $GITHUB_OUTPUT
echo "code=$(grep -E '^\s*versionCode\s*=' composeApp/build.gradle.kts | awk -F '= ' '{print $2}')" >> $GITHUB_OUTPUT
- name: Get upstream version
id: upstream
# Fetch tag_name of latest tag from GitHub.
# tag_name contains "v" prefix, so it must be removed
# before adding to GITHUB_OUTPUT
run: |
tag_name="$(curl -s https://api.github.com/repos/$GITHUB_REPOSITORY/releases/latest | jq -r .tag_name)"
echo "version=${tag_name#v}" >> $GITHUB_OUTPUT
verify-version:
needs: [versioning]
name: Verify versions
runs-on: ubuntu-latest
steps:
- name: Whether build can proceed
run: |
if [ "${{ needs.versioning.outputs.downstream }}" = "${{ needs.versioning.outputs.upstream }}" ]; then
exit 1
fi
- uses: actions/checkout@v4.2.1
with:
submodules: true
- name: Whether changelogs exists
run: |
if [ ! -e "fastlane/metadata/android/en-US/changelogs/${{ needs.versioning.outputs.code }}.txt" ]; then
exit 1
fi
build-uncompressed:
needs: [versioning, verify-version]
name: Build uncompressed version
runs-on: ubuntu-latest
timeout-minutes: 60 # Prevent Github Action from terminating this workflow on first run
steps:
- uses: actions/checkout@v4.2.1
with:
submodules: true
- name: Copy changelogs into res/raw
# Job should be canceled if file doesn't exist
run: cp "fastlane/metadata/android/en-US/changelogs/${{ needs.versioning.outputs.code }}.txt" "composeApp/src/androidMain/res/raw/release_notes.txt"
- name: Setup Java 21
uses: actions/setup-java@v4.7.1
with:
java-version: "21"
distribution: "corretto"
- name: Restore Gradle dependencies & build cache
uses: actions/cache@v4.2.3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
./build
./composeApp/build
# Cache key has flavor's name to prevent override each other
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- name: Build with Gradle
run: ./gradlew assembleGithubUncompressed
- name: Upload artifacts for signing
uses: actions/upload-artifact@v4.6.2
with:
name: unsigned-uncompressed
path: |
composeApp/build/outputs/apk/github/uncompressed/*.apk
build-release:
needs: [versioning, verify-version]
name: Build release version
runs-on: ubuntu-latest
timeout-minutes: 60 # Prevent Github Action from terminating this workflow on first run
steps:
- uses: actions/checkout@v4.2.1
with:
submodules: true
- name: Copy changelogs into res/raw
# Job should be canceled if file doesn't exist
run: cp "fastlane/metadata/android/en-US/changelogs/${{ needs.versioning.outputs.code }}.txt" "composeApp/src/androidMain/res/raw/release_notes.txt"
- name: Setup Java 21
uses: actions/setup-java@v4.7.1
with:
java-version: "21"
distribution: "corretto"
- name: Restore Gradle dependencies & build cache
uses: actions/cache@v4.2.3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
./build
./composeApp/build
# Cache key has flavor's name to prevent override each other
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- name: Build with Gradle
run: ./gradlew assembleGithubRelease
- name: Upload artifacts for signing
uses: actions/upload-artifact@v4.6.2
with:
name: unsigned-release
path: |
composeApp/build/outputs/apk/github.release/*.apk
build-izzy:
needs: [versioning, verify-version]
name: Build Izzy version
runs-on: ubuntu-latest
timeout-minutes: 60 # Prevent Github Action from terminating this workflow on first run
steps:
- uses: actions/checkout@v4.2.1
with:
submodules: true
- name: Copy changelogs into res/raw
# Job should be canceled if file doesn't exist
run: cp "fastlane/metadata/android/en-US/changelogs/${{ needs.versioning.outputs.code }}.txt" "composeApp/src/androidMain/res/raw/release_notes.txt"
- name: Setup Java 21
uses: actions/setup-java@v4.7.1
with:
java-version: "21"
distribution: "corretto"
- name: Restore Gradle dependencies & build cache
uses: actions/cache@v4.2.3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
./build
./composeApp/build
# Cache key has flavor's name to prevent override each other
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- name: Build with Gradle
run: ./gradlew assembleIzzyRelease
- name: Upload artifacts for signing
uses: actions/upload-artifact@v4.6.2
with:
name: unsigned-izzy
path: |
composeApp/build/outputs/apk/izzy/release/*.apk
sign-apks:
name: Sign all built APKs
needs:
- build-uncompressed
- build-release
- build-izzy
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4.3.0
with:
# Destination path. Supports basic tilde expansion.
# Optional. Default is $GITHUB_WORKSPACE
path: upstream/unsigned
# When multiple artifacts are matched, this changes the behavior of the destination directories.
# If true, the downloaded artifacts will be in the same directory specified by path.
# If false, the downloaded artifacts will be extracted into individual named directories within the specified path.
# Optional. Default is 'false'
merge-multiple: true
- name: Sign APKs
uses: Tlaster/android-sign@v1.2.2
with:
releaseDirectory: upstream/unsigned
signingKeyBase64: "${{ secrets.KREATE_KEYSTORE }}"
keyStorePassword: "${{ secrets.KREATE_KEYSTORE_PASSWD }}"
alias: "${{ secrets.KREATE_KEY_ALIAS }}"
keyPassword: "${{ secrets.KREATE_KEY_PASSWD }}"
output: signed
env:
BUILD_TOOLS_VERSION: "34.0.0"
- name: Remove trails # remove "-signed"
run: |
for filename in signed/*.apk; do mv "$filename" "${filename//-signed}"; done
- name: Upload for release
uses: actions/upload-artifact@v4.6.2
with:
name: signed-apks
path: signed/*.apk
upload-to-release:
needs: [build_time, versioning, sign-apks]
runs-on: ubuntu-latest
steps:
- name: Download signed APKs
uses: actions/download-artifact@v4.3.0
with:
name: signed-apks
- name: Upload built APK to release
uses: softprops/action-gh-release@v2
with:
files: '*.apk'
# Name: v0.0.1-20250303 | Weekly Build
name: v${{ needs.versioning.outputs.downstream }}-${{ needs.build_time.outputs.date }} | Weekly Build
tag_name: v${{ needs.versioning.outputs.downstream }}
make-latest: "true"
body: |
## What's the difference between `Kreate-minified.apk` and `Kreate-full.apk`
TL;DR: **No difference.**
> [This article](https://kreate.knighthat.me/usr/faq/minified_and_full) explains this matter in detail.
## What's `Kreate-izzy.apk`
This is APK built specifically for IzzyOnDroid with update checker disabled. You shouldn't
download this version here.
## Verification
> Always check for signature before installing any app you downloaded from Github or any other APK distributors.\
### Public key hashes
| Algorithm | Hash digest |
|----------------|------------------------------------------------------------------|
| SHA-256 | 9dadd5c4bbfb59174bca523dd10b66bedbbf7b2e00630fa990d140a6a17ce7a5 |
| SHA-1 | f49a497bd47322c90e9f534ff945ac05f3a8e77a |
| MD5 | d4fc781f4a5ffc10434cb84d93706eba |
### Certificate hashes
| Algorithm | Hash digest |
|----------------|------------------------------------------------------------------|
| SHA-256 | 1bd03a8de5df4dbd7faddb81b9f2aaf55681a584a93d6fb47e9a5ccc736ef7ac |
| SHA-1 | 1690571d0d8b8d54c43a4b9460a2a2bc5f67e9bc |
| MD5 | 320e604e315a0abb177e8d7570dcf4dc |
## FAQ
<details>
<summary>Q1: How do I download your build?</summary>
<blockquote>
Right below this article, there are links to prebuilt APKs.<br>
Select the one that fits your need to start the download.
</blockquote>
</details>
<details>
<summary>Q2: How verify build's signature?</summary>
<blockquote>
There are 2 main methods:
<ol>
<li>
Built-in <a href="https://stackoverflow.com/questions/7104624/how-do-i-verify-that-an-android-apk-is-signed-with-a-release-certificate" target="_blank" rel="noopener noreferrer">jarsigner</a>
</li>
<li>
<a href="https://developer.android.com/tools/apksigner#options-verify" target="_blank" rel="noopener noreferrer">apksigner</a> from AndroidSDK
</li>
</ol>
</blockquote>
</details>
## Changelogs
Please visit [wiki/changelogs](https://github.com/knighthat/Kreate/wiki/Changelogs) for details.
token: ${{ secrets.RELEASE_TOKEN }}
generate_release_notes: true