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
121 changes: 121 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: Android Build

on:
push:
branches: [main]
paths:
- 'android/**'
- '.github/workflows/android.yml'
pull_request:
paths:
- 'android/**'
- '.github/workflows/android.yml'
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: android

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: 8.9

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('android/**/*.gradle*', 'android/**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Generate Gradle wrapper
run: gradle wrapper --gradle-version 8.9

- name: Build debug APK
run: ./gradlew assembleDebug --no-daemon

- name: Run unit tests
run: ./gradlew testDebugUnitTest --no-daemon
continue-on-error: true

- name: Upload debug APK
uses: actions/upload-artifact@v4
with:
name: app-debug
path: android/app/build/outputs/apk/debug/app-debug.apk
retention-days: 7

release:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
defaults:
run:
working-directory: android

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: 8.9

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('android/**/*.gradle*', 'android/**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Generate Gradle wrapper
run: gradle wrapper --gradle-version 8.9

- name: Build release APK (unsigned)
run: ./gradlew assembleRelease --no-daemon

- name: Upload release APK
uses: actions/upload-artifact@v4
with:
name: app-release-unsigned
path: android/app/build/outputs/apk/release/app-release-unsigned.apk
retention-days: 30

# Note: For actual Play Store deployment, you would need to:
# 1. Set up signing keystore from secrets
# 2. Sign the APK or build AAB
# 3. Upload to Play Store using fastlane or Google Play Developer API

- name: Release step placeholder
run: |
echo "Release step placeholder"
echo "In production, this would:"
echo "1. Decode signing keystore from secrets"
echo "2. Sign the release APK or build signed AAB"
echo "3. Upload to Google Play Console"
104 changes: 104 additions & 0 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: iOS Build

on:
push:
branches: [main]
paths:
- 'ios/**'
- '.github/workflows/ios.yml'
pull_request:
paths:
- 'ios/**'
- '.github/workflows/ios.yml'
workflow_dispatch:

jobs:
build:
runs-on: macos-14
defaults:
run:
working-directory: ios

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Select Xcode version
run: sudo xcode-select -s /Applications/Xcode_15.2.app

- name: Show Xcode version
run: xcodebuild -version

- name: Cache Swift Package Manager
uses: actions/cache@v4
with:
path: |
ios/.build
~/Library/Caches/org.swift.swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('ios/Package.swift') }}
restore-keys: |
${{ runner.os }}-spm-

- name: Resolve Swift packages
run: swift package resolve

- name: Build for iOS Simulator
run: |
xcodebuild build \
-scheme MySpeedPuzzling \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2' \
-configuration Debug \
CODE_SIGNING_ALLOWED=NO \
| xcpretty

- name: Run tests
run: |
xcodebuild test \
-scheme MySpeedPuzzling \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2' \
-configuration Debug \
CODE_SIGNING_ALLOWED=NO \
| xcpretty
continue-on-error: true

archive:
runs-on: macos-14
needs: build
if: github.ref == 'refs/heads/main'
defaults:
run:
working-directory: ios

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Select Xcode version
run: sudo xcode-select -s /Applications/Xcode_15.2.app

- name: Cache Swift Package Manager
uses: actions/cache@v4
with:
path: |
ios/.build
~/Library/Caches/org.swift.swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('ios/Package.swift') }}
restore-keys: |
${{ runner.os }}-spm-

- name: Resolve Swift packages
run: swift package resolve

# Note: For actual App Store deployment, you would need to:
# 1. Set up code signing certificates and provisioning profiles
# 2. Use fastlane or manual xcodebuild archive commands
# 3. Upload to App Store Connect using xcrun altool or fastlane deliver

- name: Archive for distribution (dry run)
run: |
echo "Archive step placeholder"
echo "In production, this would:"
echo "1. Import signing certificates from secrets"
echo "2. Build and archive the app"
echo "3. Export IPA for App Store"
echo "4. Upload to App Store Connect"
55 changes: 55 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Gradle
.gradle/
build/
!gradle/wrapper/gradle-wrapper.jar

# Android Studio
*.iml
.idea/
*.hprof

# Local configuration
local.properties
secrets.properties

# Keystore files
*.jks
*.keystore

# Google Services
google-services.json

# Proguard
proguard/

# Log Files
*.log

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Kotlin
.kotlin/

# Caches
.cxx/

# Environment files
.env
.env.*
!.env.example

# Generated files
*.apk
*.aab
*.ap_
*.dex

# Native
obj/
88 changes: 88 additions & 0 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}

android {
namespace = "com.myspeedpuzzling.app"
compileSdk = 35

defaultConfig {
applicationId = "com.myspeedpuzzling.app"
minSdk = 28
targetSdk = 35
versionCode = 1
versionName = "1.0.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
isDebuggable = true
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
}

buildFeatures {
viewBinding = true
buildConfig = true
}
}

dependencies {
// Hotwire Native Android
implementation("dev.hotwire:core:1.2.4")
implementation("dev.hotwire:navigation-fragments:1.2.4")

// AndroidX
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.activity:activity-ktx:1.8.2")
implementation("androidx.fragment:fragment-ktx:1.6.2")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.webkit:webkit:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")

// Material Design
implementation("com.google.android.material:material:1.11.0")

// CameraX for barcode scanning
implementation("androidx.camera:camera-core:1.3.1")
implementation("androidx.camera:camera-camera2:1.3.1")
implementation("androidx.camera:camera-lifecycle:1.3.1")
implementation("androidx.camera:camera-view:1.3.1")

// ML Kit Barcode Scanning
implementation("com.google.mlkit:barcode-scanning:17.2.0")

// Google Play Billing
implementation("com.android.billingclient:billing-ktx:6.1.0")

// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")

// OkHttp for API calls
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("org.json:json:20231013")

// Testing
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
27 changes: 27 additions & 0 deletions android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.

# Keep JavaScript interface methods
-keepclassmembers class com.myspeedpuzzling.features.BarcodeScannerBridge {
@android.webkit.JavascriptInterface <methods>;
}

-keepclassmembers class com.myspeedpuzzling.billing.BillingBridge {
@android.webkit.JavascriptInterface <methods>;
}

# Keep Hotwire Turbo classes
-keep class dev.hotwire.turbo.** { *; }

# Keep Google Play Billing classes
-keep class com.android.vending.billing.** { *; }

# OkHttp
-dontwarn okhttp3.**
-dontwarn okio.**
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }

# ML Kit
-keep class com.google.mlkit.** { *; }
Loading
Loading