Complete API documentation for KMP WorkManager.
- v2.4.0 APIs
- BackgroundTaskScheduler
- WorkerResult (v2.3.0+)
- Task Triggers
- Constraints
- TaskChain
- Events
- Enums
- Platform-Specific APIs
New types and scheduler methods added in v2.4.0.
Controls how urgently the scheduler tries to run a task when multiple tasks compete for the available background execution budget.
enum class TaskPriority(internal val weight: Int) {
/** Deferred work that can wait for idle/charging conditions. */
LOW(weight = 0),
/** Default priority for most background tasks. */
NORMAL(weight = 1),
/**
* Important work that should run before NORMAL tasks.
* Android: mapped to expedited work (skips Doze).
*/
HIGH(weight = 2),
/**
* Mission-critical work (payments, security tokens, compliance uploads).
* Android: mapped to expedited work.
* iOS: placed at head of execution queue, executed in the very first available BGTask window.
* Use sparingly — overuse degrades the app's background execution budget.
*/
CRITICAL(weight = 3)
}Android mapping:
CRITICAL/HIGH→setExpedited()(bypasses Doze)NORMAL→ standard OneTime / Periodic workLOW→ standard work, deferred when battery/network is constrained
iOS mapping: The in-memory queue is sorted by priority before each BGTask execution window. Higher-priority chains are dequeued first.
Usage:
scheduler.beginWith(
TaskRequest(
workerClassName = "PaymentSyncWorker",
priority = TaskPriority.CRITICAL
)
).enqueue()Hook interface for observing task lifecycle events. Implement this to route KMP WorkManager events to your telemetry backend (Sentry, Firebase Crashlytics, Datadog, etc.).
All methods have default no-op implementations — override only what you need. Callbacks are invoked from background coroutine dispatchers and must not suspend or block.
interface TelemetryHook {
fun onTaskStarted(event: TelemetryHook.TaskStartedEvent) {}
fun onTaskCompleted(event: TelemetryHook.TaskCompletedEvent) {}
fun onTaskFailed(event: TelemetryHook.TaskFailedEvent) {}
fun onChainCompleted(event: TelemetryHook.ChainCompletedEvent) {}
fun onChainFailed(event: TelemetryHook.ChainFailedEvent) {}
fun onChainSkipped(event: TelemetryHook.ChainSkippedEvent) {}
}Event types:
| Event class | Key fields |
|---|---|
TaskStartedEvent |
taskName, chainId?, stepIndex?, platform, startedAtMs |
TaskCompletedEvent |
taskName, chainId?, stepIndex?, platform, success, durationMs, errorMessage? |
TaskFailedEvent |
taskName, chainId?, stepIndex?, platform, error, durationMs, retryCount |
ChainCompletedEvent |
chainId, totalSteps, platform, durationMs |
ChainFailedEvent |
chainId, failedStep, platform, error, retryCount, willRetry |
ChainSkippedEvent |
chainId, platform, reason |
Registration:
val config = KmpWorkManagerConfig(
telemetryHook = object : TelemetryHook {
override fun onTaskFailed(event: TelemetryHook.TaskFailedEvent) {
Sentry.captureMessage("Task failed: ${event.taskName} — ${event.error}")
}
override fun onChainFailed(event: TelemetryHook.ChainFailedEvent) {
FirebaseCrashlytics.getInstance().recordException(
RuntimeException("Chain ${event.chainId} failed at step ${event.failedStep}")
)
}
}
)A single persisted record of a background task chain execution. Records are written when a chain finishes (success, failure, abandoned, skipped, or timeout).
@Serializable
data class ExecutionRecord(
val id: String,
val chainId: String,
val status: ExecutionStatus,
val startedAtMs: Long,
val endedAtMs: Long,
val durationMs: Long,
val totalSteps: Int,
val completedSteps: Int,
val failedStep: Int? = null,
val errorMessage: String? = null,
val retryCount: Int = 0,
val platform: String,
val workerClassNames: List<String> = emptyList()
)
enum class ExecutionStatus {
SUCCESS, FAILURE, ABANDONED, SKIPPED, TIMEOUT
}ExecutionStatus values:
SUCCESS— all steps completed successfully.FAILURE— a step failed; chain is re-queued for retry.ABANDONED— max retries exhausted or non-idempotent tasks after corrupt-progress self-heal.SKIPPED— chain discarded before execution (REPLACE policy or deadline exceeded).TIMEOUT— chain timed out within its BGTask window; re-queued for continuation.
Persistent store for ExecutionRecords. Records are appended after each chain execution and automatically pruned when the store exceeds 500 entries.
interface ExecutionHistoryStore {
suspend fun save(record: ExecutionRecord)
suspend fun getRecords(limit: Int = 100): List<ExecutionRecord>
suspend fun clear()
companion object {
const val MAX_RECORDS = 500
}
}Platform implementations: iOS uses a JSONL file in Application Support; Android uses a JSONL file in filesDir.
Interface for debugging scheduler state and system health. Useful for debug screens, production monitoring dashboards, and customer support diagnostics.
interface WorkerDiagnostics {
suspend fun getSchedulerStatus(): SchedulerStatus
suspend fun getSystemHealth(): SystemHealthReport
suspend fun getTaskStatus(id: String): TaskStatusDetail?
}
data class SchedulerStatus(
val isReady: Boolean,
val totalPendingTasks: Int,
val queueSize: Int,
val platform: String,
val timestamp: Long
)
data class SystemHealthReport(
val timestamp: Long,
val batteryLevel: Int,
val isCharging: Boolean,
val networkAvailable: Boolean,
val storageAvailable: Long,
val isStorageLow: Boolean,
val isLowPowerMode: Boolean, // iOS only; always false on Android
val deviceInDozeMode: Boolean // Android only; always false on iOS
)
data class TaskStatusDetail(
val taskId: String,
val workerClassName: String,
val state: String, // "PENDING", "RUNNING", "COMPLETED", "FAILED"
val retryCount: Int,
val lastExecutionTime: Long?,
val lastError: String?
)Usage:
val diagnostics = WorkerDiagnostics.getInstance()
val health = diagnostics.getSystemHealth()
if (health.isLowPowerMode) {
println("BGTasks may be throttled — device in low power mode")
}
if (health.isStorageLow) {
println("Storage critical — tasks may fail")
}Two new methods on BackgroundTaskScheduler (v2.3.8+):
/** Returns the most recent task chain execution records, newest first. */
suspend fun getExecutionHistory(limit: Int = 100): List<ExecutionRecord>
/** Deletes all stored execution history records. */
suspend fun clearExecutionHistory()Typical usage:
// On app foreground: collect and upload, then clear
val records = scheduler.getExecutionHistory(limit = 200)
analyticsService.uploadBatchAsync(records)
scheduler.clearExecutionHistory()The main interface for scheduling and managing background tasks.
Schedule a single background task.
suspend fun enqueue(
id: String,
trigger: TaskTrigger,
workerClassName: String,
constraints: Constraints = Constraints(),
inputJson: String? = null,
policy: ExistingPolicy = ExistingPolicy.REPLACE
): ScheduleResultParameters:
id: String- Unique identifier for the task. If a task with the same ID exists, behavior depends onpolicy.trigger: TaskTrigger- When and how the task should be executed (OneTime, Periodic, Exact, etc.)workerClassName: String- Name of the worker class that will execute the taskconstraints: Constraints- Execution constraints (network, battery, charging, etc.)inputJson: String?- Optional JSON input data passed to the workerpolicy: ExistingPolicy- How to handle an existing task with the same ID (default: REPLACE)
Returns: ScheduleResult - Result of the scheduling operation
Example:
val result = scheduler.enqueue(
id = "data-sync",
trigger = TaskTrigger.Periodic(intervalMs = 15_MINUTES),
workerClassName = "SyncWorker",
constraints = Constraints(requiresNetwork = true)
)Start building a task chain with a single task or multiple parallel tasks.
fun beginWith(request: TaskRequest): TaskChain
fun beginWith(requests: List<TaskRequest>): TaskChainParameters:
request: TaskRequest- Single task to start the chainrequests: List<TaskRequest>- Multiple tasks to run in parallel at the start
Returns: TaskChain - Builder for constructing task chains
Example:
// Sequential chain
scheduler.beginWith(TaskRequest(workerClassName = "DownloadWorker"))
.then(TaskRequest(workerClassName = "ProcessWorker"))
.enqueue()
// Parallel start
scheduler.beginWith(listOf(
TaskRequest(workerClassName = "SyncWorker"),
TaskRequest(workerClassName = "CacheWorker")
))
.then(TaskRequest(workerClassName = "FinalizeWorker"))
.enqueue()Cancel a specific task by its ID.
suspend fun cancel(id: String)Parameters:
id: String- ID of the task to cancel
Example:
scheduler.cancel("data-sync")Cancel all scheduled tasks.
suspend fun cancelAll()Example:
scheduler.cancelAll()New in v2.3.0: Workers can now return structured results instead of just boolean.
sealed class WorkerResult {
data class Success(
val message: String? = null,
val data: Map<String, Any?>? = null
) : WorkerResult()
data class Failure(
val message: String
) : WorkerResult()
}Common Worker:
interface CommonWorker {
suspend fun doWork(input: String?): WorkerResult
}Backward Compatibility:
Workers returning Boolean are automatically converted to WorkerResult:
true→WorkerResult.Success()false→WorkerResult.Failure("Task failed")
class SyncWorker : CommonWorker {
override suspend fun doWork(input: String?): WorkerResult {
return try {
syncData()
WorkerResult.Success(message = "Sync completed")
} catch (e: Exception) {
WorkerResult.Failure("Sync failed: ${e.message}")
}
}
}class DownloadWorker : CommonWorker {
override suspend fun doWork(input: String?): WorkerResult {
val config = Json.decodeFromString<DownloadConfig>(input!!)
val file = downloadFile(config.url, config.savePath)
return WorkerResult.Success(
message = "Downloaded ${file.length()} bytes in 5s",
data = buildJsonObject {
put("filePath", config.savePath)
put("fileSize", file.length())
put("url", config.url)
put("duration", 5000L)
}
)
}
}// In your application code
when (val result = worker.doWork(input)) {
is WorkerResult.Success -> {
println("Success: ${result.message}")
val fileSize = result.data?.get("fileSize")?.jsonPrimitive?.longOrNull
println("File size: $fileSize bytes")
}
is WorkerResult.Failure -> {
println("Failed: ${result.message}")
}
}// Worker 1: Download file and return metadata
class DownloadWorker : CommonWorker {
override suspend fun doWork(input: String?): WorkerResult {
val file = download(url)
return WorkerResult.Success(
data = buildJsonObject {
put("filePath", file.path)
put("size", file.size)
}
)
}
}
// Worker 2: Process downloaded file
class ProcessWorker : CommonWorker {
override suspend fun doWork(input: String?): WorkerResult {
// In v2.3.0: Access previous worker data via event bus or custom implementation
// In v2.4.0: Automatic data passing will be supported
return WorkerResult.Success(message = "Processed file")
}
}
// Chain them together
scheduler.beginWith(TaskRequest("DownloadWorker"))
.then(TaskRequest("ProcessWorker"))
.withId("download-process-chain", policy = ExistingPolicy.KEEP)
.enqueue()✅ Structured Data Return: Return any data from workers ✅ Better Error Messages: Detailed failure messages ✅ Type Safety: Explicit success/failure handling ✅ Backward Compatible: Boolean returns still work ✅ Built-in Workers: All 5 built-in workers return meaningful data
Task triggers define when and how tasks should be executed.
Execute a task once after an optional delay.
data class OneTime(
val initialDelayMs: Long = 0
) : TaskTriggerParameters:
initialDelayMs: Long- Delay before execution in milliseconds (default: 0)
Supported Platforms: Android, iOS
Example:
TaskTrigger.OneTime(initialDelayMs = 5_000) // Execute after 5 secondsExecute a task repeatedly at fixed intervals.
data class Periodic(
val intervalMs: Long,
val flexMs: Long? = null
) : TaskTriggerParameters:
intervalMs: Long- Interval between executions in milliseconds (minimum: 15 minutes)flexMs: Long?- Flex time window for Android WorkManager (optional)
Supported Platforms: Android, iOS
Important Notes:
- Android: Minimum interval is 15 minutes (enforced by WorkManager)
- iOS: Task automatically re-schedules after completion
- iOS: Actual execution time determined by BGTaskScheduler (opportunistic)
Example:
TaskTrigger.Periodic(
intervalMs = 30 * 60 * 1000, // 30 minutes
flexMs = 5 * 60 * 1000 // 5 minutes flex
)Execute a task at a precise time.
data class Exact(
val atEpochMillis: Long
) : TaskTriggerParameters:
atEpochMillis: Long- Exact timestamp in epoch milliseconds
Supported Platforms: Android, iOS
Implementation:
- Android: Uses
AlarmManager.setExactAndAllowWhileIdle() - iOS: Uses
UNUserNotificationCenterlocal notifications
Example:
val targetTime = Clock.System.now()
.plus(1.hours)
.toEpochMilliseconds()
TaskTrigger.Exact(atEpochMillis = targetTime)Execute a task within a time window.
data class Windowed(
val startEpochMillis: Long,
val endEpochMillis: Long
) : TaskTriggerParameters:
startEpochMillis: Long- Window start time in epoch millisecondsendEpochMillis: Long- Window end time in epoch milliseconds
Supported Platforms: Android only (iOS returns REJECTED_OS_POLICY)
Example:
val now = Clock.System.now().toEpochMilliseconds()
TaskTrigger.Windowed(
startEpochMillis = now + 60_000, // Start in 1 minute
endEpochMillis = now + 5 * 60_000 // End in 5 minutes
)Trigger a task when content provider changes are detected.
data class ContentUri(
val uriString: String,
val triggerForDescendants: Boolean = true
) : TaskTriggerParameters:
uriString: String- Content URI to observe (e.g., "content://media/external/images/media")triggerForDescendants: Boolean- Whether to trigger for descendant URIs (default: true)
Supported Platforms: Android only (iOS returns REJECTED_OS_POLICY)
Example:
TaskTrigger.ContentUri(
uriString = "content://media/external/images/media",
triggerForDescendants = true
)Trigger tasks based on device state changes.
data object BatteryLow : TaskTrigger
data object BatteryOkay : TaskTrigger
data object StorageLow : TaskTrigger
data object DeviceIdle : TaskTriggerSupported Platforms:
BatteryLow,BatteryOkay: Android, iOSStorageLow,DeviceIdle: Android only
Example:
// Run heavy processing when battery is good
scheduler.enqueue(
id = "ml-training",
trigger = TaskTrigger.BatteryOkay,
workerClassName = "MLTrainingWorker",
constraints = Constraints(requiresCharging = true)
)Constraints define the conditions under which a task can run.
data class Constraints(
// Network
val requiresNetwork: Boolean = false,
val networkType: NetworkType = NetworkType.CONNECTED,
val requiresUnmeteredNetwork: Boolean = false,
// Battery
val requiresCharging: Boolean = false,
val requiresBatteryNotLow: Boolean = false,
// Storage
val requiresStorageNotLow: Boolean = false,
// Device State
val requiresDeviceIdle: Boolean = false,
val allowWhileIdle: Boolean = false,
// Task Properties
val isHeavyTask: Boolean = false,
val expedited: Boolean = false,
// Retry Policy
val backoffPolicy: BackoffPolicy = BackoffPolicy.EXPONENTIAL,
val backoffDelayMs: Long = 10_000,
// Existing Work Policy
val existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.KEEP,
// iOS Quality of Service
val qos: QualityOfService = QualityOfService.DEFAULT
)requiresNetwork: Boolean = falseWhether the task requires network connectivity.
Platforms: Android, iOS
networkType: NetworkType = NetworkType.CONNECTEDType of network required. Options:
NetworkType.NOT_REQUIRED- No network neededNetworkType.CONNECTED- Any network connectionNetworkType.UNMETERED- WiFi or unlimited data (Android only)NetworkType.NOT_ROAMING- Non-roaming network (Android only)NetworkType.METERED- Cellular data allowed (Android only)NetworkType.TEMPORARILY_UNMETERED- Temporarily free network (Android only)
Platforms: Android (full support), iOS (only CONNECTED/NOT_REQUIRED)
requiresUnmeteredNetwork: Boolean = falseShortcut for requiring WiFi (same as networkType = NetworkType.UNMETERED).
Platforms: Android only
requiresCharging: Boolean = falseWhether the device must be charging.
Platforms: Android, iOS
requiresBatteryNotLow: Boolean = falseWhether the battery level must be above the low threshold.
Platforms: Android, iOS
requiresStorageNotLow: Boolean = falseWhether the device must have sufficient storage available.
Platforms: Android only
requiresDeviceIdle: Boolean = falseWhether the device must be idle (screen off, not recently used).
Platforms: Android only
allowWhileIdle: Boolean = falseWhether the task can run while the device is in Doze mode.
Platforms: Android only
isHeavyTask: Boolean = falseWhether this is a long-running task (>10 minutes).
- Android: Uses
KmpHeavyWorkerwith foreground service - iOS: Uses
BGProcessingTaskinstead ofBGAppRefreshTask
Platforms: Android, iOS
expedited: Boolean = falseWhether the task should be expedited (run as soon as possible).
Platforms: Android only (uses expedited WorkManager jobs)
backoffPolicy: BackoffPolicy = BackoffPolicy.EXPONENTIALRetry strategy when a task fails. Options:
BackoffPolicy.EXPONENTIAL- Exponential backoff (10s, 20s, 40s, 80s, ...)BackoffPolicy.LINEAR- Linear backoff (10s, 20s, 30s, 40s, ...)
Platforms: Android, iOS
backoffDelayMs: Long = 10_000Initial backoff delay in milliseconds (default: 10 seconds).
Platforms: Android, iOS
existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.KEEPWhat to do when a task with the same ID already exists. Options:
ExistingWorkPolicy.REPLACE- Cancel existing and schedule new taskExistingWorkPolicy.KEEP- Keep existing task, ignore new requestExistingWorkPolicy.APPEND- Queue new task after existing oneExistingWorkPolicy.APPEND_OR_REPLACE- Append if existing is running, replace otherwise
Platforms: Android (full support), iOS (only REPLACE/KEEP)
qos: QualityOfService = QualityOfService.DEFAULTiOS priority hint for task execution. Options:
QualityOfService.HIGH- User-initiated priorityQualityOfService.DEFAULT- Default priorityQualityOfService.LOW- Background priority
Platforms: iOS only
Builder for creating sequential and parallel task workflows.
Add the next step to the chain.
fun then(request: TaskRequest): TaskChain
fun then(requests: List<TaskRequest>): TaskChainParameters:
request: TaskRequest- Single task to execute nextrequests: List<TaskRequest>- Multiple tasks to run in parallel
Returns: TaskChain - The chain builder for further chaining
Set a unique ID for the chain and specify the ExistingPolicy.
fun withId(
id: String,
policy: ExistingPolicy = ExistingPolicy.REPLACE
): TaskChainParameters:
id: String- Unique identifier for the chainpolicy: ExistingPolicy- How to handle if a chain with this ID already existsExistingPolicy.KEEP- Skip if chain already runningExistingPolicy.REPLACE- Cancel old chain and start new one
Returns: TaskChain - New chain instance with the specified ID and policy
Example:
// Prevent duplicate chain execution
scheduler.beginWith(TaskRequest("DownloadWorker"))
.then(TaskRequest("ProcessWorker"))
.withId("download-process-workflow", policy = ExistingPolicy.KEEP)
.enqueue()
// Click button multiple times - only runs once
button.onClick {
scheduler.beginWith(TaskRequest("SyncWorker"))
.withId("sync-chain", policy = ExistingPolicy.KEEP)
.enqueue()
}Execute the constructed task chain.
fun enqueue()Note: No return value in v2.3.0. The chain is enqueued asynchronously.
Data class representing a task in a chain.
data class TaskRequest(
val id: String = UUID.randomUUID().toString(),
val workerClassName: String,
val input: String? = null,
val constraints: Constraints = Constraints()
)Parameters:
id: String- Unique task identifier (auto-generated if not provided)workerClassName: String- Name of the worker classinput: String?- Optional input dataconstraints: Constraints- Execution constraints
// Sequential execution
scheduler
.beginWith(TaskRequest(workerClassName = "DownloadWorker"))
.then(TaskRequest(workerClassName = "ProcessWorker"))
.then(TaskRequest(workerClassName = "UploadWorker"))
.enqueue()
// Parallel execution
scheduler
.beginWith(listOf(
TaskRequest(workerClassName = "SyncWorker"),
TaskRequest(workerClassName = "CacheWorker"),
TaskRequest(workerClassName = "CleanupWorker")
))
.then(TaskRequest(workerClassName = "FinalizeWorker"))
.enqueue()
// Mixed sequential and parallel
scheduler
.beginWith(TaskRequest(workerClassName = "DownloadWorker"))
.then(listOf(
TaskRequest(workerClassName = "ProcessImageWorker"),
TaskRequest(workerClassName = "ProcessVideoWorker")
))
.then(TaskRequest(workerClassName = "UploadWorker"))
.enqueue()Event system for worker-to-UI communication.
Singleton object for emitting and collecting task completion events.
object TaskEventBus {
val events: SharedFlow<TaskCompletionEvent>
suspend fun emit(event: TaskCompletionEvent)
}Event emitted when a task completes.
data class TaskCompletionEvent(
val taskName: String,
val success: Boolean,
val message: String,
val outputData: JsonObject? = null,
val timestamp: Long = Clock.System.now().toEpochMilliseconds()
)Parameters:
taskName: String- Name of the worker that completedsuccess: Boolean- Whether the task succeededmessage: String- Human-readable messageoutputData: JsonObject?- Output data from worker (if successful)timestamp: Long- Event timestamp in epoch milliseconds
Emitting events from workers:
class SyncWorker : IosWorker {
override suspend fun doWork(input: String?, env: WorkerEnvironment): WorkerResult {
return try {
syncDataFromServer()
TaskEventBus.emit(
TaskCompletionEvent(
taskName = "SyncWorker",
success = true,
message = "Data synced successfully",
outputData = buildJsonObject {
put("count", 100)
}
)
)
WorkerResult.Success(message = "Data synced successfully")
} catch (e: Exception) {
TaskEventBus.emit(
TaskCompletionEvent(
taskName = "SyncWorker",
success = false,
message = "Sync failed: ${e.message}"
)
)
WorkerResult.Failure("Sync failed: ${e.message}")
}
}
}Collecting events in UI:
@Composable
fun TaskMonitor() {
LaunchedEffect(Unit) {
TaskEventBus.events.collect { event ->
when {
event.success -> {
showSuccessToast(event.message)
}
else -> {
showErrorToast(event.message)
}
}
}
}
}Result of a task scheduling operation.
enum class ScheduleResult {
SUCCESS, // Task scheduled successfully
REJECTED_OS_POLICY, // OS rejected the task (e.g., iOS background restrictions)
REJECTED_INVALID_PARAMS, // Invalid parameters provided
FAILED_UNKNOWN // Unknown error occurred
}Retry strategy for failed tasks.
enum class BackoffPolicy {
EXPONENTIAL, // Exponential backoff (10s, 20s, 40s, 80s, ...)
LINEAR // Linear backoff (10s, 20s, 30s, 40s, ...)
}Policy for handling existing tasks with the same ID.
enum class ExistingWorkPolicy {
REPLACE, // Cancel existing and schedule new task
KEEP, // Keep existing task, ignore new request
APPEND, // Queue new task after existing one
APPEND_OR_REPLACE // Append if running, replace otherwise
}Network requirement for tasks.
enum class NetworkType {
NOT_REQUIRED, // No network needed
CONNECTED, // Any network connection
UNMETERED, // WiFi or unlimited data
NOT_ROAMING, // Non-roaming network
METERED, // Cellular data allowed
TEMPORARILY_UNMETERED // Temporarily free network
}Priority hint for iOS tasks.
enum class QualityOfService {
HIGH, // User-initiated priority
DEFAULT, // Default priority
LOW // Background priority
}Base worker class for deferrable tasks.
class KmpWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val workerClassName = inputData.getString("workerClassName")
return when (workerClassName) {
"YourWorker" -> executeYourWorker()
else -> Result.failure()
}
}
private suspend fun executeYourWorker(): Result {
// Your implementation
return Result.success()
}
}Foreground service worker for long-running tasks (>10 minutes).
class KmpHeavyWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
setForeground(createForegroundInfo())
// Your long-running work here
return Result.success()
}
private fun createForegroundInfo(): ForegroundInfo {
// Create notification for foreground service
}
}Kotlin-native API for handling the iOS background task lifecycle. Replaces the need for manual Swift boilerplate in AppDelegate.
object IosBackgroundTaskHandler {
fun handleSingleTask(
task: BGTask,
scheduler: BackgroundTaskScheduler,
executor: SingleTaskExecutor
)
fun handleChainExecutorTask(
task: BGTask,
chainExecutor: ChainExecutor
)
}Swift Usage:
BGTaskScheduler.shared.register(forTaskWithIdentifier: "my-task", using: nil) { task in
IosBackgroundTaskHandler.shared.handleSingleTask(
task: task,
scheduler: koin.getScheduler(),
executor: koin.getExecutor()
)
}Interface for iOS background workers.
interface IosWorker : dev.brewkits.kmpworkmanager.background.domain.Worker {
override suspend fun doWork(input: String?, env: WorkerEnvironment): WorkerResult
}Implementation:
class SyncWorker : IosWorker {
override suspend fun doWork(input: String?, env: WorkerEnvironment): WorkerResult {
// Your implementation (must complete within 25 seconds for light tasks)
return WorkerResult.Success(message = "Sync complete")
}
}Factory for creating worker instances.
interface IosWorkerFactory : dev.brewkits.kmpworkmanager.background.domain.WorkerFactory {
override fun createWorker(workerClassName: String): IosWorker?
}const val ONE_SECOND = 1_000L
const val ONE_MINUTE = 60_000L
const val FIFTEEN_MINUTES = 900_000L
const val ONE_HOUR = 3_600_000L
const val ONE_DAY = 86_400_000L- Quick Start Guide - Get started in 5 minutes
- Platform Setup - Detailed platform configuration
- Task Chains - Advanced workflow patterns
- Constraints & Triggers - Detailed trigger documentation
- GitHub Issues