swift - 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 秒(大约)后调用一次
解决方案
我发现我正在使用后台进程来实现一些可能没有它的问题我在功能部分启用了后台位置更新,它开始在后台给我持续更新。
推荐阅读
- php - PHP > 下载 ZIP:网络错误
- dart - 使用 ScopedModel 过滤 Flutter ListView 会引发奇怪的错误
- java - org.codehaus.plexus.archiver.AbstractArchiver 的 maven 编译器插件错误
- jenkins - Jenkins emailext 多个附件
- unity3d - Resonance 支持哪些平台?
- java - 在 Gmail 中,Selenium 有时会在不同区域返回 WebDriverException
- java - java.lang.System 和 java.io.PrintStream 类之间有什么关系?
- c++ - 为什么多线程代码在更快的机器上运行得更慢?
- php - PHP添加下拉值以更新记录
- appium - 如何在 Appium 中检测滑动完成