我目前正在开发一款跨平台(使用原生Java和Swift/Objective-C)移动应用,用户可能经常面临网络连接受限的情况,但我们希望在网络恢复连接时记录并发送统计数据,即使我们的应用已关闭。我们已经在Android上使用AndroidX.WorkManager
库轻松完成了这项工作,如下所示:
String URL = "https://myexampleurl.com";
Data inputData = new Data.Builder()
.putString("URL", URL)
.build();
Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(NetworkWorker.class)
.setInputData(inputData)
.setConstraints(constraints)
.build();
WorkManager.getInstance(context).enqueueUniqueWork("com.lkuich.exampleWorker", ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest);
这很好用,当我们的应用程序调用此方法时,我们的请求将被添加到队列中,即使用户离线并关闭了我们的应用程序,当他们重新连接到网络时,我们的请求仍然会被执行。
然而,我一直在寻找一个类似于这个API的iOS等效物,而且我对本地iOS开发还比较新。我们已经启用了后台任务功能,并在我们的项目中注册了我们的标识符
Plist.info
。首先,我们尝试了
URLSession
“background” API,代码如下:class NetworkController: NSObject, URLSessionTaskDelegate {
func buildTask() -> URLSession {
let config = URLSessionConfiguration.background(withIdentifier: "com.lkuich.exampleWorker")
config.waitsForConnectivity = true
config.shouldUseExtendedBackgroundIdleMode = true
return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
}
func makeNetworkRequest(session: URLSession) {
let url = URL(string: "https://myexampleurl.com")!
let task = session.dataTask(with: url)
task.resume()
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("We're done here")
}
}
当WiFi被禁用并重新启用时,这很有效,但似乎如果应用程序关闭,则请求永远不会被发送。
因此,我们尝试使用BGTaskScheduler
,但我很难测试它是否在应用程序关闭后在后台工作,因为它通常需要数小时才能实际运行(通过网络连接立即运行它可以起到作用):
static let bgIdentifier = "com.lkuich.exampleWorker"
// Invoked on app start (didFinishLaunchingWithOptions)
static func registerBackgroundTasks() {
BGTaskScheduler.shared.register(forTaskWithIdentifier: bgIdentifier, using: nil) { (task) in
task.expirationHandler = {
task.setTaskCompleted(success: false)
}
// Make my network request in BG
let url = URL(string: "https://myexampleworker.com")!
let t = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
// Print the response
print(response)
task.setTaskCompleted(success: true)
})
t.resume()
}
}
static func makeRequest() {
do {
let bgRequest = BGProcessingTaskRequest(identifier: bgIdentifier)
bgRequest.requiresNetworkConnectivity = true
bgRequest.requiresExternalPower = false
try BGTaskScheduler.shared.submit(bgRequest)
print("Submitted task request")
} catch {
print("Failed to submit BGTask")
}
}
当网络可用时,即使调用应用程序关闭,是否可以安排一个网络请求在后台运行?如果可以的话,我该如何传递输入数据(例如URL参数)给我的后台任务,因为我的任务必须在应用程序启动时注册?
URLSession
方法(URLSessionConfiguration.background
),但似乎它实际上从未在后台运行过。这是否会遇到与使用BGTaskScheduler
创建的后台任务相同的调度问题? - Loren KuichURLSession
,它必须作为BGTask
的一部分才能被安排在后台执行。而且它必须具有URLSessionConfiguration.background
。我遇到了一个问题,即后台执行会在随机行暂停,直到下一次调用。所以下次系统在后台运行应用程序时,执行将从停止的地方继续。很奇怪,无法弄清楚为什么会发生这种情况。 - andrija