Re-implement Crashlytics
This commit is contained in:
parent
f830657668
commit
0ff5ccdbd6
14 changed files with 104 additions and 5 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,4 +12,3 @@
|
||||||
*.log
|
*.log
|
||||||
keystore.properties
|
keystore.properties
|
||||||
*.jks
|
*.jks
|
||||||
sentry.properties
|
|
||||||
|
|
3
app/acra.properties.sample
Normal file
3
app/acra.properties.sample
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
url=ACRA_URL
|
||||||
|
user=ACRA_USER
|
||||||
|
pass=ACRA_PASS
|
|
@ -3,6 +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'
|
||||||
|
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
try {
|
try {
|
||||||
|
@ -110,8 +111,9 @@ dependencies {
|
||||||
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
|
||||||
implementation 'com.commonsware.cwac:anddown:0.3.0'
|
implementation 'com.commonsware.cwac:anddown:0.3.0'
|
||||||
playImplementation 'com.android.billingclient:billing:3.0.0'
|
playImplementation 'com.android.billingclient:billing:3.0.0'
|
||||||
playImplementation 'com.google.firebase:firebase-core:17.5.0'
|
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
|
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||||
|
playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
|
||||||
implementation "androidx.core:core-ktx:1.3.1"
|
implementation "androidx.core:core-ktx:1.3.1"
|
||||||
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"
|
||||||
|
@ -132,7 +134,6 @@ android.productFlavors.each { flavor ->
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
jcenter()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.wbrawner.simplemarkdown.utility
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class errorHandlerImpl {
|
||||||
|
operator fun getValue(thisRef: Any, property: KProperty<*>): ErrorHandler {
|
||||||
|
return implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Default no-op error handler for debugging
|
||||||
|
val implementation: ErrorHandler = object : ErrorHandler {
|
||||||
|
override fun enable(enable: Boolean) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reportException(t: Throwable, message: String?) {
|
||||||
|
Log.e("ErrorHandler", "Caught non-fatal exception. Message: $message", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,7 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".view.activity.MainActivity" />
|
<activity android:name=".view.activity.MainActivity" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
@ -52,6 +53,9 @@
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/file_paths" />
|
android:resource="@xml/file_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
<meta-data
|
||||||
|
android:name="firebase_crashlytics_collection_enabled"
|
||||||
|
android:value="false" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
12
app/src/main/assets/Privacy Policy.md
Normal file
12
app/src/main/assets/Privacy Policy.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
## Privacy Policy
|
||||||
|
|
||||||
|
The 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
|
||||||
|
reports to myself whenever the app runs into an issue. These error reports are opt-out, and are
|
||||||
|
powered by [Firebase Crashlytics] (https://firebase.google.com/docs/crashlytics/), which is a
|
||||||
|
free error reporting solution provided by Google. These error reports are used exclusively for
|
||||||
|
fixing problems that occur while you're using the app, along with some analytics info like how
|
||||||
|
long you use the app for, how often, and which features of the app you use. This helps me to
|
||||||
|
determine how to spend my very limited time on building out new features. I'll have to defer to
|
||||||
|
[Google's Privacy Policy](https://policies.google.com/privacy) to explain how they handle the
|
||||||
|
data. As for me, I don't knowingly or willingly sell or share your data.
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.wbrawner.simplemarkdown.utility
|
||||||
|
|
||||||
|
interface ErrorHandler {
|
||||||
|
fun enable(enable: Boolean)
|
||||||
|
fun reportException(t: Throwable, message: String? = null)
|
||||||
|
}
|
|
@ -24,6 +24,8 @@ import androidx.navigation.ui.AppBarConfiguration
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
|
import com.wbrawner.simplemarkdown.utility.ErrorHandler
|
||||||
|
import com.wbrawner.simplemarkdown.utility.errorHandlerImpl
|
||||||
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
|
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
|
||||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_main.*
|
import kotlinx.android.synthetic.main.fragment_main.*
|
||||||
|
@ -37,6 +39,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||||
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
private val viewModel: MarkdownViewModel by viewModels()
|
private val viewModel: MarkdownViewModel by viewModels()
|
||||||
private var appBarConfiguration: AppBarConfiguration? = null
|
private var appBarConfiguration: AppBarConfiguration? = null
|
||||||
|
private val errorHandler: ErrorHandler by errorHandlerImpl()
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
|
@ -137,6 +140,17 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val enableErrorReports = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
.getBoolean(getString(R.string.pref_key_error_reports_enabled), true)
|
||||||
|
errorHandler.enable(enableErrorReports)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
launch {
|
launch {
|
||||||
|
|
|
@ -12,6 +12,8 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
|
import com.wbrawner.simplemarkdown.utility.ErrorHandler
|
||||||
|
import com.wbrawner.simplemarkdown.utility.errorHandlerImpl
|
||||||
import com.wbrawner.simplemarkdown.utility.readAssetToString
|
import com.wbrawner.simplemarkdown.utility.readAssetToString
|
||||||
import com.wbrawner.simplemarkdown.utility.toHtml
|
import com.wbrawner.simplemarkdown.utility.toHtml
|
||||||
import kotlinx.android.synthetic.main.fragment_markdown_info.*
|
import kotlinx.android.synthetic.main.fragment_markdown_info.*
|
||||||
|
@ -23,6 +25,7 @@ import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class MarkdownInfoFragment : Fragment(), CoroutineScope {
|
class MarkdownInfoFragment : Fragment(), CoroutineScope {
|
||||||
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
|
private val errorHandler: ErrorHandler by errorHandlerImpl()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -60,6 +63,7 @@ class MarkdownInfoFragment : Fragment(), CoroutineScope {
|
||||||
"UTF-8", null
|
"UTF-8", null
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
errorHandler.reportException(e)
|
||||||
Toast.makeText(view.context, R.string.file_load_error, Toast.LENGTH_SHORT).show()
|
Toast.makeText(view.context, R.string.file_load_error, Toast.LENGTH_SHORT).show()
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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="pref_key_error_reports_enabled">acra.enable</string>
|
<string name="pref_key_error_reports_enabled">crashlytics.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>
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.wbrawner.simplemarkdown.utility
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import com.wbrawner.simplemarkdown.BuildConfig
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class CrashlyticsErrorHandler : ErrorHandler {
|
||||||
|
private val crashlytics = FirebaseCrashlytics.getInstance()
|
||||||
|
|
||||||
|
override fun enable(enable: Boolean) {
|
||||||
|
crashlytics.setCrashlyticsCollectionEnabled(enable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reportException(t: Throwable, message: String?) {
|
||||||
|
@Suppress("ConstantConditionIf")
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.e("CrashlyticsErrorHandler", "Caught exception: $message", t)
|
||||||
|
}
|
||||||
|
crashlytics.recordException(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class errorHandlerImpl {
|
||||||
|
operator fun getValue(thisRef: Any, property: KProperty<*>): ErrorHandler {
|
||||||
|
return impl
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val impl = CrashlyticsErrorHandler()
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ object ReviewHelper : Application.ActivityLifecycleCallbacks {
|
||||||
private lateinit var application: Application
|
private lateinit var application: Application
|
||||||
private lateinit var reviewManager: ReviewManager
|
private lateinit var reviewManager: ReviewManager
|
||||||
private lateinit var sharedPreferences: SharedPreferences
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
|
private val errorHandler: ErrorHandler by errorHandlerImpl()
|
||||||
private var currentActivity: Activity? = null
|
private var currentActivity: Activity? = null
|
||||||
private var activityCount = 0
|
private var activityCount = 0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||||
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.3.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,4 +1,4 @@
|
||||||
#Wed Jun 10 07:53:53 MST 2020
|
#Mon Sep 21 10:36:14 MST 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
Loading…
Reference in a new issue