From bce6eee5d862083e47456132b9f23f9abcf100b5 Mon Sep 17 00:00:00 2001
From: skydoves
Date: Wed, 16 Sep 2026 22:34:12 +0900
Subject: [PATCH 1/3] Make Snitcher a Kotlin Multiplatform library for Android,
desktop and iOS
The screens, the theme, the texts, the captured model and the storage live in
commonMain and are drawn with Compose Multiplatform, while each platform
installs the crash capture that its runtime allows.
- Android keeps today's behaviour: the default uncaught exception handler
persists the crash, launches the trace activity and kills the process
- Desktop installs the JVM uncaught exception handler, delegates to the handler
that was there before it, and opens SnitcherTraceWindow while the process
keeps running
- iOS installs the Kotlin unhandled exception hook and, unless asked not to, the
NSException handler. The runtime always terminates the process at the
Objective-C boundary, so the crash is persisted and presented on the next
launch through snitcherViewController
- DataStore is replaced with a synchronous okio store, because a suspending
write does not flush while the process is being torn down
- The android string resources become a SnitcherStrings configuration, since
resources are not shared across platforms
- ExceptionTraceScreen and AppRestoreScreen take the actions as callbacks and
hide the buttons a platform cannot support, and Android keeps the launcher
based overloads
- The Kotlin ABI validation replaces the binary compatibility validator, which
lets the AGP 9 opt-out flags go, and it now covers android, desktop and the
klib
- Adds a desktop sample, a SwiftUI sample built with xcodegen, tests for the
store, the capture and the iOS hook, and rewrites the README and the docs
---
.github/workflows/android.yml | 22 +-
.gitignore | 5 +
README.md | 300 +++++++---------
art/android_trace.png | Bin 0 -> 187435 bytes
art/desktop_restore.png | Bin 0 -> 52069 bytes
art/desktop_trace.png | Bin 0 -> 123827 bytes
art/desktop_trace_dark.png | Bin 0 -> 118078 bytes
art/ios_trace.png | Bin 0 -> 177311 bytes
benchmark/build.gradle.kts | 1 -
build.gradle.kts | 11 +-
demo-desktop/build.gradle.kts | 54 +++
.../com/skydoves/snitcherdemo/desktop/Main.kt | 88 +++++
.../snitcherdemo/desktop/Screenshots.kt | 121 +++++++
demo-ios/Info.plist | 32 ++
.../SnitcherDemo.xcodeproj/project.pbxproj | 327 ++++++++++++++++++
demo-ios/Sources/ContentView.swift | 54 +++
demo-ios/Sources/iOSApp.swift | 18 +
demo-ios/project.yml | 42 +++
demo/build.gradle.kts | 1 -
.../skydoves/snitcherdemo/SnitcherDemoApp.kt | 1 +
docs/android.md | 43 +++
docs/custom-build-type.md | 19 +-
docs/custom-launcher-activity.md | 12 +-
docs/custom-theme.md | 31 +-
docs/custom-trace-screen.md | 78 ++++-
docs/desktop.md | 45 +++
docs/index.md | 69 ++--
docs/ios.md | 105 ++++++
docs/trace-global-exception.md | 39 ++-
docs/trace-strategy.md | 4 +-
gradle.properties | 7 -
gradle/libs.versions.toml | 19 +-
mkdocs.yml | 3 +
settings.gradle.kts | 1 +
snitcher/api/android/snitcher.api | 281 +++++++++++++++
snitcher/api/{ => desktop}/snitcher.api | 99 ++++--
snitcher/api/snitcher.klib.api | 307 ++++++++++++++++
snitcher/build.gradle.kts | 139 ++++----
.../{main => androidMain}/AndroidManifest.xml | 3 +-
.../baselineProfiles/baseline-prof.txt | 0
.../com/skydoves/snitcher/Snitcher.android.kt | 144 ++++++++
.../snitcher/extensions/ContextExtensions.kt | 24 +-
.../internal/SnitcherExceptionHandler.kt | 135 ++++++++
.../snitcher/ui/ExceptionTraceActivity.kt | 5 +-
.../snitcher/ui/SnitcherScreens.android.kt | 64 ++++
.../ui/theme/SnitcherSystemBars.android.kt} | 6 +-
.../kotlin/com/skydoves/snitcher/Snitcher.kt | 127 +++++++
.../com/skydoves/snitcher/SnitcherStrings.kt | 54 +++
.../com/skydoves/snitcher/TraceStrategy.kt | 0
.../skydoves/snitcher/internal/Platform.kt | 44 +++
.../snitcher/model/SnitcherException.kt | 24 +-
.../snitcher/model/SnitcherPreference.kt | 6 +-
.../model/SnitcherStackTraceElement.kt | 14 +-
.../snitcher/storage/SnitcherStore.kt | 56 +++
.../skydoves/snitcher/ui/AppRestoreScreen.kt | 57 ++-
.../snitcher/ui/ExceptionTraceScreen.kt | 194 +++++++++++
.../com/skydoves/snitcher/ui/SnitcherIcons.kt | 68 ++++
.../snitcher/ui/SnitcherPrimaryButton.kt | 0
.../snitcher/ui/theme/SnitcherColor.kt | 1 -
.../snitcher/ui/theme/SnitcherShapes.kt | 12 +-
.../snitcher/ui/theme/SnitcherSystemBars.kt} | 19 +-
.../snitcher/ui/theme/SnitcherTheme.kt | 0
.../snitcher/ui/theme/SnitcherThemeConfig.kt | 19 +-
.../snitcher/ui/theme/SnitcherTypography.kt | 0
.../internal/ThrowableExtensionsTest.kt | 43 +++
.../snitcher/storage/SnitcherStoreTest.kt | 70 ++++
.../com/skydoves/snitcher/Snitcher.desktop.kt | 81 +++++
.../snitcher/ui/SnitcherTraceWindow.kt | 60 ++++
.../ui/theme/SnitcherSystemBars.desktop.kt | 23 ++
.../com/skydoves/snitcher/Snitcher.ios.kt | 185 ++++++++++
.../snitcher/internal/Platform.ios.kt | 43 +++
.../snitcher/ui/SnitcherViewController.kt | 55 +++
.../ui/theme/SnitcherSystemBars.ios.kt | 26 ++
.../com/skydoves/snitcher/SnitcherIosTest.kt | 81 +++++
.../snitcher/internal/Platform.jvm.kt | 37 ++
.../snitcher/model/SnitcherExceptions.kt | 29 ++
.../kotlin/com/skydoves/snitcher/Snitcher.kt | 307 ----------------
.../snitcher/datastore/SnitcherSerializer.kt | 44 ---
.../snitcher/installer/SnitcherInstaller.kt | 60 ----
.../snitcher/ui/ExceptionTraceScreen.kt | 184 ----------
snitcher/src/main/res/values/strings.xml | 25 --
81 files changed, 3715 insertions(+), 1092 deletions(-)
create mode 100644 art/android_trace.png
create mode 100644 art/desktop_restore.png
create mode 100644 art/desktop_trace.png
create mode 100644 art/desktop_trace_dark.png
create mode 100644 art/ios_trace.png
create mode 100644 demo-desktop/build.gradle.kts
create mode 100644 demo-desktop/src/main/kotlin/com/skydoves/snitcherdemo/desktop/Main.kt
create mode 100644 demo-desktop/src/main/kotlin/com/skydoves/snitcherdemo/desktop/Screenshots.kt
create mode 100644 demo-ios/Info.plist
create mode 100644 demo-ios/SnitcherDemo.xcodeproj/project.pbxproj
create mode 100644 demo-ios/Sources/ContentView.swift
create mode 100644 demo-ios/Sources/iOSApp.swift
create mode 100644 demo-ios/project.yml
create mode 100644 docs/android.md
create mode 100644 docs/desktop.md
create mode 100644 docs/ios.md
create mode 100644 snitcher/api/android/snitcher.api
rename snitcher/api/{ => desktop}/snitcher.api (76%)
create mode 100644 snitcher/api/snitcher.klib.api
rename snitcher/src/{main => androidMain}/AndroidManifest.xml (95%)
rename snitcher/src/{main/generated => androidMain}/baselineProfiles/baseline-prof.txt (100%)
create mode 100644 snitcher/src/androidMain/kotlin/com/skydoves/snitcher/Snitcher.android.kt
rename snitcher/src/{main => androidMain}/kotlin/com/skydoves/snitcher/extensions/ContextExtensions.kt (76%)
create mode 100644 snitcher/src/androidMain/kotlin/com/skydoves/snitcher/internal/SnitcherExceptionHandler.kt
rename snitcher/src/{main => androidMain}/kotlin/com/skydoves/snitcher/ui/ExceptionTraceActivity.kt (93%)
create mode 100644 snitcher/src/androidMain/kotlin/com/skydoves/snitcher/ui/SnitcherScreens.android.kt
rename snitcher/src/{main/kotlin/com/skydoves/snitcher/ui/theme/Statusbar.kt => androidMain/kotlin/com/skydoves/snitcher/ui/theme/SnitcherSystemBars.android.kt} (91%)
create mode 100644 snitcher/src/commonMain/kotlin/com/skydoves/snitcher/Snitcher.kt
create mode 100644 snitcher/src/commonMain/kotlin/com/skydoves/snitcher/SnitcherStrings.kt
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/TraceStrategy.kt (100%)
create mode 100644 snitcher/src/commonMain/kotlin/com/skydoves/snitcher/internal/Platform.kt
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/model/SnitcherException.kt (60%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/model/SnitcherPreference.kt (89%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/model/SnitcherStackTraceElement.kt (68%)
create mode 100644 snitcher/src/commonMain/kotlin/com/skydoves/snitcher/storage/SnitcherStore.kt
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/AppRestoreScreen.kt (56%)
create mode 100644 snitcher/src/commonMain/kotlin/com/skydoves/snitcher/ui/ExceptionTraceScreen.kt
create mode 100644 snitcher/src/commonMain/kotlin/com/skydoves/snitcher/ui/SnitcherIcons.kt
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/SnitcherPrimaryButton.kt (100%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/theme/SnitcherColor.kt (99%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/theme/SnitcherShapes.kt (78%)
rename snitcher/src/{main/kotlin/com/skydoves/snitcher/datastore/SnitcherDataStore.kt => commonMain/kotlin/com/skydoves/snitcher/ui/theme/SnitcherSystemBars.kt} (61%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/theme/SnitcherTheme.kt (100%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/theme/SnitcherThemeConfig.kt (74%)
rename snitcher/src/{main => commonMain}/kotlin/com/skydoves/snitcher/ui/theme/SnitcherTypography.kt (100%)
create mode 100644 snitcher/src/commonTest/kotlin/com/skydoves/snitcher/internal/ThrowableExtensionsTest.kt
create mode 100644 snitcher/src/commonTest/kotlin/com/skydoves/snitcher/storage/SnitcherStoreTest.kt
create mode 100644 snitcher/src/desktopMain/kotlin/com/skydoves/snitcher/Snitcher.desktop.kt
create mode 100644 snitcher/src/desktopMain/kotlin/com/skydoves/snitcher/ui/SnitcherTraceWindow.kt
create mode 100644 snitcher/src/desktopMain/kotlin/com/skydoves/snitcher/ui/theme/SnitcherSystemBars.desktop.kt
create mode 100644 snitcher/src/iosMain/kotlin/com/skydoves/snitcher/Snitcher.ios.kt
create mode 100644 snitcher/src/iosMain/kotlin/com/skydoves/snitcher/internal/Platform.ios.kt
create mode 100644 snitcher/src/iosMain/kotlin/com/skydoves/snitcher/ui/SnitcherViewController.kt
create mode 100644 snitcher/src/iosMain/kotlin/com/skydoves/snitcher/ui/theme/SnitcherSystemBars.ios.kt
create mode 100644 snitcher/src/iosTest/kotlin/com/skydoves/snitcher/SnitcherIosTest.kt
create mode 100644 snitcher/src/jvmSharedMain/kotlin/com/skydoves/snitcher/internal/Platform.jvm.kt
create mode 100644 snitcher/src/jvmSharedMain/kotlin/com/skydoves/snitcher/model/SnitcherExceptions.kt
delete mode 100644 snitcher/src/main/kotlin/com/skydoves/snitcher/Snitcher.kt
delete mode 100644 snitcher/src/main/kotlin/com/skydoves/snitcher/datastore/SnitcherSerializer.kt
delete mode 100644 snitcher/src/main/kotlin/com/skydoves/snitcher/installer/SnitcherInstaller.kt
delete mode 100644 snitcher/src/main/kotlin/com/skydoves/snitcher/ui/ExceptionTraceScreen.kt
delete mode 100644 snitcher/src/main/res/values/strings.xml
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index d21d8e3..400dfe8 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -24,7 +24,7 @@ jobs:
api_check:
name: API check
- runs-on: ubuntu-latest
+ runs-on: macos-latest
steps:
- name: Check out code
uses: actions/checkout@v7
@@ -35,10 +35,11 @@ jobs:
java-version: 17
- uses: gradle/actions/setup-gradle@v6
- name: API check
- run: ./gradlew apiCheck
+ run: ./gradlew checkKotlinAbi
build:
- runs-on: ubuntu-latest
+ # the apple targets can only be compiled on a mac.
+ runs-on: macos-latest
steps:
- uses: actions/checkout@v7
- name: set up JDK
@@ -55,3 +56,18 @@ jobs:
run: |
./gradlew --scan --stacktrace \
assemble -x :benchmark:pixel6api31Setup -x :benchmark:pixel6api31NonMinifiedReleaseAndroidTest -x :benchmark:collectNonMinifiedReleaseBaselineProfile
+
+ test:
+ name: Test
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v7
+ - name: set up JDK
+ uses: actions/setup-java@v6
+ with:
+ distribution: zulu
+ java-version: 17
+
+ - uses: gradle/actions/setup-gradle@v6
+ - name: Desktop and iOS tests
+ run: ./gradlew :snitcher:desktopTest :snitcher:iosSimulatorArm64Test
diff --git a/.gitignore b/.gitignore
index 885180f..75b6dcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,3 +58,8 @@ google-services.json
freeline.py
freeline/
freeline_project_description.json
+
+# Xcode
+xcuserdata/
+*.xcworkspace/
+DerivedData/
diff --git a/README.md b/README.md
index 30f71db..91b8d05 100644
--- a/README.md
+++ b/README.md
@@ -9,18 +9,24 @@
-π¦ Snitcher captures global crashes, enabling easy redirection to the exception tracing screen for swift recovery.
+π¦ Snitcher captures global crashes on Android, desktop, and iOS, and redirects to the exception tracing screen for swift recovery.
-
-
+
+
+
+
+
+
## What is Snitcher?
Snitcher offers versatile advantages such as aiding in debugging crashes during development, facilitating easy sharing of exceptions by your QA team, enhancing user experiences with recovery screens instead of abrupt closures, and enabling global exception tracing and customized launch behaviors tailored to your specific needs. You have the complete freedom to customize the crash tracing screens according to your build types and preferences, reporting to the Firebase's Crashlytics with displaying the exception screen, including options like launching a designated Activity, sending messages to your BroadcastReceiver, or any other desired actions.
+The screens, the theme, and the captured model are shared across every platform with Compose Multiplatform, and each platform installs the crash capture that its runtime allows.
+
## Documentation
For comprehensive details about Snitcher, please refer to the **[complete documentation available here](https://skydoves.github.io/snitcher/)**.
@@ -31,17 +37,44 @@ For comprehensive details about Snitcher, please refer to the **[complete docume
### Gradle
-Add the dependency below to your **module**'s `build.gradle` file:
+Add the dependency below to your **module**'s `build.gradle.kts` file:
-```gradle
+```kotlin
dependencies {
- implementation "com.github.skydoves:snitcher:1.0.3"
+ implementation("com.github.skydoves:snitcher:$version")
}
```
+In a multiplatform module, add it to the source set that needs it:
+
+```kotlin
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ implementation("com.github.skydoves:snitcher:$version")
+ }
+ }
+}
+```
+
+## What each platform can capture
+
+| | Android | Desktop (JVM) | iOS |
+| --- | --- | --- | --- |
+| Uncaught JVM exceptions | yes | yes | not applicable |
+| Unhandled Kotlin exceptions | yes | yes | yes |
+| Uncaught `NSException` | not applicable | not applicable | yes |
+| Unix signals, such as a Swift trap or a memory error | no | no | no |
+| When the screen is shown | right after the crash, in a trace activity | right after the crash, in a window | on the next launch |
+| Can restart the app | yes | no, the process keeps running | no, iOS does not let an app relaunch itself |
+
+On iOS an unhandled Kotlin exception that reaches the Objective-C boundary always terminates the process, so the crash is persisted and displayed on the next launch. An exception that is only unhandled inside a coroutine does not terminate the process, and is published right away.
+
## Usage
-Installing Snitcher is a breeze; it hooks into global exceptions, replacing application closure with informative exception tracing screens. You can seamlessly install Snitcher using the following example:
+### Android
+
+Install Snitcher in your `Application` class. Snitcher becomes the default uncaught exception handler, persists the crash, and launches the exception tracing activity.
```kotlin
class App : Application() {
@@ -54,91 +87,92 @@ class App : Application() {
}
```
-It's recommended to install Snitcher on your **Application** class or your on initialization solution, such as [App Startup](https://developer.android.com/topic/libraries/app-startup).
-
-### Tracing Global Exceptions
+### Desktop
-You can trace the global exceptions by providing `exceptionHandler` lambda parameter. This can be highly beneficial if you intend to gather and report exceptions to other platforms, such as [Firebase Crashlyrics](https://firebase.google.com/docs/crashlytics).
+Install Snitcher before your `application { }` block, and place `SnitcherTraceWindow` next to your own window. The JVM keeps running after an uncaught exception, so the crash window opens right away.
```kotlin
-Snitcher.install(
- application = this,
- exceptionHandler = { exception: SnitcherException ->
- Firebase.crashlytics.log(exception.stackTrace) // or exception.message,
+fun main() {
+ Snitcher.install()
+
+ application {
+ Window(onCloseRequest = ::exitApplication) {
+ App()
+ }
+
+ SnitcherTraceWindow()
}
-)
+}
```
-The `exceptionHandler` gives you `SnitcherException`, encompassing the exception message, stack traces, package name, and thread information. Additionally, it enables you to recover the original `Throwable` instance with the `SnitcherException.throwable` extension.
+### iOS
-```kotlin
-Snitcher.install(
- application = this,
- exceptionHandler = { exception: SnitcherException ->
- val message: String = exception.message
- val stackTrace: String = exception.stackTrace
- val throwable: Throwable = exception.throwable
- val threadName: String = exception.threadName
+Install Snitcher when your app starts. The runtime terminates the process after a crash, so present the screen on the launch that follows it.
- // do somethings
- }
-)
-```
+```swift
+import Snitcher
-### Custom Exception Trace Screen
+@main
+struct SampleApp: App {
-Snitcher provides ready-to-use exception tracing screens (such as `ExceptionTraceActivity`, built with the `ExceptionTraceScreen` Composable), giving you the flexibility to extensively tailor these screens according to your preferences, and even design your own distinct tracing interfaces.
+ init() {
+ Snitcher.shared.install()
+ }
-```kotlin
-Snitcher.install(
- application = this,
- traceActivity = ExceptionTraceActivity::class
-)
+ var body: some Scene {
+ WindowGroup { ContentView() }
+ }
+}
```
-If you don't specify the `traceActivity` parameter, the default value will be `ExceptionTraceActivity`. You can tailor the launched activity by modifying the `traceActivity` parameter to match your preferred choice. The example below demonstrates the construction of a customized trace Activity:
+```swift
+struct ContentView: View {
-```kotlin
-class MyExceptionTraceActivity : ComponentActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContent {
- val exception by Snitcher.exception.collectAsState()
- val launcher by Snitcher.launcher.collectAsState()
-
- SnitcherTheme {
- if (exception != null) {
- if (BuildConfig.DEBUG) {
- // implement your own exception trace screen
- ExceptionTraceScreen(
- launcher = launcher,
- snitcherException = exception!!,
- )
- } else {
- // implement your own app restore screen
- AppRestoreScreen(launcher = launcher)
- }
+ @State private var showsCrash = Snitcher.shared.exception.value != nil
+
+ var body: some View {
+ MyContent()
+ .fullScreenCover(isPresented: $showsCrash) {
+ SnitcherScreen {
+ Snitcher.shared.clear()
+ showsCrash = false
}
+ .ignoresSafeArea()
}
- }
}
}
+
+struct SnitcherScreen: UIViewControllerRepresentable {
+ let onRestore: () -> Void
+
+ func makeUIViewController(context: Context) -> UIViewController {
+ SnitcherViewControllerKt.snitcherViewController(onRestore: onRestore)
+ }
+
+ func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
+}
```
-As demonstrated in the example above, Snitcher provides access to the `SnitcherException` and the package name of the launcher Activity. This information can be utilized to construct highly customized trace screens that align with your specific needs. Snitcher conveniently provides this information through [StateFlow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/)s, allowing you to observe these values without the need for cumbersome intent handling when initiating the trace Activity.
+The [demo-ios](demo-ios) module is a complete sample, and [demo-desktop](demo-desktop) and [demo](demo) cover the other two platforms.
+
+### Tracing global exceptions
+
+Every installer takes an `exceptionHandler`, which is useful to report a crash to another platform, such as [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics).
```kotlin
-val exception: SnitcherException? by Snitcher.exception.collectAsState()
-val launcher: String by Snitcher.launcher.collectAsState()
+Snitcher.install(
+ application = this,
+ exceptionHandler = { exception: SnitcherException ->
+ Firebase.crashlytics.log(exception.stackTrace)
+ },
+)
```
-> **Note**: Following any app crashes, you can readily observe the exception details across various components at any time and from any location.
+`SnitcherException` carries the exception name, the message, the whole stack trace, and the thread information. On Android and on the desktop you can restore the original throwable with `SnitcherException.toThrowable()`.
-### Custom Launcher (Restore) Activity
+### Launcher (restore) Activity
-Furthermore, you can customize the launcher (restore activity), specifying which Activity should be executed upon restoration within the trace activity. If you don't specify a `launcher` activity, the most recent Activity that encountered a crash will automatically be launched when users press the 'restore' button. However, if you wish to launch a particular Activity instead of the most recent one, you can accomplish this by providing the launcher parameter:
+On Android you can decide which Activity is launched when the user restores the app. Without it, the most recent Activity before the crash is used.
```kotlin
Snitcher.install(
@@ -149,7 +183,7 @@ Snitcher.install(
### Custom Snitcher Theme
-The pre-built screens are styled by a `SnitcherThemeConfig`. Give one to `Snitcher.install`, and the built-in `ExceptionTraceActivity`, as well as every screen you wrap in `SnitcherTheme`, will be drawn with it:
+The pre-built screens are styled by a `SnitcherThemeConfig`. Give one to the installer, and the pre-built screens, as well as every screen you wrap in `SnitcherTheme`, will be drawn with it:
```kotlin
Snitcher.install(
@@ -165,138 +199,44 @@ Snitcher.install(
)
```
-`lightColors` and `darkColors` are picked by the system dark mode. Every field has a default, so you only need to declare what you want to change.
-
-**SnitcherColor**
-
-| Property | Where it is used |
-|---|---|
-| `primary` | The title, the section labels, and the button background |
-| `onPrimary` | The content that is drawn on the buttons |
-| `background` | The screen background, which is also drawn behind the system bars |
-| `textHighEmphasis` | The exception message, the stack trace, and the restore screen texts |
-| `textLowEmphasis` | The package and device information |
-| `outline` | The border of the stack trace container |
-
-**SnitcherTypography**
-
-`title`, `message`, `deviceInfo`, `sectionLabel`, `stacktrace`, and `button` are plain `TextStyle`s, so fonts, sizes, and weights are all yours.
-
-**SnitcherShapes**
-
-`button` and `stacktrace` are plain `Shape`s.
-
-You can also swap the theme at any time, which restyles the screens right away:
-
-```kotlin
-Snitcher.theme = Snitcher.theme.copy(darkColors = SnitcherColor.defaultDarkColors())
-```
-
-If you build your own trace screens, wrap them in `SnitcherTheme`. Its defaults come from the installed configuration, so your screens and the pre-built ones stay in sync, and you can still override any of them for a single screen:
+Colors left unspecified follow the color they belong to, so `copy(primary = Color.Red)` restyles the title, the labels, the buttons, and the stack trace border together.
-```kotlin
-SnitcherTheme(
- colors = SnitcherTheme.colors.copy(primary = Color.Blue),
-) {
- if (exception != null) {
- ExceptionTraceScreen(
- launcher = launcher,
- snitcherException = exception!!,
- )
- }
-}
-```
+### Custom texts
-If you wish to personalize the text strings within the pre-built UIs, you can override the following string values within your `strings.xml` file:
-
-```xml
-Oops, Restore the previous screen?
-The app crashed unexpectedly. We apologize for the inconvenience. Would you like to return to where you left off?
-Restore
-Restore App
-Debug on IDE
-Stacktrace
-```
-
-### Custom Build Types
-
-If you intend to launch distinct trace activities and implement different behaviors or flavors, you can install Snitcher based on specific build types, as shown in the example below:
+The texts of the pre-built screens are plain strings, so they travel across platforms and you can translate them:
```kotlin
Snitcher.install(
application = this,
- traceActivity = if (BuildConfig.DEBUG) {
- MyExceptionTraceActivity::class
- } else {
- RestoreActivity::class
- },
- exceptionHandler = {
- if (!BuildConfig.DEBUG) {
- Firebase.crashlytics.log(exception.stackTrace)
- }
- }
+ strings = SnitcherStrings(
+ traceRestoreButton = "λ€μ μμ",
+ traceStacktrace = "μ€ννΈλ μ΄μ€",
+ ),
)
```
-Alternatively, you can create a single trace Activity and manage the different build types within the activity itself, as demonstrated in the example below:
+### Custom trace screens
+
+`ExceptionTraceScreen` and `AppRestoreScreen` are plain composables, so you can build your own screen around the state that Snitcher publishes:
```kotlin
-Snitcher.install(
- application = this,
- launcher = MyExceptionTraceActivity::class,
-)
+val exception by Snitcher.exception.collectAsState()
-class MyExceptionTraceActivity : ComponentActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContent {
- val exception by Snitcher.exception.collectAsState()
- val launcher by Snitcher.launcher.collectAsState()
-
- SnitcherTheme {
- if (exception != null) {
- if (Snitcher.isDebuggable) {
- ExceptionTraceScreen(
- launcher = launcher,
- snitcherException = exception!!,
- )
- } else {
- AppRestoreScreen(launcher = launcher)
- }
- }
- }
- }
+SnitcherTheme {
+ exception?.let {
+ ExceptionTraceScreen(
+ snitcherException = it,
+ onRestore = { /* restore your app */ },
+ )
}
}
```
-As demonstrated in the above example, you have the flexibility to create your own trace or restore Activities and install them according to your various build types.
-
-### Trace Strategy
-
-You can globally trace exceptions by providing the `exceptionHandler` lambda parameter during Snitcher installation. However, there might be instances where you don't wish to launch the trace Activity but rather perform other actions, such as reporting crashes or sending messages to a `BroadcastReceiver`. In such cases, you can modify the trace strategy as shown in the example below:
-
-```kotlin
-Snitcher.install(
- application = this,
- traceStrategy = TraceStrategy.REPLACE,
- exceptionHandler = {
- // do something
- },
-)
-```
-
-In this scenario, only the `exceptionHandler` lambda function will be executed without triggering the launch of any trace Activity. If the `traceStrategy` parameter is not specified, the default behavior is set to `TraceStrategy.CO_WORK`, which involves executing the `exceptionHandler` lambda and initiating the trace activity when an app crash occurs.
-
## Find this repository useful? :heart:
-
-Support it by joining __[stargazers](https://github.com/skydoves/cloudy/stargazers)__ for this repository. :star:
+Support it by joining __[stargazers](https://github.com/skydoves/snitcher/stargazers)__ for this repository. :star:
Also, __[follow me](https://github.com/skydoves)__ on GitHub for my next creations! π€©
# License
-
```xml
Designed and developed by 2023 skydoves (Jaewoong Eum)
@@ -304,7 +244,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/art/android_trace.png b/art/android_trace.png
new file mode 100644
index 0000000000000000000000000000000000000000..26255c0454e6f8f80e676ac9488896e1e41b9ac0
GIT binary patch
literal 187435
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