Skip to content

v3.3.0

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 08 Aug 16:19
· 129 commits to main since this release
9639eb5

Removed

  • BREAKING — Koin is no longer a dependency. koin-core shipped at runtime scope in all
    five published artifacts, so consumers who never used Koin still carried it on the classpath
    and in the iOS klib link (#66).
    kmpWorkerModule() and kmpWorkerCoreModule() are removed; call KmpWorkManager.initialize()
    instead. The migration is roughly four lines in one file — see
    docs/MIGRATION_V3.3.0.md. Koin and Hilt users keep working by
    binding KmpWorkManager.getInstance() from their own module; the library deliberately does
    not ship a bridge artifact.
  • koin-android dropped from the Android artifact (#67).
    No production code imported it — it was only surviving because it transitively supplied
    androidx.core (NotificationCompat), which is now declared directly.

Added

  • iOS: KmpWorkManager.initialize() — a DI-agnostic entry point mirroring Android's,
    keeping the eager fail-fast checks (IosWorkerFactory type, Info.plist
    BGTaskSchedulerPermittedIdentifiers) at the same point in startup
    (#68).
  • KmpWorkManagerInstance.workerFactory on Android, for hosts that run workers outside
    WorkManager (a custom exact-alarm BroadcastReceiver, for example) and need to resolve a
    worker by class name themselves.
  • Registry hardening suites — V330RegistryHardeningTest (iOS) and
    V330AndroidRegistryHardeningTest (Robolectric) — covering concurrent init election,
    concurrent readers against by lazy, init/shutdown leak loops, startup-path init cost,
    cached-resolution cost, hostile worker class names, and fail-fast before state is published.

Fixed

  • iOS: execution history and task events were silently dropped. EventStore and
    ExecutionHistoryStore were lazy single { } bindings whose global-registration side
    effects only ran if something resolved them — and nothing in the library or the sample ever
    did. Unless a host app resolved them itself, KmpWorkManagerRuntime.executionHistoryStore
    stayed null, workers dropped every record through ?.save(record), and
    getExecutionHistory() returned an empty list. Android was already correct via
    createdAtStart = true. Both stores are now created eagerly on both platforms.
  • shutdown() left stale global registrations. TaskEventManager.initialize() is
    compare-and-set "first call wins", and neither platform's shutdown() released the claim, so
    shutdown() → initialize() left the global event store pointing at the dead registry's
    instance while the live registry held a different one. shutdown() now releases both the
    event store and the execution history store.
  • iOS: nested-timeout misattribution could theoretically survive under CPU starvation.
    ChainExecutor.executeChain/executeStep disambiguated an inner (chain/task) timeout from
    an outer one via elapsedNow() < timeout inside catch (TimeoutCancellationException).
    Correct under normal load, but a scheduling stall between the outer cancellation and the
    elapsed-time read could push elapsed past the inner budget and misattribute an outer
    cancellation as a genuine chain/task timeout. Both call sites now wrap their inner block in
    withTimeoutOrNull instead of withTimeout — kotlinx.coroutines identity-checks the
    exception internally, so there is no elapsed-time read on this path at all, and no window
    for the race. See V330TimeoutIdentityDisambiguationTest.
  • Android: OverflowFileRegistry could leak files in multi-process apps. The
    SharedPreferences-backed registry caches in memory per Context, so a host with separate
    processes (:background, :push, …) could race a register() in one process against a
    consumeAndDelete() in another and leak the overflow file until the 24 h janitor sweep. Now
    backed by one file per entry under cacheDir/overflow_registry/, with no per-process cache to
    race. Task ids are caller-supplied, so filenames are derived via an injective, traversal-safe
    percent-encoding rather than a hash. Migrates any legacy SharedPreferences entries
    automatically on first use.

Changed

  • KmpWorkManagerKoin → KmpWorkManagerAndroid, backed by AndroidServiceRegistry; the iOS
    equivalent is IosServiceRegistry. Both are plain internal registries of by lazy
    singletons — the Koin module never used a container feature (no scopes, no qualifiers, no
    parametersOf, no lazy graph).
  • Documentation swept for the removed API: README, quickstart, platform-setup, api-reference,
    examples, troubleshooting, the KSP README, and the @Worker / BgTaskIdProvider KDoc.

Install

implementation("dev.brewkits:kmpworkmanager:3.3.0")          // core engine (no Ktor)
implementation("dev.brewkits:kmpworkmanager-http:3.3.0")     // optional — Ktor 3 HTTP workers

Docs