Background task scheduling and dispatch for iOS.
ForgeBackgroundTasks wraps BGTaskScheduler in a registry-based API. Define your tasks, register them once at launch, and ForgeBackgroundTasks handles system registration, scheduling, the expiration/completion race, and automatic rescheduling.
BackgroundTaskRegistry— handlesBGTaskScheduler.register, request building, dispatch, and the expiration/completion race with atomic state trackingBackgroundTaskprotocol — identifier,requiresNetwork,requiresProtectedData, schedule config, andexecute(context:)for the actual work- Connectivity and protected-data pre-checks — skip tasks cleanly when the device is locked or offline
- Automatic rescheduling — tasks reschedule themselves on completion or expiration
- Refresh and processing variants —
BGAppRefreshTaskRequestandBGProcessingTaskRequestvia a singleBackgroundTaskScheduleenum - Dependency-injected observers — takes
ConnectivityObservingandProtectedDataObservingfrom ForgeObservers or your own
- iOS 18+
- Swift 6.3+ (Xcode 26 or later)
- Task identifiers declared in
BGTaskSchedulerPermittedIdentifiersin Info.plist processingbackground mode for.processingschedule variants
- File → Add Package Dependencies…
- Paste
https://github.com/stefanprojchev/ForgeBackgroundTasks.git - Set rule to Up to Next Major from
1.0.0
dependencies: [
.package(url: "https://github.com/stefanprojchev/ForgeBackgroundTasks.git", from: "1.0.0")
],
targets: [
.target(
name: "YourApp",
dependencies: ["ForgeBackgroundTasks"]
)
]import ForgeBackgroundTasks
struct SyncTask: BackgroundTask {
let identifier = "com.yourapp.sync"
let requiresNetwork = true
let requiresProtectedData = false
let schedule: BackgroundTaskSchedule = .refresh(interval: 3600)
func execute(context: BackgroundTaskContext) async {
guard context.connectivity.isConnected else { return }
let items = try? await api.fetchPendingUpdates()
for item in items ?? [] {
if context.isCancelled() { return }
try? await process(item)
}
}
}import UIKit
import ForgeBackgroundTasks
import ForgeObservers
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
let registry = BackgroundTaskRegistry(
connectivity: ConnectivityObserver(),
protectedData: ProtectedDataObserver()
)
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
registry.register([
SyncTask(),
CleanupTask(),
])
registry.registerWithSystem()
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
registry.scheduleAll()
}
}<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.yourapp.sync</string>
<string>com.yourapp.cleanup</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>// Short refresh (~30s window)
.refresh(interval: 3600)
// Long-running processing task
.processing(
requiresNetwork: true,
requiresCharging: true,
interval: 7200
)ForgeBackgroundTasks is part of the Forge family of Swift packages for iOS.
| Package | Description |
|---|---|
| ForgeCore | Thread-safe primitives for iOS Swift packages. |
| ForgeInject | Dependency injection with constructor and property wrapper support. |
| ForgeObservers | Reactive system observers — connectivity, lifecycle, keyboard, and more. |
| ForgeStorage | Type-safe key-value, file, and Keychain storage. |
| ForgeDB | Type-safe repository pattern and GRDB-backed SQLite persistence. |
| ForgeOrchestrator | Orchestrate app flows — startup gates, data pipelines, and continuous monitors. |
| ForgePush | Push notification management — permissions, tokens, and routing. |
| ForgeLocation | Location triggers — geofencing, significant changes, and visits. |
| ForgeBackgroundTasks | Background task scheduling and dispatch. |
| ForgeNetworking | Typed, async/await-first HTTP networking with auth, retry, and background transfers. |
| ForgeLog | Structured logging with pluggable providers and a built-in inspector UI. |
| ForgeAccess | Subscription-aware feature gating with override channels and debug UI. |
ForgeBackgroundTasks is released under the MIT License. See LICENSE.