diff --git a/.github/workflows/sign.yml b/.github/workflows/sign.yml index 44cc6f5..cd0b8eb 100644 --- a/.github/workflows/sign.yml +++ b/.github/workflows/sign.yml @@ -32,6 +32,9 @@ jobs: MEALIENT_KEY_PASSWORD: ${{ secrets.MEALIENT_KEY_PASSWORD }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} APPSWEEP_API_KEY: ${{ secrets.APPSWEEP_API_KEY }} + ACRA_HOST: ${{ secrets.ACRA_HOST }} + ACRA_LOGIN: ${{ secrets.ACRA_LOGIN }} + ACRA_PASSWORD: ${{ secrets.ACRA_PASSWORD }} run: | echo "$MEALIENT_KEY_STORE" | base64 -d > app/keystore.jks echo "storeFile=keystore.jks" > keystore.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts index eac7796..03db79c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,6 +22,19 @@ android { testInstrumentationRunner = "gq.kirmanak.mealient.MealientTestRunner" testInstrumentationRunnerArguments += mapOf("clearPackageData" to "true") resourceConfigurations += listOf("en", "es", "ru", "fr", "nl", "pt", "de") + + buildConfigField( + "String", + "ACRA_HOST", + System.getenv("ACRA_HOST")?.let { "\"$it\"" } ?: "\"\"") + buildConfigField( + "String", + "ACRA_LOGIN", + System.getenv("ACRA_LOGIN")?.let { "\"$it\"" } ?: "\"\"") + buildConfigField( + "String", + "ACRA_PASSWORD", + System.getenv("ACRA_PASSWORD")?.let { "\"$it\"" } ?: "\"\"") } signingConfigs { @@ -139,6 +152,9 @@ dependencies { implementation(libs.coil) implementation(libs.coil.compose) + implementation(libs.acra.http) + implementation(libs.acra.scheduler) + testImplementation(libs.junit) implementation(libs.jetbrains.kotlinx.coroutinesAndroid) diff --git a/app/src/main/java/gq/kirmanak/mealient/App.kt b/app/src/main/java/gq/kirmanak/mealient/App.kt index 1368d87..028fee3 100644 --- a/app/src/main/java/gq/kirmanak/mealient/App.kt +++ b/app/src/main/java/gq/kirmanak/mealient/App.kt @@ -1,12 +1,14 @@ package gq.kirmanak.mealient import android.app.Application +import android.content.Context import coil.Coil import coil.ImageLoader import com.google.android.material.color.DynamicColors import dagger.hilt.android.HiltAndroidApp import gq.kirmanak.mealient.architecture.configuration.BuildConfiguration import gq.kirmanak.mealient.data.migration.MigrationDetector +import gq.kirmanak.mealient.extensions.setupCrashReporting import gq.kirmanak.mealient.logging.Logger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -31,6 +33,11 @@ class App : Application() { private val appCoroutineScope = CoroutineScope(Dispatchers.Main + Job()) + override fun attachBaseContext(base: Context?) { + super.attachBaseContext(base) + setupCrashReporting() + } + override fun onCreate() { super.onCreate() logger.v { "onCreate() called" } diff --git a/app/src/main/java/gq/kirmanak/mealient/extensions/ContextExtensions.kt b/app/src/main/java/gq/kirmanak/mealient/extensions/ContextExtensions.kt index 5c3c909..dd2074d 100644 --- a/app/src/main/java/gq/kirmanak/mealient/extensions/ContextExtensions.kt +++ b/app/src/main/java/gq/kirmanak/mealient/extensions/ContextExtensions.kt @@ -1,8 +1,16 @@ package gq.kirmanak.mealient.extensions import android.app.Activity +import android.app.Application +import android.app.job.JobInfo import android.content.Context import android.content.ContextWrapper +import gq.kirmanak.mealient.BuildConfig +import org.acra.config.httpSender +import org.acra.config.scheduler +import org.acra.data.StringFormat +import org.acra.ktx.initAcra +import org.acra.sender.HttpSender fun Context.findActivity(): Activity? { var context = this @@ -12,3 +20,27 @@ fun Context.findActivity(): Activity? { } return null } + +internal fun Application.setupCrashReporting() { + val acraHost = BuildConfig.ACRA_HOST.takeUnless { it.isBlank() } ?: return + val acraLogin = BuildConfig.ACRA_LOGIN.takeUnless { it.isBlank() } ?: return + val acraPassword = BuildConfig.ACRA_PASSWORD.takeUnless { it.isBlank() } ?: return + initAcra { + reportFormat = StringFormat.JSON + alsoReportToAndroidFramework = true + + httpSender { + uri = "$acraHost/report" + basicAuthLogin = acraLogin + basicAuthPassword = acraPassword + httpMethod = HttpSender.Method.POST + // TODO compressed reports are failing due to https://github.com/F43nd1r/Acrarium/issues/458 + compress = false + } + + scheduler { + requiresNetworkType = JobInfo.NETWORK_TYPE_UNMETERED + requiresBatteryNotLow = true + } + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8eede0b..e94501a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -93,6 +93,8 @@ hiltNavigationCompose = "1.0.0" ktor = "2.3.5" # https://github.com/coil-kt/coil/releases coil = "2.5.0" +# https://github.com/ACRA/acra/releases +acra = "5.11.3" [libraries] android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } @@ -207,6 +209,9 @@ ktor-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", versi coil = { group = "io.coil-kt", name = "coil", version.ref = "coil" } coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } +acra-http = { group = "ch.acra", name = "acra-http", version.ref = "acra" } +acra-scheduler = { group = "ch.acra", name = "acra-advanced-scheduler", version.ref = "acra" } + [plugins] sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" } appsweep = { id = "com.guardsquare.appsweep", version.ref = "appsweep" }