IOS:后台任务仅执行一次或两次,而不是定期执行

问题描述 投票:0回答:1

我的后台任务,按照Apple的文档实现,只运行一两次,而不是连续运行一次又一次。寻求帮助来解决此问题。

应用程序委托

import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    let apiKey = "xxxxxxx"  // jsonbin x-master-key
    let timestampUserDefaultsKey = "Timestamps"
    static let backgroundAppRefreshTaskSchedulerIdentifier = "com.process"
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Register a background task
        if #available(iOS 13.0, *) {
            let status = BGTaskScheduler.shared.register(
                forTaskWithIdentifier: AppDelegate.backgroundAppRefreshTaskSchedulerIdentifier, using: .global()) { task in
                    self.handleBackgroundTask(task: task as! BGProcessingTask)
                }
            print(status)
        }
        return true
    }
    
    func handleBackgroundTask(task: BGProcessingTask) {
        self.scheduleAppRefresh()
        task.expirationHandler = {
            task.setTaskCompleted(success: false)
            self.scheduleAppRefresh()
        }
        let backgroundQueue = DispatchQueue.global(qos: .background)
        
        backgroundQueue.async {
            self.postToJsonBin(prefix:"P-Background") { result in
                switch result {
                case .success(let responseJSON):
                    // Handle the success and responseJSON
                    print("Response JSON: \(responseJSON)")
                    task.setTaskCompleted(success: true)
                    
                case .failure(let error):
                    task.setTaskCompleted(success: false)
                    // Handle the error
                    print("Error: \(error.localizedDescription)")
                }
                
            }
        }
    }
    
    func scheduleAppRefresh() {
        if #available(iOS 13.0, *) {
            let request = BGProcessingTaskRequest(identifier: AppDelegate.backgroundAppRefreshTaskSchedulerIdentifier)
            // Fetch no earlier than 15 seconds from now.
            request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 5)  // 60 seconds
            //            request.requiresNetworkConnectivity = true
            do {
                try BGTaskScheduler.shared.submit(request)
                print("bg App Refresh requested")
            } catch {
                print("Could not schedule app refresh: \(error)")
            }
        }
    }
    
    
    func postToJsonBin(prefix:String, completion: @escaping (Result<Any, Error>) -> Void) {
        // Define the URL for jsonbin.io with the collection ID
        
        let apiUrl = URL(string: "https://api.jsonbin.io/v3/b")!
        
        // Define your JSON data including the timestamp parameter
        let jsonData: [String: Any] = ["timestamp": Date().currentTimestampInIST(), "prefix":prefix]
        
        do {
            // Serialize the JSON data
            let requestData = try JSONSerialization.data(withJSONObject: jsonData)
            
            // Create the URLRequest
            var request = URLRequest(url: apiUrl)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.setValue(apiKey, forHTTPHeaderField: "X-Master-Key") // Replace with your API key
            request.setValue(prefix, forHTTPHeaderField: "X-Bin-Name")
            
            // Set the HTTP body with the serialized JSON data
            request.httpBody = requestData
            
            // Create a URLSession task
            let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
                if let error = error {
                    completion(.failure(error))
                    return
                }
                
                if let httpResponse = response as? HTTPURLResponse,
                   httpResponse.statusCode == 200 {
                    if let responseData = data {
                        do {
                            // Parse the response data and call the completion handler
                            let responseJSON = try JSONSerialization.jsonObject(with: responseData, options: [])
                            completion(.success(responseJSON))
                        } catch {
                            completion(.failure(error))
                        }
                    }
                } else {
                    completion(.failure(NSError(domain: "JsonBinErrorDomain", code: 0, userInfo: nil))) // Replace with appropriate error handling
                }
            }
            
            // Start the URLSession task
            task.resume()
        } catch {
            completion(.failure(error))
        }
    }
}

extension Date {
    func currentTimestampInIST() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.timeZone = TimeZone(identifier: "Asia/Kolkata") // Set the time zone to IST
        
        // Define your desired date format
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        
        // Get the current date and time
        let currentDate = Date()
        
        // Format the date as a string in IST
        let istTimestamp = dateFormatter.string(from: currentDate)
        
        return istTimestamp
    }
}

场景委托

func sceneDidEnterBackground(_ scene: UIScene) {
    if #available(iOS 13.0, *) {
        let request = BGProcessingTaskRequest(identifier: AppDelegate.backgroundAppRefreshTaskSchedulerIdentifier)
        request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 5 )
        do {
            try BGTaskScheduler.shared.submit(request)
            print("bg App Refresh requested")
        } catch {
            print("Could not schedule app refresh: \(error)")
        }
    }
}

观察

给了5分钟作为最早的开始时间间隔,并观察了18小时,发现只执行了两次,有时只执行了一次。

我想要什么

  1. 我希望后台任务能够连续执行,即使 执行时间超出预期。
  2. 代码有问题吗?
  3. 如果这是正常行为,那么我怎样才能实现第 1 点。
ios swift uikit background-task bgtaskscheduler
1个回答
0
投票

如果您希望后台任务每 5 分钟运行一次,您可以这样做:

通过后台推送唤醒您的应用程序

这确实需要大量的实际工作才能让 APNS 正常工作(请记住,静默后台通知不是本地通知)。

话虽如此,我认为您的方法对于您所描述的应用程序功能来说并不理想,我认为评论很好地解释了这一点。通过网络加载应用程序数据的视觉延迟是一个常见问题,除了让本地后台任务进行轮询/数据拉取之外,还有很多方法可以解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.