[英]Forwarding user's location to server when application is in the background (Swift/iOS)
I need to keep my server updated with user's location even when the app is in the background or terminated.即使应用程序在后台或终止,我也需要使用用户的位置更新我的服务器。
The location updating is working just fine and seems to wake the application as wanted.位置更新工作得很好,似乎可以根据需要唤醒应用程序。
My problem is regarding the forwarding of the user's location via a PUT
request to the server.我的问题是关于通过
PUT
请求将用户的位置转发到服务器。 I was able to go through the code with breakpoints and it goes well except that when I check with Charles if requests are going though, nothing appears.我能够通过带有断点的代码 go 并且它运行良好,除了当我与 Charles 检查请求是否正在执行时,什么都没有出现。
Here is what I have so far:这是我到目前为止所拥有的:
API Client API 客户端
final class BackgroundNetwork: NSObject, BackgroundNetworkInterface, URLSessionDelegate {
private let keychainStorage: Storage
private var backgroundURLSession: URLSession?
init(keychainStorage: Storage) {
self.keychainStorage = keychainStorage
super.init()
defer {
let sessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundURLSession")
sessionConfiguration.sessionSendsLaunchEvents = true
sessionConfiguration.allowsCellularAccess = true
backgroundURLSession = URLSession(configuration: sessionConfiguration,
delegate: self,
delegateQueue: nil)
}
}
func put<T: Encodable>(url: URL, headers: Headers, body: T) {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "PUT"
let authenticationToken: String? = try? keychainStorage.get(forKey: StorageKeys.authenticationToken)
if let authenticationToken = authenticationToken {
urlRequest.setValue(String(format: "Bearer %@", authenticationToken), forHTTPHeaderField: "Authorization")
}
headers.forEach { (key, value) in
if let value = value as? String {
urlRequest.setValue(value, forHTTPHeaderField: key)
}
}
do {
let jsonData = try JSONEncoder().encode(body)
urlRequest.httpBody = jsonData
} catch {
#if DEBUG
print("\(error.localizedDescription)")
#endif
}
backgroundURLSession?.dataTask(with: urlRequest)
}
}
AppDelegate应用委托
// ...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if launchOptions?[UIApplication.LaunchOptionsKey.location] != nil {
environment.locationInteractor.backgroundDelegate = self
_ = environment.locationInteractor.start()
}
return true
}
// ...
extension AppDelegate: LocationInteractorBackgroundDelegate {
func locationDidUpdate(location: CLLocation) {
taskId = UIApplication.shared.beginBackgroundTask {
UIApplication.shared.endBackgroundTask(self.taskId)
self.taskId = .invalid
}
environment.tourInteractor.updateLocationFromBackground(latitude: Float(location.coordinate.latitude),
longitude: Float(location.coordinate.longitude))
UIApplication.shared.endBackgroundTask(taskId)
taskId = .invalid
}
}
SceneDelegate (yes, the application is using SwiftUI
and Combine
and I target iOS 13
or later) SceneDelegate (是的,应用程序正在使用
SwiftUI
和Combine
,我的目标iOS 13
或更高版本)
func sceneWillEnterForeground(_ scene: UIScene) {
if let environment = (UIApplication.shared.delegate as? AppDelegate)?.environment {
environment.locationInteractor.backgroundDelegate = nil
}
}
func sceneDidEnterBackground(_ scene: UIScene) {
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
appDelegate.environment.locationInteractor.backgroundDelegate = appDelegate
_ = appDelegate.environment.locationInteractor.start()
}
}
So basically, whenever my app goes in background, I set my delegate, restart the location updates and whenever an update comes, my interactor is called and a request is triggered.所以基本上,每当我的应用程序进入后台时,我都会设置我的委托,重新启动位置更新,每当有更新时,都会调用我的交互器并触发请求。
According to breakpoints, eveything just works fine up to backgroundURLSession?.dataTask(with: urlRequest)
.根据断点,一切都可以正常工作到
backgroundURLSession?.dataTask(with: urlRequest)
。 But for some reason the request never gets fired.但由于某种原因,该请求永远不会被解雇。
I obviously checked Background Modes
capabilities Location updates
and Background fetch
.我显然检查了
Background Modes
功能Location updates
和Background fetch
。
Any idea why?知道为什么吗?
That's correct, the line没错,线
backgroundURLSession?.dataTask(with: urlRequest)
does nothing.什么也没做。 The way to do networking with a session task is to say
resume
, and you never say that.使用 session 任务进行联网的方法是说
resume
,而你永远不会那样说。 Your task is created and just thrown away.您的任务已创建并被丢弃。 (I'm surprised the compiler doesn't warn about this.)
(我很惊讶编译器没有对此发出警告。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.