diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml
index 89392a316..b17758cc6 100644
--- a/.github/workflows/actions.yml
+++ b/.github/workflows/actions.yml
@@ -4,6 +4,7 @@ on:
push:
branches:
- master
+ - feature/compose-ui
- test/**
pull_request:
types: [opened, synchronize, reopened]
@@ -48,6 +49,8 @@ jobs:
- name: Setup Android SDK
uses: android-actions/setup-android@v4
+ with:
+ cmdline-tools-version: '9477386'
- name: Install Android SDK components
run: |
@@ -66,21 +69,29 @@ jobs:
echo "${{ secrets.RUNALYZE }}" > $GITHUB_WORKSPACE/runalyze.properties
chmod +x gradlew
- - name: Build bundle
- run: ./gradlew :app:bundleLatestRelease :wear:bundleRelease
+ - name: Build AAB and APK
+ run: ./gradlew :app:bundleLatestRelease :app:assembleLatestRelease :wear:bundleRelease --stacktrace --info
+
+ - name: Find APK files
+ run: |
+ echo "Searching for all APK files..."
+ find app/build -name "*.apk" -type f
+ echo "Listing apk directory structure..."
+ ls -la app/build/outputs/apk/ || echo "APK directory not found"
- name: Upload build logs
if: always()
uses: actions/upload-artifact@v7
with:
name: build-bundle
- # possibly include: app/build/outputs/bundle/latestRelease/ wear/build/outputs/bundle/release/
path: |
**/build/outputs/logs/
+ app/build/outputs/bundle/latestRelease/*.aab
+ app/build/outputs/apk/latest/release/*.apk
+ wear/build/outputs/bundle/release/*.aab
- name: Test
run: ./gradlew test
-
- name: Upload test logs
if: always()
uses: actions/upload-artifact@v7
@@ -128,3 +139,15 @@ jobs:
name: fdroid-logs
path: |
build/reports/problems/
+
+ - name: List F-Droid APK (for debug)
+ run: ls -la app/build/outputs/apk/latestRelease/ || echo "Directory not found"
+
+ - name: Upload F-Droid APK
+ if: always()
+ uses: actions/upload-artifact@v7
+ with:
+ name: fdroid-apk
+ path: |
+ app/build/outputs/apk/latest/release/*.apk
+
diff --git a/README.md b/README.md
index 9e665c4e5..016d32865 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+20260712
RunnerUp
========
diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
index 6b112a6da..fb0e0c337 100644
--- a/app/AndroidManifest.xml
+++ b/app/AndroidManifest.xml
@@ -67,14 +67,23 @@
tools:ignore="UnusedAttribute"
android:dataExtractionRules="@xml/data_extraction_rules">
+
+
+
+
+
+
-
+
diff --git a/app/build.gradle b/app/build.gradle
index da9f33c51..1afbb9a8c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,10 +1,16 @@
-apply plugin: 'com.android.application'
+// apply plugin: 'com.android.application'
+// apply plugin: 'kotlin-android'
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+}
def getGitHash = providers.exec {
commandLine('git', 'rev-parse', '--short', 'HEAD')
}.standardOutput.asText.get().strip()
android {
+ compileSdk 34
buildToolsVersion = rootProject.ext.buildToolsVersion
namespace = 'org.runnerup'
@@ -13,28 +19,55 @@ android {
targetCompatibility = JavaVersion.toVersion("17")
}
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+
sourceSets {
+ // main {
+ // manifest.srcFile 'AndroidManifest.xml'
+ // java.srcDirs = ['src/main']
+ // if (rootProject.ext.allowNonFree) {
+ // java.srcDirs += ['src/play']
+ // } else {
+ // java.srcDirs += ['src/nonplay']
+ // }
+ // if (rootProject.ext.enableWear) {
+ // java.srcDirs += ['src/wear']
+ // } else {
+ // java.srcDirs += ['src/nonwear']
+ // }
+ // if (rootProject.ext.noMap) {
+ // java.srcDirs += ['src/nomap']
+ // } else if (rootProject.ext.mapboxEnabled) {
+ // java.srcDirs += ['src/mapbox']
+ // } else {
+ // java.srcDirs += ['src/osmdroid']
+ // }
+ // res.srcDirs = ['res']
+ // assets.srcDirs = ['assets']
+ // }
main {
manifest.srcFile 'AndroidManifest.xml'
- java.srcDirs = ['src/main']
+ java.srcDirs = ['src/main/java'] // 明确指定
if (rootProject.ext.allowNonFree) {
- java.srcDirs += ['src/play']
+ java.srcDirs += ['src/play/java'] // 明确指定
} else {
- java.srcDirs += ['src/nonplay']
+ java.srcDirs += ['src/nonplay/java'] // 明确指定
}
if (rootProject.ext.enableWear) {
- java.srcDirs += ['src/wear']
+ java.srcDirs += ['src/wear/java'] // 明确指定
} else {
- java.srcDirs += ['src/nonwear']
+ java.srcDirs += ['src/nonwear/java'] // 明确指定
}
if (rootProject.ext.noMap) {
- java.srcDirs += ['src/nomap']
+ java.srcDirs += ['src/nomap/java'] // 明确指定
} else if (rootProject.ext.mapboxEnabled) {
- java.srcDirs += ['src/mapbox']
+ java.srcDirs += ['src/mapbox/java'] // 明确指定
} else {
- java.srcDirs += ['src/osmdroid']
+ java.srcDirs += ['src/osmdroid/java'] // 明确指定
}
- // renderscript.srcDirs = java.srcDirs
+ // 资源目录保持不变
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
@@ -45,9 +78,8 @@ android {
productFlavors {
latest {
dimension = "all"
- // multidexing support, min play support
minSdk = rootProject.ext.minSdk
- compileSdk = rootProject.ext.compileSdk
+ //compileSdk = rootProject.ext.compileSdk
targetSdk = rootProject.ext.targetSdk
versionName = rootProject.ext.versionName
versionCode = rootProject.ext.latestBaseVersionCode + rootProject.ext.versionCode
@@ -55,10 +87,6 @@ android {
}
defaultConfig {
- // Set a separate applicationId to allow variant installations
- // The applicationId is also used in some xml files (android:targetPackage)
- // The packageId (in the manifest) is never changed
- // See also applicationIdFull in common/build.gradle, must be in sync
applicationId = rootProject.ext.applicationId
vectorDrawables.useSupportLibrary = true
}
@@ -70,20 +98,19 @@ android {
buildTypes {
debug {
- // Separate the debug build, sync with common/build.gradle
applicationIdSuffix ".debug"
versionNameSuffix = "-${getGitHash}"
}
release {
debuggable = false
applicationIdSuffix = ""
-
minifyEnabled = rootProject.ext.allowNonFree
shrinkResources = rootProject.ext.allowNonFree
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard.txt'
signingConfig = signingConfigs.release
}
}
+
buildTypes.configureEach {
buildConfigField 'boolean', 'MAPBOX_ENABLED', "${rootProject.ext.mapboxEnabled}"
buildConfigField 'String', 'MAPBOX_ACCESS_TOKEN', "\"${rootProject.ext.mapboxAccessToken}\""
@@ -97,6 +124,7 @@ android {
buildConfigField 'String', 'DROPBOX_ID', "\"${rootProject.ext.dropboxId}\""
buildConfigField 'String', 'DROPBOX_SECRET', "\"${rootProject.ext.dropboxSecret}\""
}
+
lint {
baseline = file('lint-baseline.xml')
checkReleaseBuilds = true
@@ -106,23 +134,34 @@ android {
lintConfig = file('lint-osmdroid.xml')
}
showAll = true
- //textOutput = 'stdout'
textReport = true
- // Treat all warnings as errors
warningsAsErrors = true
- // Halt the build if any errors are found
abortOnError = true
}
+
bundle {
language {
- // Language can be set for audio cues, include all locales
enableSplit = false
}
}
+
buildFeatures {
aidl = true
buildConfig = true
resValues = true
+ compose = true
+ }
+
+ // 1. 启用 composeOptions(关键)
+ composeOptions {
+ kotlinCompilerExtensionVersion = rootProject.ext.kotlinCompilerExtensionVersion
+ }
+
+ // 2. 添加 packaging 配置(与参考项目对齐)
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
}
androidResources {
generateLocaleConfig = true
@@ -131,7 +170,7 @@ android {
repositories {
google()
- mavenCentral() //MapBox GraphView
+ mavenCentral()
if (rootProject.ext.mapboxEnabled) {
maven {
url = 'https://api.mapbox.com/downloads/v2/releases/maven'
@@ -139,10 +178,7 @@ repositories {
basic(BasicAuthentication)
}
credentials {
- // Do not change the username below.
- // This should always be `mapbox` (not your username).
username = 'mapbox'
- // Use the secret token you stored in gradle.properties as the password
def props = new Properties()
props.load(new FileInputStream(rootProject.file("mapbox.properties")))
password = props.mapboxDownloadToken
@@ -169,7 +205,6 @@ dependencies {
implementation "com.squareup.okhttp3:okhttp:5.4.0"
if (rootProject.ext.allowNonFree) {
- // MapBox uses telemetry, without Play there may be exceptions from mapbox (OK to ignore)
latestImplementation "com.google.android.gms:play-services-location:${rootProject.ext.googlePlayServicesVersion}"
}
if (rootProject.ext.mapboxEnabled) {
@@ -181,22 +216,30 @@ dependencies {
testImplementation "junit:junit:${rootProject.ext.junitVersion}"
testImplementation "org.mockito:mockito-core:${rootProject.ext.mockitoVersion}"
+
+ // Jetpack Compose 依赖 - 使用根目录定义的 BOM 版本
+ implementation platform("androidx.compose:compose-bom:${rootProject.ext.composeBomVersion}")
+ implementation 'androidx.compose.ui:ui'
+ implementation 'androidx.compose.ui:ui-graphics'
+ implementation 'androidx.compose.ui:ui-tooling-preview'
+ implementation 'androidx.compose.material3:material3'
+ implementation 'androidx.compose.runtime:runtime-livedata'
+
+ debugImplementation 'androidx.compose.ui:ui-tooling'
+ debugImplementation 'androidx.compose.ui:ui-test-manifest'
}
allprojects {
tasks.withType(JavaCompile).tap {
configureEach {
- // options.compilerArgs << "-Xlint:deprecation";
options.compilerArgs << "-Xlint:unchecked"
}
}
}
def props = new Properties()
-// For locally signed builds only, Google Play signs the bundle
if (rootProject.file("release.properties").exists()) {
props.load(new FileInputStream(rootProject.file("release.properties")))
-
android.signingConfigs.release.storeFile rootProject.file(props.keyStore)
android.signingConfigs.release.storePassword props.keyStorePassword
android.signingConfigs.release.keyAlias props.keyAlias
diff --git a/app/src/main/org/runnerup/compose/ComposeMainActivity.kt b/app/src/main/org/runnerup/compose/ComposeMainActivity.kt
new file mode 100644
index 000000000..84292e2c0
--- /dev/null
+++ b/app/src/main/org/runnerup/compose/ComposeMainActivity.kt
@@ -0,0 +1,28 @@
+package org.runnerup.compose
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+
+class ComposeMainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ Greeting("RunnerUp")
+ }
+ }
+}
+
+@Composable
+fun Greeting(name: String) {
+ Text(text = "Hello, $name!")
+}
+
+@Preview
+@Composable
+fun PreviewGreeting() {
+ Greeting("RunnerUp")
+}
diff --git a/build.gradle b/build.gradle
index 6d3f0cc0b..545bf50ba 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,12 +4,16 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:9.2.1'
+ //classpath 'com.android.tools.build:gradle:9.2.1'
+ classpath 'com.android.tools.build:gradle:8.0.2'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10"
}
}
plugins {
id "com.diffplug.spotless" version "8.6.0"
+ // 移除了错误的 'org.jetbrains.kotlin.kapt' 插件声明
+ //id 'org.jetbrains.kotlin.plugin.compose' version '1.8.10' // 添加这一行
}
repositories {
@@ -27,7 +31,7 @@ project.ext {
appcompat_version = "1.7.1"
annotation_version = "1.9.1"
preference_version = "1.2.1"
- googlePlayServicesVersion = '21.3.0'
+ googlePlayServicesVersion = '21.4.0'
googlePlayServicesWearableVersion = '20.0.1'
googleWearVersion = '2.9.0'
@@ -105,6 +109,12 @@ project.ext {
} else {
applicationId = "org.runnerup"
}
+
+ // 保留了 Compose 版本变量,供 app/build.gradle 引用
+ // composeBomVersion = '2024.04.01'
+ // kotlinCompilerExtensionVersion = '1.5.4'
+ composeBomVersion = '2023.03.00'
+ kotlinCompilerExtensionVersion = '1.4.3'
}
// Special setup for antPlusLib, not allowed to copy the .aar and create mavenLocal
@@ -132,4 +142,4 @@ allprojects {
google()
mavenCentral()
}
-}
\ No newline at end of file
+}