SwiftUI应用中用BackgroundTasks实现网络请求与通知是否可行?
针对你的SwiftUI后台通知需求的方案分析
一、BackgroundTasks 是否适合你的场景?
明确说:BGAppRefreshTask这类后台任务没法保证严格的10分钟间隔执行。苹果的调度逻辑完全基于应用活跃度、设备电量、网络状态等因素,会延迟甚至跳过任务,如果你对“最多10分钟一次”的要求很刚性,这个方案满足不了。
但如果你的市场仅工作日开放4小时,且能接受偶尔的延迟(比如15-20分钟才执行一次),可以尝试用它——毕竟是苹果官方合规的后台任务方案,适配性最好。给你一个SwiftUI下的极简示例:
先在
Info.plist里添加后台权限:
新增UIBackgroundModes数组,加入fetch(对应BGAppRefreshTask)在App结构体里注册并处理任务:
import SwiftUI import BackgroundTasks import UserNotifications @main struct MarketApp: App { init() { // 注册后台刷新任务 BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.yourcompany.market.check", using: nil) { task in handleRefreshTask(task: task as! BGAppRefreshTask) } // 首次启动时请求通知权限并提交第一个任务 Task { await requestNotificationPermission() submitNextRefreshTask() } } var body: some Scene { WindowGroup { ContentView() } } // 处理后台刷新逻辑 private func handleRefreshTask(task: BGAppRefreshTask) { // 先调度下一次任务(最多10分钟后) submitNextRefreshTask() // 执行网络请求检查订单 Task { do { let orders = try await fetchMarketOrders() // 匹配条件:产品A卖单、单价4、数量5kg let targetOrder = orders.first(where: { $0.productId == "A" && $0.type == .sell && $0.price == 4.0 && $0.quantity == 5.0 }) if targetOrder != nil { // 发送本地通知 let content = UNMutableNotificationContent() content.title = "市场异动提醒" content.body = "产品A出现单价4元、5kg的卖单" content.sound = UNNotificationSound.default let request = UNNotificationRequest( identifier: UUID().uuidString, content: content, trigger: nil ) try await UNUserNotificationCenter.current().add(request) } task.setTaskCompleted(success: true) } catch { print("请求或通知发送失败:\(error.localizedDescription)") task.setTaskCompleted(success: false) } } } // 提交下一次后台刷新任务 private func submitNextRefreshTask() { let request = BGAppRefreshTaskRequest(identifier: "com.yourcompany.market.check") request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 10) // 10分钟后 do { try BGTaskScheduler.shared.submit(request) } catch { print("提交后台任务失败:\(error.localizedDescription)") } } // 请求通知权限 private func requestNotificationPermission() async { let center = UNUserNotificationCenter.current() let status = await center.requestAuthorization(options: [.alert, .sound]) if status { await UIApplication.shared.registerForRemoteNotifications() } } // 模拟网络请求接口 private func fetchMarketOrders() async throws -> [Order] { let url = URL(string: "https://your-api-url.com/orders")! let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode([Order].self, from: data) } } // 订单模型示例 struct Order: Codable { let productId: String enum OrderType: String, Codable { case buy, sell } let type: OrderType let price: Double let quantity: Double }
二、更可靠的替代方案
1. 后端触发APNs远程通知(最推荐)
如果你的后端能做监控,完全让后端实时检查订单条件,满足时直接给用户推送苹果远程通知(APNs)——这是最可靠的方案:
- 不需要App在后台跑任务,完全依赖苹果的推送服务,送达率极高
- 避开了系统对后台任务的各种限制
- App只需要处理通知的接收和展示即可
SwiftUI里处理远程通知的核心代码:
@main struct MarketApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { ContentView() } } } class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, _ in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } UNUserNotificationCenter.current().delegate = self return true } // 后台接收远程通知时触发(可用来更新本地数据) func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 这里可以更新本地订单数据 completionHandler(.newData) } // 前台收到通知时展示弹窗 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.alert, .sound]) } }
2. 不推荐的违规方案
- 后台音频播放:利用音频后台权限保活App,苹果审核大概率拒绝,除非你的App是音频类应用
- 后台定位更新:持续触发定位更新来唤醒App,耗电极高,用户体验差,完全不适合你的场景
总结
- 优先选后端触发APNs远程通知,这是最符合苹果生态、最可靠的方案
- 若后端无法配合,只能用
BackgroundTasks,但要接受任务执行的不确定性,尤其是App长期不活跃时,任务可能被系统压制 - 绝对不要用违规的后台保活手段,会导致审核被拒
内容的提问来源于stack exchange,提问作者iosdevok
相关产品推荐
相关产品推荐

