首页 > 解决方案 > iOS 13 中的后台任务不会多次运行

问题描述

我正在使用新的 iOS13 后台任务框架,实现了 BGAppRefreshTask 类型。我不知道我做错了什么,因为我尝试了许多不同的方法,但是后台任务从未执行过一次我想以恒定的时间间隔将用户的位置更新到服务器,我启用了后台位置更新和后台获取能力。我试过方法

performFetchWithCompletionHandler

但它在 iOS 13 中已贬值,我正在 iPhone 11 中进行测试,除非我从 Debug > Simulate background fetch 运行它,否则它从不工作除此之外,我已经尝试过我在 WWDC 2019 中看到的这段代码

这里是

应用代表:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
     LocationHelper.shared.locationManager = CLLocationManager()
            
            if #available(iOS 13.0, *) {
                BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.testApp.updateLocation", using: nil) { task in
                    //This task is cast with processing request (BGProcessingTask)
                    self.handleLocationUpdateTask(task: task as! BGAppRefreshTask)
                }
                self.registerLocalNotification()
            } else {
                // Fallback on earlier versions
            }
    
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
            if #available(iOS 13.0, *) {
                cancelAllPendingBGTask()
                scheduleLocationUpdate()
            } else {
                // Fallback on earlier versions
            }
        }

    func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
            // For iOS < 13
            // fetch data from internet now
            if #available(iOS 13.0, *) {
            }
            else {
                LocationHelper.shared.locationManager.startMonitoringSignificantLocationChanges()
                
                fetchSomeData(completion: { (bool) in
                    if bool {
                        LocationHelper.shared.locationManager.stopMonitoringSignificantLocationChanges()
                        completionHandler(.newData)
                    } else {
                        LocationHelper.shared.locationManager.stopMonitoringSignificantLocationChanges()
                        completionHandler(.failed)
                    }
                })
            }
        }

func registerLocalNotification() {
        let notificationCenter = UNUserNotificationCenter.current()
        let options: UNAuthorizationOptions = [.alert, .sound, .badge]
        
        notificationCenter.requestAuthorization(options: options) {
            (didAllow, error) in
            if !didAllow {
                print("User has declined notifications")
            }
        }
    }
    
    //MARK: Register BackGround Tasks
    
    @available(iOS 13.0, *)
    func scheduleLocalNotification() {
        let notificationCenter = UNUserNotificationCenter.current()
        notificationCenter.delegate = self
        notificationCenter.getNotificationSettings { (settings) in
            if settings.authorizationStatus == .authorized {
                self.fireNotification()
            }
        }
    }
    
    @available(iOS 13.0, *)
    func scheduleLocationUpdate() {
        let request = BGAppRefreshTaskRequest(identifier: "com.testApp.updateLocation") // BGProcessingTaskRequest(identifier: "com.testApp.updateLocation")
        request.earliestBeginDate = Date(timeIntervalSinceNow: 10) // fetch data after 10 secs.
        //Note :: EarliestBeginDate should not be set to too far into the future.
        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("Could not schedule image fetch: (error)")
        }
    }
    
    @available(iOS 13.0, *)
    func handleLocationUpdateTask(task: BGAppRefreshTask) {
        scheduleLocationUpdate()
        
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        let lastOperation = queue.operations.last!
        
        task.expirationHandler = {
            queue.cancelAllOperations()
        }
        
        
        lastOperation.completionBlock = {
            task.setTaskCompleted(success: !lastOperation.isCancelled)
        }
        
        queue.addOperation {
            self.fetchSomeData { (bool) in
                self.scheduleLocalNotification()
                task.setTaskCompleted(success: bool)
            }
        }
        
    }
    
    @available(iOS 13.0, *)
    func cancelAllPendingBGTask() {
        BGTaskScheduler.shared.cancelAllTaskRequests()
    }
    
    func fireNotification() {
        // Create Notification Content
        let notificationContent = UNMutableNotificationContent()
        
        // Configure Notification Content
        notificationContent.title = Constants.Values.appName.rawValue
        notificationContent.body = "The app just tried to run a background task on \(UserDefaults.standard.string(forKey: "LastBackgroundFetch") ?? "NEVER")"
        notificationContent.badge = 1
        if #available(iOS 12.0, *) {
            notificationContent.sound = .defaultCriticalSound(withAudioVolume: .infinity)
        } else {
            // Fallback on earlier versions
        }
        
        // Add Trigger
        let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 1.0, repeats: false)
        
        // Create Notification Request
        let notificationRequest = UNNotificationRequest(identifier: "local_notification", content: notificationContent, trigger: notificationTrigger)
        UNUserNotificationCenter.current().delegate = self
        // Add Request to User Notification Center
        UNUserNotificationCenter.current().add(notificationRequest) { (error) in
            if let error = error {
                print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
            }
        }
    }

func fetchSomeData(completion: @escaping (Bool) -> () ) {
        
        LocationHelper.shared.updateUser { (bool) in
            let date = DateFormatter.sharedDateFormatter.string(from: Date())
            UserDefaults.standard.set(date, forKey: "LastBackgroundFetch")
            completion(bool)
        }
    }

在这段代码中,我可以通过暂停应用程序,然后在调试器中输入这段代码,然后恢复,按照苹果的文档测试后台模式

e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.FindFamily.updateLocation"]

即使在此之后,代码只运行一次然后停止,实际上它应该scheduleLocationUpdate()在函数内部调用它自己handleLocationUpdateTask(task:),这将在每 10 秒(大约)后调用一次

标签: swiftxcodeios13

解决方案


我发现我正在使用后台进程来实现一些可能没有它的问题我在功能部分启用了后台位置更新,它开始在后台给我持续更新。


推荐阅读