# Quick Start Guide Get KMP WorkManager running in your project in just 5 minutes! ## Table of Contents - [Installation](#installation) - [Android Setup](#android-setup) - [iOS Setup](#ios-setup) - [Your First Task](#your-first-task) - [Create a Worker](#create-a-worker) - [Next Steps](#next-steps) --- ## Installation Add KMP WorkManager to your `build.gradle.kts` (module level): ```kotlin kotlin { sourceSets { commonMain.dependencies { implementation("dev.brewkits:kmpworkmanager:1.1.0") } } } ``` Sync your project with Gradle files. --- ## Android Setup ### Step 1: Add Required Permissions Add these permissions to your `AndroidManifest.xml`: ```xml ``` ### Step 2: Initialize Koin in Application Class Create or update your `Application` class: ```kotlin class MyApp : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MyApp) modules(kmpWorkerModule()) } } } ``` Update your `AndroidManifest.xml` to reference the Application class: ```xml ``` ### Step 3: Add WorkManager Dependency (Optional) KMP WorkManager uses WorkManager internally, but you may want to add it explicitly: ```kotlin androidMain.dependencies { implementation("androidx.work:work-runtime-ktx:2.11.0") } ``` --- ## iOS Setup ### Step 1: Configure Info.plist Add background task identifiers to your `Info.plist`: ```xml BGTaskSchedulerPermittedIdentifiers periodic-sync-task upload-task heavy-processing-task UIBackgroundModes processing fetch remote-notification ``` ### Step 2: Initialize Koin in AppDelegate Create or update your `iOSApp.swift`: ```swift import SwiftUI import composeApp @main struct iOSApp: App { init() { // Initialize Koin KoinIOSKt.doInitKoinIos() // Register background tasks registerBackgroundTasks() } var body: some Scene { WindowGroup { ContentView() } } private func registerBackgroundTasks() { let koinIos = KoinIOS() // Register periodic sync task BGTaskScheduler.shared.register( forTaskWithIdentifier: "periodic-sync-task", using: nil ) { task in koinIos.getScheduler().handleSingleTask( task: task as! BGAppRefreshTask, taskIdentifier: "periodic-sync-task" ) } // Register heavy processing task BGTaskScheduler.shared.register( forTaskWithIdentifier: "heavy-processing-task", using: nil ) { task in koinIos.getScheduler().handleSingleTask( task: task as! BGProcessingTask, taskIdentifier: "heavy-processing-task" ) } } } ``` ### Step 3: Handle App Lifecycle Add this extension to handle background task scheduling when app enters background: ```swift extension iOSApp { func scenePhase(_ phase: ScenePhase) { if phase == .background { // iOS will execute scheduled tasks when app is in background print("App entered background - BGTasks can now execute") } } } ``` --- ## Your First Task Now you're ready to schedule your first background task! ### 1. Inject the Scheduler ```kotlin class MyViewModel( private val scheduler: BackgroundTaskScheduler ) { // Your code here } ``` Or get it from Koin directly: ```kotlin val scheduler: BackgroundTaskScheduler = get() ``` ### 2. Schedule a Periodic Task ```kotlin suspend fun scheduleDataSync() { val result = scheduler.enqueue( id = "data-sync", trigger = TaskTrigger.Periodic( intervalMs = 15 * 60 * 1000 // 15 minutes ), workerClassName = "SyncWorker", constraints = Constraints( requiresNetwork = true, requiresCharging = false ) ) when (result) { ScheduleResult.SUCCESS -> println("Task scheduled successfully!") ScheduleResult.REJECTED_OS_POLICY -> println("OS rejected the task") ScheduleResult.REJECTED_INVALID_PARAMS -> println("Invalid parameters") ScheduleResult.FAILED_UNKNOWN -> println("Unknown error occurred") } } ``` ### 3. Schedule a One-Time Task ```kotlin suspend fun uploadFile() { scheduler.enqueue( id = "file-upload", trigger = TaskTrigger.OneTime( initialDelayMs = 0 // Execute immediately ), workerClassName = "UploadWorker", constraints = Constraints( requiresNetwork = true, networkType = NetworkType.UNMETERED, // WiFi only backoffPolicy = BackoffPolicy.EXPONENTIAL, backoffDelayMs = 10_000 // Retry after 10 seconds ) ) } ``` --- ## Create a Worker Now implement the actual work that will be executed in the background. ### Android Worker Add the worker logic to `KmpWorker.kt` (in `androidMain`): ```kotlin class KmpWorker( context: Context, params: WorkerParameters ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val workerClassName = inputData.getString("workerClassName") return when (workerClassName) { "SyncWorker" -> executeSyncWorker() "UploadWorker" -> executeUploadWorker() else -> Result.failure() } } private suspend fun executeSyncWorker(): Result { return try { // Your sync logic here println("Syncing data from server...") delay(2000) // Emit event to notify UI TaskEventBus.emit( TaskCompletionEvent( taskName = "SyncWorker", success = true, message = "✅ Data synced successfully" ) ) Result.success() } catch (e: Exception) { Logger.e(LogTags.WORKER, "Sync failed", e) Result.retry() } } private suspend fun executeUploadWorker(): Result { return try { // Your upload logic here println("Uploading file...") delay(3000) TaskEventBus.emit( TaskCompletionEvent( taskName = "UploadWorker", success = true, message = "✅ File uploaded" ) ) Result.success() } catch (e: Exception) { Logger.e(LogTags.WORKER, "Upload failed", e) Result.retry() } } } ``` ### iOS Worker Create worker classes in `iosMain/background/workers/`: ```kotlin class SyncWorker : IosWorker { override suspend fun doWork(input: String?): Boolean { return try { // Your sync logic here (must complete within 25 seconds) println("Syncing data from server...") delay(2000) // Emit event to notify UI TaskEventBus.emit( TaskCompletionEvent( taskName = "SyncWorker", success = true, message = "✅ Data synced successfully" ) ) true // Return true for success } catch (e: Exception) { Logger.e(LogTags.WORKER, "Sync failed", e) false // Return false for failure } } } ``` Register the worker in `IosWorkerFactory.kt`: ```kotlin object IosWorkerFactory { fun createWorker(className: String): IosWorker? { return when (className) { "SyncWorker" -> SyncWorker() "UploadWorker" -> UploadWorker() else -> null } } } ``` --- ## Next Steps Congratulations! You've successfully integrated KMP WorkManager. Now you can: 1. **[Explore all triggers](constraints-triggers.md)** - Learn about 9 different trigger types 2. **[Build task chains](task-chains.md)** - Execute sequential and parallel workflows 3. **[Configure constraints](constraints-triggers.md#constraints)** - Fine-tune when tasks run 4. **[Platform-specific setup](platform-setup.md)** - Advanced Android & iOS configuration 5. **[API Reference](api-reference.md)** - Complete API documentation --- ## Common Issues ### Android: Tasks Not Running 1. **Check WorkManager initialization**: Ensure Koin is properly initialized 2. **Check permissions**: Verify all required permissions are in AndroidManifest.xml 3. **Check constraints**: Tasks won't run if constraints aren't met (e.g., no network) 4. **Check Doze mode**: Test with `adb shell dumpsys battery unplug` and `adb shell dumpsys deviceidle force-idle` ### iOS: Background Tasks Not Executing 1. **Check Info.plist**: Ensure task identifiers are registered 2. **Check AppDelegate**: Verify `registerBackgroundTasks()` is called 3. **App must be in background**: BGTasks only run when app is backgrounded 4. **Test with simulator**: Use `e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"periodic-sync-task"]` in LLDB 5. **Check worker registration**: Ensure worker is registered in `IosWorkerFactory` ### Tasks Running But No Events Make sure you're collecting events from `TaskEventBus`: ```kotlin @Composable fun MyScreen() { LaunchedEffect(Unit) { TaskEventBus.events.collect { event -> println("Task event: ${event.taskName} - ${event.message}") } } } ``` --- ## Need Help? - Read the [API Reference](api-reference.md) - Check the [Platform Setup Guide](platform-setup.md) - Browse [GitHub Issues](https://github.com/brewkits/kmpworkmanager/issues) - Ask in [GitHub Discussions](https://github.com/brewkits/kmpworkmanager/discussions) Happy scheduling! 🚀