iOS Swift实现后台每小时调用Alamofire接口并推送本地通知
解决方案:iOS后台/关闭状态下周期性获取数据并推送通知
核心问题分析
你当前使用UIApplication.willResignActiveNotification仅能在APP即将退至后台时触发一次请求,无法实现周期性执行;且APP完全关闭后,沙盒内的代码完全停止运行,常规本地通知触发无法唤醒APP执行网络请求。iOS对后台行为有严格限制,必须依赖系统提供的合法后台机制才能实现需求。
方案1:后台刷新任务(Background App Refresh)- 处理APP后台状态
该机制允许系统在后台唤醒APP,执行短时间的数据获取任务,系统会根据用户使用习惯、设备状态调度执行(无法保证严格每小时,但可设置最小间隔)。
步骤1:开启后台刷新权限
- 在
Info.plist中添加键UIBackgroundModes,添加子项fetch; - 在Xcode项目的
Signing & Capabilities中,开启Background Modes并勾选Background fetch。
步骤2:实现后台刷新回调
在AppDelegate中实现以下方法,替换原有的通知监听逻辑:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 设置后台刷新最小间隔(单位:秒),这里设为3600小时 application.setMinimumBackgroundFetchInterval(3600) // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } return true } func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 调用数据获取方法,完成后通知系统 getCustomerOrders { hasNewData in completionHandler(hasNewData ? .newData : .noData) } }
步骤3:重构数据获取方法
将原有的getCustomerOrders改为带完成回调的异步方法,避免阻塞后台任务:
func getCustomerOrders(completion: @escaping (Bool) -> Void) { let headers = [ "accept": "application/json", "Username": "info@bse.com.cy", "Password": "1234" ] Alamofire.request("https://leathermaster.bse.com.cy/api/getcompletedorders", method: .get, headers: headers) .responseJSON { response in switch response.result { case .success: guard let data = response.data else { completion(false) return } do { let orders = try JSONDecoder().decode([OrderComplete].self, from: data) let preferences = UserDefaults.standard guard let userPhone = preferences.string(forKey: "phone") else { completion(false) return } // 筛选当前用户的有效订单 let userOrders = orders.filter { $0.PhoneNumber == userPhone } guard !userOrders.isEmpty else { completion(false) return } // 推送本地通知(找到符合条件的订单立即推送) let center = UNUserNotificationCenter.current() for order in userOrders { let content = UNMutableNotificationContent() let userName = "\(preferences.string(forKey: "firstname") ?? "") \(preferences.string(forKey: "surname") ?? "")" content.title = "\(userName) your order with \(order.TransactionCode) is ready for pickup" let cleanDate = order.TransactionDate.date.replacingOccurrences(of: ".000000", with: "") content.body = "\(order.TransactionStatus) | Date: \(cleanDate)" content.sound = .default content.userInfo = ["transactionCode": order.TransactionCode] // 立即触发通知 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false) let request = UNNotificationRequest(identifier: "order_\(order.TransactionCode)", content: content, trigger: trigger) center.add(request) { error in if let error = error { print("Notification error: \(error.localizedDescription)") } } } completion(true) } catch { print("Decode error: \(error.localizedDescription)") completion(false) } case .failure(let error): print("Request error: \(error.localizedDescription)") completion(false) } } }
方案2:静默远程通知 - 处理APP完全关闭状态
iOS中APP完全关闭后,无法通过本地机制唤醒,必须依赖静默远程通知(Silent Push)。服务器定时发送静默通知,系统会唤醒APP在后台执行代码,完成数据检查和通知推送。
步骤1:配置静默通知Payload
服务器发送的推送Payload需包含content-available: 1,示例:
{ "aps": { "content-available": 1 }, "type": "order_check" }
注意:静默通知不能包含
alert、sound等可见内容,否则会变成普通推送;若需要同时展示通知,可添加alert字段并保留content-available:1。
步骤2:处理静默通知回调
在AppDelegate中实现以下方法:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 判断是否为订单检查类型的静默通知 if userInfo["type"] as? String == "order_check" { getCustomerOrders { hasNewData in completionHandler(hasNewData ? .newData : .noData) } } else { completionHandler(.noData) } }
关键注意事项
- 后台刷新调度限制:系统不会严格按照设置的3600秒执行,会根据用户使用频率、电池电量等因素调整,低电量或长时间未使用APP时可能暂停。
- 后台任务时长限制:所有后台任务(包括后台刷新、静默通知唤醒)的执行时间约为30秒,需确保网络请求高效完成。
- 权限依赖:用户必须允许APP的「通知权限」和「后台刷新权限」,否则机制无法生效。
- 避免重复通知:创建本地通知时使用唯一标识符(如订单号),避免重复添加相同通知。
内容的提问来源于stack exchange,提问作者Dimitra
相关产品推荐
相关产品推荐

