Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
version: 2.1

orbs:
flutter: circleci/flutter@3.0.0


executors:
android-flutter:
docker:
- image: cimg/android:2025.12
working_directory: ~/project
environment:
JVM_OPTS: -Xmx3200m
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2

jobs:
build:
executor: android-flutter
steps:
- checkout

- run:
name: Extract and sanitize branch name
command: |
SANITIZED_BRANCH="${CIRCLE_BRANCH//\//-}"
echo "export SANITIZED_BRANCH=$SANITIZED_BRANCH" >> $BASH_ENV
echo "Sanitized branch: $SANITIZED_BRANCH"

- restore_cache:
keys:
- gradle-cache-v1-{{ checksum "app/build.gradle.kts" }}
- gradle-cache-v1-

- restore_cache:
keys:
- flutter-dart-tool-v1-{{ checksum "flutter_module/pubspec.lock" }}
- flutter-dart-tool-v1-

- flutter/install_sdk_and_pub:
version: 3.35.6
channel: stable
app_dir: flutter_module

- run:
name: Accept Android licenses
command: yes | flutter doctor --android-licenses || true

- run:
name: Run Flutter doctor
command: flutter doctor -v

- run:
name: Run Flutter unit tests
working_directory: flutter_module
command: |
flutter pub get
flutter test --coverage --machine > test-results.json || true
flutter test --coverage
mkdir test-results
cp test-results.json test-results

- store_test_results:
path: flutter_module/test-results

- store_artifacts:
path: flutter_module/test-results/test-results.json
destination: test-results/flutter-test-results.json

- run:
name: Decode Keystore
command: |
echo "$KEYSTORE_BASE64" | base64 -d > app/keystore.jks

- run:
name: Create keystore.properties
command: |
echo "storePassword=$KEYSTORE_PASSWORD" > keystore.properties
echo "keyPassword=$KEY_PASSWORD" >> keystore.properties
echo "keyAlias=$KEY_ALIAS" >> keystore.properties
echo "storeFile=keystore.jks" >> keystore.properties

- run:
name: Grant execute permission for gradlew
command: chmod +x gradlew

- run:
name: Build Release APK
command: ./gradlew assembleRelease --stacktrace

- save_cache:
key: gradle-cache-v1-{{ checksum "app/build.gradle.kts" }}
paths:
- ~/.gradle
- .gradle

- save_cache:
key: flutter-dart-tool-v1-{{ checksum "flutter_module/pubspec.lock" }}
paths:
- flutter_module/.dart_tool

- store_artifacts:
path: app/build/outputs/apk/release/app-release.apk
destination: app-release-${SANITIZED_BRANCH}-${CIRCLE_BUILD_NUM}.apk

- run:
name: Rename APK for storage
command: |
mkdir -p ~/artifacts
cp app/build/outputs/apk/release/app-release.apk ~/artifacts/app-release-${SANITIZED_BRANCH}-${CIRCLE_BUILD_NUM}.apk

- store_artifacts:
path: ~/artifacts
destination: apk

- store_artifacts:
path: flutter_module/coverage
destination: coverage

workflows:
build-and-deploy:
jobs:
- build:
context: android-build
42 changes: 28 additions & 14 deletions .github/workflows/build-apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ jobs:
- name: Extract branch name
id: extract_branch
shell: bash
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
run: |
BRANCH_NAME="${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
SANITIZED_BRANCH="${BRANCH_NAME//\//-}"
echo "branch=${SANITIZED_BRANCH}" >> $GITHUB_OUTPUT

- name: Set up JDK 17
uses: actions/setup-java@v4
Expand All @@ -32,33 +35,44 @@ jobs:
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
flutter-version: '3.35.6'
channel: 'stable'
cache: true

- name: Accept Android licenses
run: yes | flutter doctor --android-licenses

- name: Run Flutter doctor
run: flutter doctor -v

- name: Install Flutter dependencies
working-directory: ./flutter_module
run: flutter pub get

- name: Run Flutter unit tests
working-directory: ./flutter_module
run: flutter test --coverage

- name: Decode Keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > app/keystore.jks

- name: Create keystore.properties
run: |
echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > keystore.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> keystore.properties
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> keystore.properties
echo "storeFile=keystore.jks" >> keystore.properties

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build Debug APK
run: ./gradlew assembleDebug --stacktrace

- name: Build Release APK
run: ./gradlew assembleRelease --stacktrace

- name: Upload Debug APK
uses: actions/upload-artifact@v4
with:
name: app-debug-${{ steps.extract_branch.outputs.branch }}-${{ github.run_number }}
path: app/build/outputs/apk/debug/app-debug.apk
retention-days: 30


- name: Upload Release APK
uses: actions/upload-artifact@v4
with:
name: app-release-${{ steps.extract_branch.outputs.branch }}-${{ github.run_number }}
path: app/build/outputs/apk/release/app-release-unsigned.apk
path: app/build/outputs/apk/release/app-release.apk
retention-days: 30
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ google-services.json
# Android Profiling
*.hprof
nul
app/keystore.properties
squash_from_commit.sh
log.sh
squash_commits.sh
24 changes: 24 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import java.util.Properties
import java.io.FileInputStream

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
Expand All @@ -6,6 +9,13 @@ plugins {
id("kotlin-kapt")
}

// Load keystore properties
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}

android {
namespace = "com.example.myapplication"
compileSdk {
Expand All @@ -22,13 +32,27 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

signingConfigs {
create("release") {
if (keystorePropertiesFile.exists()) {
storeFile = file(keystoreProperties.getProperty("storeFile") ?: "keystore.jks")
storePassword = keystoreProperties.getProperty("storePassword")
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
}
}
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
if (keystorePropertiesFile.exists()) {
signingConfig = signingConfigs.getByName("release")
}
}
}

Expand Down
Loading