Replace Crashlytics with Sentry

Signed-off-by: William Brawner <me@wbrawner.com>
This commit is contained in:
William Brawner 2020-06-10 10:16:53 -07:00
parent 0e70364c6e
commit 1cc0063b15
11 changed files with 59 additions and 31 deletions

1
.gitignore vendored
View file

@ -12,3 +12,4 @@
*.log *.log
keystore.properties keystore.properties
*.jks *.jks
sentry.properties

View file

@ -3,7 +3,7 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: 'jacoco' apply plugin: 'jacoco'
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'io.sentry.android.gradle'
def keystoreProperties = new Properties() def keystoreProperties = new Properties()
try { try {
@ -44,6 +44,9 @@ android {
versionCode 26 versionCode 26
versionName "0.8.4" versionName "0.8.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [
sentryDsn: "https://399270639b2e4b10a028a2be9192d1d3@sentry.brawner.dev/2"
]
buildConfigField "boolean", "ENABLE_CUSTOM_CSS", "false" buildConfigField "boolean", "ENABLE_CUSTOM_CSS", "false"
} }
signingConfigs { signingConfigs {
@ -99,11 +102,10 @@ dependencies {
implementation 'com.commonsware.cwac:anddown:0.3.0' implementation 'com.commonsware.cwac:anddown:0.3.0'
implementation 'com.android.billingclient:billing:2.2.0' implementation 'com.android.billingclient:billing:2.2.0'
implementation 'com.google.firebase:firebase-core:17.3.0' implementation 'com.google.firebase:firebase-core:17.3.0'
implementation 'com.google.firebase:firebase-crashlytics:17.0.0-beta04'
implementation 'com.google.firebase:firebase-analytics:17.3.0'
implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.core:core-ktx:1.2.0"
implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.browser:browser:1.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'io.sentry:sentry-android:2.1.6'
def coroutines_version = "1.3.0-RC2" def coroutines_version = "1.3.0-RC2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
@ -117,6 +119,7 @@ dependencies {
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
repositories { repositories {
mavenCentral() mavenCentral()
jcenter()
} }
jacoco { jacoco {

View file

@ -67,7 +67,10 @@
<activity android:name=".view.activity.SupportActivity" /> <activity android:name=".view.activity.SupportActivity" />
<meta-data <meta-data
android:name="firebase_crashlytics_collection_enabled" android:name="io.sentry.dsn"
android:value="${sentryDsn}" />
<meta-data
android:name="io.sentry.auto-init"
android:value="false" /> android:value="false" />
</application> </application>

View file

@ -1,13 +1,12 @@
## Privacy Policy ## Privacy Policy
First and foremost, Simple Markdown DOES NOT collect any personally identifiable information. The First and foremost, Simple Markdown DOES NOT collect any personally identifiable information. The
internet access permission is requested primarily for retrieving images from the internet in internet access permission is requested primarily for retrieving images from the internet in
case you embed them in your markdown, but it also allows me to send automated error and crash case you embed them in your markdown, but it also allows me to send automated error and crash
reports to myself whenever the app runs into an issue. These error reports are opt-out, and are reports to myself whenever the app runs into an issue. These automated reports are powered by my own
powered by [Firebase Crashlytics] (https://firebase.google.com/docs/crashlytics/), which is a self-hosted version of [Sentry] (https://sentry.io/), which is a free and open source error
free error reporting solution provided by Google. These error reports are used exclusively for reporting solution. These error reports are used exclusively for fixing problems that occur while
fixing problems that occur while you're using the app, along with some analytics info like how you're using the app. For more information on the kinds of data that may be sent in these automated
long you use the app for, how often, and which features of the app you use. This helps me to error reports, please see the [relevant documentation](https://docs.sentry.io/platforms/android/#context)
determine how to spend my very limited time on building out new features. I'll have to defer to on Sentry's website. If you would like to opt-out of these error reports, please visit the in-app
[Google's Privacy Policy](https://policies.google.com/privacy) to explain how they handle the settings page to disable the toggle for error reports.
data. As for me, I don't knowingly or willingly sell or trade your data.

View file

@ -2,15 +2,19 @@ package com.wbrawner.simplemarkdown
import android.app.Application import android.app.Application
import android.os.StrictMode import android.os.StrictMode
import com.wbrawner.simplemarkdown.utility.CrashlyticsErrorHandler import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.utility.ErrorHandler import com.wbrawner.simplemarkdown.utility.ErrorHandler
import com.wbrawner.simplemarkdown.utility.SentryErrorHandler
class MarkdownApplication : Application() { class MarkdownApplication : Application() {
val errorHandler: ErrorHandler by lazy { val errorHandler: ErrorHandler by lazy {
CrashlyticsErrorHandler() SentryErrorHandler()
} }
override fun onCreate() { override fun onCreate() {
val enableErrorReports = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(getString(R.string.error_reports_enabled), true)
errorHandler.init(this, enableErrorReports)
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll() .detectAll()

View file

@ -1,27 +1,44 @@
package com.wbrawner.simplemarkdown.utility package com.wbrawner.simplemarkdown.utility
import android.content.Context
import android.util.Log import android.util.Log
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.wbrawner.simplemarkdown.BuildConfig import com.wbrawner.simplemarkdown.BuildConfig
import io.sentry.android.core.SentryAndroid
import io.sentry.core.Sentry
import java.util.concurrent.atomic.AtomicBoolean
interface ErrorHandler { interface ErrorHandler {
fun init(context: Context, enable: Boolean)
fun enable(enable: Boolean) fun enable(enable: Boolean)
fun reportException(t: Throwable, message: String? = null) fun reportException(t: Throwable, message: String? = null)
} }
class CrashlyticsErrorHandler : ErrorHandler { class SentryErrorHandler : ErrorHandler {
private val crashlytics = FirebaseCrashlytics.getInstance() private lateinit var enabled: AtomicBoolean
override fun init(context: Context, enable: Boolean) {
enabled = AtomicBoolean(enable)
SentryAndroid.init(context) { options ->
options.setBeforeSend { event, _ ->
if (enabled.get()) {
event
} else {
null
}
}
}
}
override fun enable(enable: Boolean) { override fun enable(enable: Boolean) {
crashlytics.setCrashlyticsCollectionEnabled(enable) enabled.set(enable)
} }
override fun reportException(t: Throwable, message: String?) { override fun reportException(t: Throwable, message: String?) {
@Suppress("ConstantConditionIf") @Suppress("ConstantConditionIf")
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Log.e("CrashlyticsErrorHandler", "Caught exception: $message", t) Log.e("SentryErrorHandler", "Caught exception: $message", t)
return return
} }
crashlytics.recordException(t) Sentry.captureException(t)
} }
} }

View file

@ -3,7 +3,6 @@ package com.wbrawner.simplemarkdown.view.activity
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
class SettingsActivity : AppCompatActivity() { class SettingsActivity : AppCompatActivity() {
@ -12,9 +11,7 @@ class SettingsActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings) setContentView(R.layout.activity_settings)
setSupportActionBar(findViewById(R.id.toolbar)) setSupportActionBar(findViewById(R.id.toolbar))
if (supportActionBar != null) { supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
}
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {

View file

@ -34,7 +34,7 @@
<string name="action_lock_swipe">Lock Swiping</string> <string name="action_lock_swipe">Lock Swiping</string>
<string name="action_select">Select</string> <string name="action_select">Select</string>
<string name="action_privacy">Privacy</string> <string name="action_privacy">Privacy</string>
<string name="error_reports_enabled">crashlytics.enable</string> <string name="error_reports_enabled">errors.enable</string>
<string name="pref_title_error_reports">Enable automated error reports</string> <string name="pref_title_error_reports">Enable automated error reports</string>
<string name="pref_error_reports_off">Error reports will not be sent</string> <string name="pref_error_reports_off">Error reports will not be sent</string>
<string name="pref_error_reports_on">Error reports will be sent</string> <string name="pref_error_reports_on">Error reports will be sent</string>

View file

@ -7,9 +7,9 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.google.gms:google-services:4.3.3' classpath 'com.google.gms:google-services:4.3.3'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0-beta04' classpath 'io.sentry:sentry-android-gradle-plugin:1.7.34'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View file

@ -1,6 +1,6 @@
#Thu Mar 19 08:56:07 CST 2020 #Wed Jun 10 07:53:53 MST 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

4
sentry.properties.sample Normal file
View file

@ -0,0 +1,4 @@
defaults.url=https://sentry.brawner.dev/
defaults.project=simplemarkdown
defaults.org=wbrawner
auth.token=