5 Commits

Author SHA1 Message Date
Hermes
56a7103503 ci: bump APK versionCode and timestamp AAB names
Some checks failed
Android build / build (push) Successful in 15m22s
Android build / build (release) Failing after 12m34s
2026-08-31 15:06:03 -05:00
Hermes
f7722216a0 build: upgrade AGP for Android 16 support
All checks were successful
Android build / build (push) Successful in 16m36s
Android build / build (release) Successful in 13m37s
2026-08-31 13:31:01 -05:00
Hermes
8af42dbe48 build: target Android 16 / API 36
All checks were successful
Android build / build (push) Successful in 19m59s
2026-08-31 12:18:31 -05:00
Hermes
ebd7910b32 fix: resolve MindMachine release keystore path from repo root
All checks were successful
Android build / build (push) Successful in 11m29s
Android build / build (release) Successful in 11m56s
2026-08-29 14:03:23 -05:00
Hermes
c2a78e1a73 ci: align MindMachine Android workflow with e-Sun setup
Some checks failed
Android build / build (push) Successful in 15m28s
Android build / build (release) Failing after 8m10s
2026-08-29 13:30:22 -05:00
4 changed files with 201 additions and 17 deletions

View File

@@ -0,0 +1,173 @@
name: Android build
permissions:
contents: read
releases: write
on:
push:
branches:
- '**'
pull_request:
release:
types:
- published
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Java 17
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
- name: Install Android SDK command-line tools and packages
shell: bash
run: |
set -euxo pipefail
export ANDROID_SDK_ROOT="$HOME/.android/sdk"
export ANDROID_HOME="$ANDROID_SDK_ROOT"
mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools"
if [ ! -x "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" ]; then
tools_url="$(curl -fsSL https://developer.android.com/studio | grep -o 'https://dl.google.com/android/repository/commandlinetools-linux-[0-9][0-9]*_latest.zip' | head -n 1)"
test -n "$tools_url"
curl -fsSL -o /tmp/commandlinetools.zip "$tools_url"
rm -rf "$ANDROID_SDK_ROOT/cmdline-tools/latest" "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools"
unzip -q /tmp/commandlinetools.zip -d "$ANDROID_SDK_ROOT/cmdline-tools"
mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest"
fi
export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH"
set +o pipefail
yes | sdkmanager --licenses >/dev/null
set -o pipefail
sdkmanager \
"platform-tools" \
"platforms;android-36" \
"build-tools;36.0.0"
- name: Prepare optional release signing
if: github.event_name == 'release'
continue-on-error: true
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
shell: bash
run: |
set -euo pipefail
missing=()
for key in ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD; do
if [ -z "${!key:-}" ]; then
missing+=("$key")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
printf -v missing_csv '%s, ' "${missing[@]}"
missing_csv="${missing_csv%, }"
echo "::error::Release signing secrets missing: ${missing_csv}. Continuing with unsigned/default-signed release AAB."
exit 1
fi
mkdir -p .ci-secrets
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > .ci-secrets/release-keystore.jks
cat > keystore.properties <<EOF
storeFile=.ci-secrets/release-keystore.jks
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
keyPassword=$ANDROID_KEY_PASSWORD
EOF
- name: Make Gradle wrapper executable
run: chmod +x gradlew
- name: Write Android SDK location
shell: bash
run: |
set -euxo pipefail
printf 'sdk.dir=%s/.android/sdk\n' "$HOME" > local.properties
- name: Prepare CI build metadata
id: build_meta
shell: bash
run: |
set -euxo pipefail
timestamp_utc="$(date -u +%Y%m%d-%H%M%S)"
version_code="$(date -u +%s)"
project_name="$(basename "$GITHUB_REPOSITORY")"
python3 - "$version_code" <<'PY'
from pathlib import Path
import re, sys
path = Path('app/build.gradle.kts')
text = path.read_text(encoding='utf-8')
new_text, count = re.subn(r'(\bversionCode\s*=\s*)\d+', rf'\g<1>{sys.argv[1]}', text, count=1)
if count != 1:
raise SystemExit('versionCode not found in app/build.gradle.kts')
path.write_text(new_text, encoding='utf-8')
PY
echo "Using CI versionCode: $version_code"
echo "project_name=$project_name" >> "$GITHUB_OUTPUT"
echo "timestamp_utc=$timestamp_utc" >> "$GITHUB_OUTPUT"
echo "version_code=$version_code" >> "$GITHUB_OUTPUT"
- name: Build debug APK
if: github.event_name != 'release'
shell: bash
run: |
set -euxo pipefail
export ANDROID_SDK_ROOT="$HOME/.android/sdk"
export ANDROID_HOME="$ANDROID_SDK_ROOT"
./gradlew --no-daemon clean assembleDebug
- name: Build release AAB
if: github.event_name == 'release'
shell: bash
run: |
set -euxo pipefail
export ANDROID_SDK_ROOT="$HOME/.android/sdk"
export ANDROID_HOME="$ANDROID_SDK_ROOT"
./gradlew --no-daemon bundleRelease
- name: Rename release AAB for upload
if: github.event_name == 'release'
id: release_aab
shell: bash
run: |
set -euxo pipefail
aab="$(find app/build/outputs/bundle/release -name '*.aab' | head -n 1)"
renamed="app/build/outputs/bundle/release/${{ steps.build_meta.outputs.project_name }}-${{ steps.build_meta.outputs.timestamp_utc }}-release.aab"
mv -f "$aab" "$renamed"
echo "Renamed release AAB to $(basename "$renamed")"
echo "path=$renamed" >> "$GITHUB_OUTPUT"
- name: Upload debug APK
if: github.event_name != 'release'
uses: actions/upload-artifact@v3
with:
name: debug-apk
path: app/build/outputs/apk/debug/*.apk
if-no-files-found: error
- name: Attach release AAB to Gitea release
if: github.event_name == 'release'
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
shell: bash
run: |
set -euxo pipefail
release_id="$(python3 -c 'import json, os; print(json.load(open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8"))["release"]["id"])')"
aab="${{ steps.release_aab.outputs.path }}"
curl --fail-with-body \
--request POST \
--header "Authorization: token ***" \
--form "attachment=@${aab}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=$(basename "$aab")"

View File

@@ -1,3 +1,5 @@
import java.util.Properties
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
@@ -5,41 +7,51 @@ plugins {
id("org.jetbrains.kotlin.plugin.compose") id("org.jetbrains.kotlin.plugin.compose")
} }
import java.util.Properties val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystorePropertiesFile.inputStream().use { keystoreProperties.load(it) }
}
val hasReleaseSigning = listOf(
"storeFile",
"storePassword",
"keyAlias",
"keyPassword",
).all { !keystoreProperties.getProperty(it).isNullOrBlank() }
android { android {
namespace = "solutions.tretter.mindmachine" namespace = "solutions.tretter.mindmachine"
compileSdk = 35 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "solutions.tretter.mindmachine" applicationId = "solutions.tretter.mindmachine"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 36
versionCode = 18 versionCode = 18
versionName = "1.0.13" versionName = "1.0.13"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { signingConfigs {
signingConfigs { if (hasReleaseSigning) {
create("release") { create("release") {
val propsFile = rootProject.file("keystore/upload-keystore.properties") storeFile = rootProject.file(keystoreProperties.getProperty("storeFile"))
if (propsFile.exists()) { storePassword = keystoreProperties.getProperty("storePassword")
val props = Properties().apply { propsFile.inputStream().use { this.load(it) } } keyAlias = keystoreProperties.getProperty("keyAlias")
storeFile = rootProject.file(props.getProperty("storeFile")) keyPassword = keystoreProperties.getProperty("keyPassword")
storePassword = props.getProperty("storePassword")
keyAlias = props.getProperty("keyAlias")
keyPassword = props.getProperty("keyPassword")
}
} }
} }
}
buildTypes {
debug { debug {
buildConfigField("boolean", "DEBUG_AD_FREE", "true") buildConfigField("boolean", "DEBUG_AD_FREE", "true")
} }
release { release {
signingConfig = signingConfigs.getByName("release") if (hasReleaseSigning) {
signingConfig = signingConfigs.getByName("release")
}
isMinifyEnabled = false isMinifyEnabled = false
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
@@ -88,7 +100,6 @@ dependencies {
implementation("androidx.compose.material:material-icons-extended") implementation("androidx.compose.material:material-icons-extended")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
// Monetization
implementation("com.google.android.gms:play-services-ads:23.1.0") implementation("com.google.android.gms:play-services-ads:23.1.0")
implementation("com.android.billingclient:billing-ktx:8.0.0") implementation("com.android.billingclient:billing-ktx:8.0.0")

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("com.android.application") version "8.5.2" apply false id("com.android.application") version "8.10.0" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false
id("org.jetbrains.kotlin.plugin.serialization") version "2.1.0" apply false id("org.jetbrains.kotlin.plugin.serialization") version "2.1.0" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.1.0" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.1.0" apply false

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME