Skip to content

Migrate to Kotlin Multiplatform (Android, JVM, iOS)#1

Merged
theshid merged 1 commit into
mainfrom
kmp-migration
May 1, 2026
Merged

Migrate to Kotlin Multiplatform (Android, JVM, iOS)#1
theshid merged 1 commit into
mainfrom
kmp-migration

Conversation

@theshid
Copy link
Copy Markdown
Owner

@theshid theshid commented May 1, 2026

Summary

Make PrettyLog callable from KMP commonMain so consumers don't have to gate logging behind their own expect/actual declarations or platform-specific source sets.

  • Android consumers keep working unchanged via the published prettylog-android variant; existing call sites compile against the same Log.{d,i,w,e,wtf,network,timed}, PrettyLog.init, and LogBreadcrumbs.{record,getEntries,clear,dumpToFile} API.
  • New: JVM + iOS targets (iosX64, iosArm64, iosSimulatorArm64) ship the same API.
  • Version bumps to 0.2.0 to flag the binary-shape change.

What changed

Source layoutsrc/mainsrc/commonMain. Platform-touching code is extracted behind seams in commonMain:

  • expect fun platformLog(...) — Logcat on Android, println on JVM, NSLog on iOS.
  • expect fun resolveCallerInfo() — JVM stack walk shared by Android + JVM via a jvmCommonMain intermediate source set; returns null on iOS where Kotlin/Native lacks a portable equivalent (the bordered output simply omits the call-site header).
  • expect helpers in Platform.kt for currentTimeMs(), currentThreadName(), and the HH:mm:ss.SSS log-timestamp format used by BreadcrumbEntry.formatted().

LogBreadcrumbs — buffer logic stays in commonMain; dumpToFile(Context) moves to androidMain as a top-level extension on the LogBreadcrumbs object so the existing call site (LogBreadcrumbs.dumpToFile(applicationContext)) compiles unchanged.

Three implementation choices worth flagging

  1. ConcurrentLinkedDequeArrayDeque in the breadcrumb buffer. ArrayDeque is the only KMP-portable deque without pulling in kotlinx-atomicfu as a dep. Trade-off: high-concurrency logging may very rarely drop a single breadcrumb. Acceptable for a debug tool; if strict thread-safety becomes a requirement, the next move is kotlinx.atomicfu.locks.synchronized around the buffer ops.
  2. kotlin.system.measureTimeMilliskotlin.time.measureTimedValue in Log.timed. The original var result: T + assign-inside-lambda pattern is rejected by Kotlin/Native; measureTimedValue is the KMP-portable equivalent (still @OptIn(ExperimentalTime::class) in 1.9, stabilized in 2.0).
  3. @kotlin.jvm.Volatile@kotlin.concurrent.Volatile on PrettyLog.service. The latter is the KMP-portable annotation introduced in Kotlin 1.9.

Test plan

  • ./gradlew :prettylog:assemble — Android AAR (debug + release), JVM JAR, all three iOS klibs compile cleanly
  • ./gradlew :prettylog:publishToMavenLocal — produces the standard KMP publication: root metadata artifact prettylog + prettylog-android, prettylog-jvm, prettylog-iosx64, prettylog-iosarm64, prettylog-iossimulatorarm64
  • Pull 0.2.0 into a downstream Android consumer and verify the existing call sites still link without changes
  • Pull the iOS variant into a Compose Multiplatform sample to sanity-check NSLog output and the stack-trace-attached error path

🤖 Generated with Claude Code

Make the library callable from KMP commonMain so consumers don't have
to gate logging behind expect/actual or platform-specific source sets.

Source layout: src/main → src/commonMain. Platform-touching code is
extracted behind two seams in commonMain:
- expect fun platformLog(...) — Logcat on Android, println on JVM, NSLog
  on iOS.
- expect fun resolveCallerInfo() — JVM stack walk shared by Android +
  JVM via a jvmCommonMain intermediate source set; null on iOS where
  Kotlin/Native lacks a portable equivalent.
- expect helpers for currentTimeMs / currentThreadName / log-timestamp
  formatting (Platform.kt) — keeps PrettyLoggingService and
  LogBreadcrumbs.formatted() portable.

LogBreadcrumbs.dumpToFile(Context) moves to androidMain as a top-level
extension on the LogBreadcrumbs object. The buffer itself is portable
(ArrayDeque instead of ConcurrentLinkedDeque — accepts that concurrent
logging may very rarely drop a single breadcrumb in exchange for
KMP-portability without an atomicfu dep).

API surface preserved for Android consumers: Log.{d,i,w,e,wtf,network,
timed}, PrettyLog.init, LogBreadcrumbs.{record,getEntries,clear,
dumpToFile} all unchanged. Version bumps to 0.2.0.

Build: AGP 8.7.3 / Kotlin 1.9.25 / Gradle 8.9, no version changes.
Maven publication produces the standard KMP shape (root metadata
artifact + per-target variants prettylog-android / prettylog-jvm /
prettylog-iosX64 / prettylog-iosArm64 / prettylog-iosSimulatorArm64).
JitPack supports KMP publishing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@theshid theshid merged commit 17ef7e6 into main May 1, 2026
@theshid theshid deleted the kmp-migration branch May 1, 2026 12:14
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.

2 participants