This guide covers the necessary steps to properly configure your iOS project for native_workmanager, specifically focusing on the integration of the Kotlin Multiplatform (KMP) framework.
- Xcode 14.0+
- CocoaPods 1.12.0+
- iOS Deployment Target: 14.0+
- Apple Silicon Mac (M1/M2/M3): Requires specific Podfile configuration for simulators.
The native_workmanager plugin includes a pre-compiled .xcframework. To ensure it works across all architectures (including simulators on Apple Silicon), you must add the following post_install hook to your ios/Podfile:
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
# 1. Ensure deployment target matches (minimum 14.0 for KMP compatibility)
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
# 2. Fix Apple Silicon Simulator architecture issues
# This prevents "Undefined symbol: _OBJC_CLASS_$_..." errors when running on M1/M2/M3 Macs
config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386 arm64'
end
end
endThe KMPWorkManager.xcframework is a binary dependency. By default, Xcode might try to build it for arm64 simulators on Intel Macs or vice versa, causing linker errors. The configuration above ensures that the simulator only uses the compatible architecture.
You must register the background task identifiers used by the plugin. Open ios/Runner/Info.plist and add:
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<!-- Used for standard background tasks -->
<string>dev.brewkits.native_workmanager.refresh</string>
<!-- Used for heavy background tasks (Processing tasks) -->
<string>dev.brewkits.native_workmanager.task</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>To handle background task completion and URLSession events, update your AppDelegate.swift:
import UIKit
import Flutter
import native_workmanager
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// REQUIRED: Handle Background URLSession events (for downloads/uploads)
override func application(
_ application: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void
) {
NativeWorkmanagerPlugin.handleBackgroundURLSession(
identifier: identifier,
completionHandler: completionHandler
)
}
}- Solution: Ensure you have run
pod installin theiosdirectory. - Solution: Check if the
KMPWorkManager.xcframeworkexists inios/Pods/native_workmanager/Frameworks/. - Solution: Verify your
IPHONEOS_DEPLOYMENT_TARGETis at least14.0in BOTH the project and the Podfile.
- Solution: This usually happens on Apple Silicon Macs. Ensure you have added the
EXCLUDED_ARCHSsetting in thepost_installhook shown above. - Solution: Try running Xcode using Rosetta (Right-click Xcode.app -> Get Info -> Open using Rosetta), though the Podfile fix is the preferred modern approach.
- Reason: iOS Simulator does not support automatic
BGTaskSchedulerfiring. - Solution: Use the debugger command in Xcode's LLDB console:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"dev.brewkits.native_workmanager.refresh"]
Symptoms: Your DartWorker runs, but other plugins like flutter_local_notifications or shared_preferences don't seem to work or throw errors.
Solution: Enable plugin registration during initialization in Dart:
await NativeWorkManager.initialize(
registerPlugins: true,
dartWorkers: { ... },
);By default, the background engine does not register plugins to save RAM and avoid side-effects.
To maintain peak performance and avoid side-effects (like Audio/Bluetooth drops), we recommend keeping registerPlugins: false and manually registering only the necessary plugins for your background tasks.
In your AppDelegate.swift:
import native_workmanager
import flutter_local_notifications
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GeneratedPluginRegistrant.register(with: self)
NativeWorkmanagerPlugin.setPluginRegistrantCallback { registry in
// Manually register specific plugins for the background engine
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")!)
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}The plugin includes a PrivacyInfo.xcprivacy file as required by Apple (effective May 2024). It declares the use of:
- Background Tasks API: Used for scheduling work.
- File System API: Used for
FileWorkerandImageProcessWorker.
No additional action is needed; CocoaPods will automatically merge this into your app's privacy manifest.