iOS - 运行 在应用程序关闭的后台网络请求
iOS - Running a network request in the background with app closed
您好,我目前正在开发跨平台(本机 Java 和 Swift/Objective-C)移动应用程序,用户可能经常访问网络连接受限,但我们想记录并在网络可用时发送统计信息,即使我们的应用程序已关闭。我们已经使用他们的 AndroidX.WorkManager
库在 Android 上相当轻松地完成了此操作,如下所示:
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
“背景”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 args)传递给我的后台任务,因为我的任务必须在应用程序启动时注册?
谢谢你,罗兰 K
关闭的应用程序可能处于两种可能的状态。它要么处于后台,要么处于已终止。应用程序可能会由于各种原因被系统终止,或者被用户终止,用户可以从应用程序切换器中终止它。
这很重要,因为当应用程序被终止时,您无法在后台执行任何操作。只有 VoIP 应用程序例外(使用 PushKit,如果应用程序没有 VoIP 功能,你现在可以使用它,你不会'无法通过 AppStore) 和 watchOS 并发症。但是对于所有其他应用程序,当应用程序被终止时,您根本没有任何选择。这只是 Apple 的标准,出于安全原因,他们不希望非 运行 的应用能够 运行 编码。
您可以注册一些要完成的任务,当应用程序仍在后台时,使用您提到的 BGTask API。我对我的一个应用程序使用了相同的 API,发现它非常不稳定。有时一个任务每30分钟完成一次,然后直到明天早上才执行,然后有一次根本不执行。
因此我认为 静默推送通知 是最好的出路,但它们也只有在应用程序仍在后台而不是被杀死时才有效。除非您的应用程序具有 VoIP 功能,在这种情况下您可以使用 PushKit。
您好,我目前正在开发跨平台(本机 Java 和 Swift/Objective-C)移动应用程序,用户可能经常访问网络连接受限,但我们想记录并在网络可用时发送统计信息,即使我们的应用程序已关闭。我们已经使用他们的 AndroidX.WorkManager
库在 Android 上相当轻松地完成了此操作,如下所示:
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
“背景”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 args)传递给我的后台任务,因为我的任务必须在应用程序启动时注册?
谢谢你,罗兰 K
关闭的应用程序可能处于两种可能的状态。它要么处于后台,要么处于已终止。应用程序可能会由于各种原因被系统终止,或者被用户终止,用户可以从应用程序切换器中终止它。
这很重要,因为当应用程序被终止时,您无法在后台执行任何操作。只有 VoIP 应用程序例外(使用 PushKit,如果应用程序没有 VoIP 功能,你现在可以使用它,你不会'无法通过 AppStore) 和 watchOS 并发症。但是对于所有其他应用程序,当应用程序被终止时,您根本没有任何选择。这只是 Apple 的标准,出于安全原因,他们不希望非 运行 的应用能够 运行 编码。
您可以注册一些要完成的任务,当应用程序仍在后台时,使用您提到的 BGTask API。我对我的一个应用程序使用了相同的 API,发现它非常不稳定。有时一个任务每30分钟完成一次,然后直到明天早上才执行,然后有一次根本不执行。
因此我认为 静默推送通知 是最好的出路,但它们也只有在应用程序仍在后台而不是被杀死时才有效。除非您的应用程序具有 VoIP 功能,在这种情况下您可以使用 PushKit。