Skip to content

Make Snitcher a Kotlin Multiplatform library for Android, desktop and iOS - #18

Merged
skydoves merged 4 commits into
mainfrom
feature/kmp
Sep 17, 2026
Merged

skydoves merged 4 commits into
mainfrom
feature/kmp

Conversation

@skydoves

Copy link
Copy Markdown
Owner

The screens, the theme, the texts, the captured model and the storage move to commonMain and are drawn with Compose Multiplatform, while each platform installs the crash capture its runtime allows. Android keeps today's behaviour, desktop opens a crash window while the process keeps running, and iOS records the crash and presents it on the next launch, since the runtime always terminates the process.
DataStore gives way to a synchronous okio store because a suspending write does not flush while a process is being torn down, android string resources become a SnitcherStrings config, and the Kotlin ABI validation replaces the binary compatibility validator, which also lets the AGP 9 opt-out flags go.
Verified on an API 37 emulator, on the desktop, and on an iOS 26.5 simulator with a SwiftUI sample, plus simulator tests for the Kotlin hook and the persistence. Screenshots are in the README.

… 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
Crash handling:
- Android records the crash even without a foreground activity, kills the
  process from a finally, and catches Throwable while delegating
- Restoring the app clears the stored crash, which otherwise came back on
  every launch
- The desktop handler prints the trace when the JVM had no default handler,
  which installing one would otherwise silence
- The iOS hook terminates through terminateWithUnhandledException when no
  other hook was installed, so the runtime still writes its crash report
- A nil callStackSymbols no longer crashes inside the iOS handler
- Throwing the recorded exception again for a debugger no longer overwrites it

Storage:
- The crash is written to a temporary file and moved into place, so a kill in
  the middle of a write cannot leave a truncated file, and write reports
  whether it reached the disk
- A file that cannot be decoded is removed instead of failing every launch

API:
- Compose, coroutines and the activity dependency are api scoped, since they
  carry types of the public API
- TraceStrategy and the launcher flow move to the Android source set
- Adds Snitcher.latestException for Swift, SnitcherColor.fromArgb for platforms
  that cannot build a Color, and moves debug() to the shared JVM source set
- The unspecified color sentinel is resolved when a theme is installed
- The screens fall back to the installed theme instead of throwing
- The desktop installer takes isDebuggable, like the other two

Build and docs:
- Releases are published from a macOS runner, CI builds and checks in one
  macOS job with the Kotlin/Native toolchain cached, and android host tests run
- The javadoc jars carry real Dokka output, the baseline profile is generated
  again, and the version becomes 2.0.0 for a breaking release
- Corrects the iOS semantics, the theme samples and the install snippets, and
  documents the framework setup and the migration from 1.0.x
# Conflicts:
#	.github/workflows/publish.yml
#	buildSrc/src/main/kotlin/com/skydoves/snitcher/Configuration.kt
The workflow is no longer Android only, so it becomes ci.yml and builds each
target in one macOS job, which is the only host that can build the apple ones.
The Kotlin/Native toolchain is cached, the steps are split per platform so a
failure names the target, and the iOS sample is generated with xcodegen and
built against the simulator so the Swift sources cannot rot.
@skydoves
skydoves merged commit ac31216 into main Sep 17, 2026
3 checks passed
@skydoves
skydoves deleted the feature/kmp branch September 17, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant