Add ACRA error reports

This commit is contained in:
William Brawner 2020-08-22 19:19:42 -07:00
parent 773b514e42
commit cce6a3f371
9 changed files with 117 additions and 3 deletions

1
android/.gitignore vendored
View file

@ -1 +1,2 @@
/build /build
acra.properties

View file

@ -0,0 +1,3 @@
url=ACRA_URL
user=ACRA_USER
pass=ACRA_PASS

View file

@ -3,6 +3,17 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
def acraProperties = new Properties()
try {
def acraPropertiesFile = project.file("acra.properties")
acraProperties.load(new FileInputStream(acraPropertiesFile))
} catch (FileNotFoundException ignored) {
logger.warn("Unable to load ACRA properties. Error reporting won't be available")
acraProperties['url'] = ""
acraProperties['user'] = ""
acraProperties['pass'] = ""
}
android { android {
compileSdkVersion 29 compileSdkVersion 29
compileOptions { compileOptions {
@ -25,6 +36,9 @@ android {
// buildConfigField "String", "API_URL", "\"http://192.168.86.163:8080/\"" // buildConfigField "String", "API_URL", "\"http://192.168.86.163:8080/\""
// buildConfigField "String", "API_URL", "\"http://10.0.2.2:8080/\"" // buildConfigField "String", "API_URL", "\"http://10.0.2.2:8080/\""
buildConfigField "String", "API_URL", "\"https://api.twigs.brawner.dev/\"" buildConfigField "String", "API_URL", "\"https://api.twigs.brawner.dev/\""
buildConfigField "String", "ACRA_URL", "\"${acraProperties['url']}\""
buildConfigField "String", "ACRA_USER", "\"${acraProperties['user']}\""
buildConfigField "String", "ACRA_PASS", "\"${acraProperties['pass']}\""
} }
buildTypes { buildTypes {
release { release {
@ -65,6 +79,8 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2' implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2' implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
implementation "ch.acra:acra-http:$acra_version"
implementation "ch.acra:acra-advanced-scheduler:$acra_version"
debugImplementation "com.willowtreeapps.hyperion:hyperion-core:$hyperion" debugImplementation "com.willowtreeapps.hyperion:hyperion-core:$hyperion"
debugImplementation "com.willowtreeapps.hyperion:hyperion-attr:$hyperion" debugImplementation "com.willowtreeapps.hyperion:hyperion-attr:$hyperion"

View file

@ -14,5 +14,6 @@ class AllowanceApplication : Application() {
.baseUrl(BuildConfig.API_URL) .baseUrl(BuildConfig.API_URL)
.context(this) .context(this)
.build() .build()
appComponent.errorHandler.init(this)
} }
} }

View file

@ -1,6 +1,7 @@
package com.wbrawner.budget package com.wbrawner.budget
import android.content.Context import android.content.Context
import com.wbrawner.budget.common.util.ErrorHandler
import com.wbrawner.budget.lib.network.NetworkModule import com.wbrawner.budget.lib.network.NetworkModule
import com.wbrawner.budget.storage.StorageModule import com.wbrawner.budget.storage.StorageModule
import com.wbrawner.budget.ui.SplashViewModel import com.wbrawner.budget.ui.SplashViewModel
@ -18,7 +19,7 @@ import javax.inject.Named
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@Component(modules = [StorageModule::class, NetworkModule::class]) @Component(modules = [AppModule::class, StorageModule::class, NetworkModule::class])
interface AppComponent { interface AppComponent {
fun inject(viewModel: OverviewViewModel) fun inject(viewModel: OverviewViewModel)
fun inject(viewModel: SplashViewModel) fun inject(viewModel: SplashViewModel)
@ -30,6 +31,9 @@ interface AppComponent {
fun inject(viewModel: TransactionListViewModel) fun inject(viewModel: TransactionListViewModel)
fun inject(viewModel: TransactionFormViewModel) fun inject(viewModel: TransactionFormViewModel)
@Singleton
val errorHandler: ErrorHandler
@Component.Builder @Component.Builder
interface Builder { interface Builder {
@BindsInstance @BindsInstance

View file

@ -0,0 +1,12 @@
package com.wbrawner.budget
import com.wbrawner.budget.common.util.ErrorHandler
import com.wbrawner.budget.util.AcraErrorHandler
import dagger.Module
import dagger.Provides
@Module
class AppModule {
@Provides
fun provideErrorHandler(): ErrorHandler = AcraErrorHandler()
}

View file

@ -0,0 +1,68 @@
package com.wbrawner.budget.util
import android.app.Application
import android.app.job.JobInfo
import android.util.Log
import com.wbrawner.budget.BuildConfig
import com.wbrawner.budget.common.util.ErrorHandler
import org.acra.ACRA
import org.acra.ReportField
import org.acra.config.CoreConfigurationBuilder
import org.acra.config.HttpSenderConfigurationBuilder
import org.acra.config.SchedulerConfigurationBuilder
import org.acra.data.StringFormat
import org.acra.sender.HttpSender
class AcraErrorHandler : ErrorHandler {
override fun init(application: Application) {
if (BuildConfig.ACRA_URL.isBlank()
|| BuildConfig.ACRA_USER.isBlank()
|| BuildConfig.ACRA_PASS.isBlank()) {
return
}
val builder = CoreConfigurationBuilder(application)
.setBuildConfigClass(BuildConfig::class.java)
.setReportFormat(StringFormat.JSON)
.setReportContent(
ReportField.ANDROID_VERSION,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.APPLICATION_LOG,
ReportField.AVAILABLE_MEM_SIZE,
ReportField.BRAND,
ReportField.BUILD_CONFIG,
ReportField.CRASH_CONFIGURATION,
ReportField.CUSTOM_DATA, // Not currently used, but might be useful in the future
ReportField.INITIAL_CONFIGURATION,
ReportField.PACKAGE_NAME,
ReportField.PHONE_MODEL,
ReportField.SHARED_PREFERENCES,
ReportField.STACK_TRACE,
ReportField.STACK_TRACE_HASH,
ReportField.THREAD_DETAILS,
ReportField.TOTAL_MEM_SIZE,
ReportField.USER_APP_START_DATE,
ReportField.USER_CRASH_DATE
)
builder.getPluginConfigurationBuilder(HttpSenderConfigurationBuilder::class.java)
.setUri(BuildConfig.ACRA_URL)
.setHttpMethod(HttpSender.Method.POST)
.setBasicAuthLogin(BuildConfig.ACRA_USER)
.setBasicAuthPassword(BuildConfig.ACRA_PASS)
.setEnabled(true)
builder.getPluginConfigurationBuilder(SchedulerConfigurationBuilder::class.java)
.setRequiresNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setRequiresBatteryNotLow(true)
.setEnabled(true)
ACRA.init(application, builder)
}
override fun reportException(t: Throwable, message: String?) {
@Suppress("ConstantConditionIf")
if (BuildConfig.DEBUG) {
Log.e("AcraErrorHandler", "Caught exception: $message", t)
}
ACRA.getErrorReporter().handleException(t)
}
}

View file

@ -1,11 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.72' ext.acra_version = '5.7.0'
ext.dagger = '2.23.1' ext.dagger = '2.23.1'
ext.hyperion = '0.9.27'
ext.kotlin_version = '1.3.72'
ext.moshi = '1.8.0' ext.moshi = '1.8.0'
ext.retrofit = '2.6.0' ext.retrofit = '2.6.0'
ext.hyperion = '0.9.27'
ext.room_version = "2.2.5" ext.room_version = "2.2.5"
repositories { repositories {
google() google()

View file

@ -0,0 +1,8 @@
package com.wbrawner.budget.common.util
import android.app.Application
interface ErrorHandler {
fun init(application: Application)
fun reportException(t: Throwable, message: String? = null)
}