【问题标题】:Forwarding user's location to server when application is in the background (Swift/iOS)当应用程序在后台时将用户的位置转发到服务器(Swift/iOS)
【发布时间】:2021-08-02 00:12:18
【问题描述】:

即使应用程序处于后台或终止状态,我也需要使用用户的位置更新我的服务器。

位置更新工作正常,似乎可以按需要唤醒应用程序。

我的问题是关于通过PUT 请求将用户位置转发到服务器。 我能够通过断点浏览代码,并且运行良好,只是当我与 Charles 检查请求是否正在执行时,什么都没有出现。

这是我目前所拥有的:

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(是的,应用程序正在使用SwiftUICombine,我的目标是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()
    }
}

所以基本上,每当我的应用程序进入后台时,我都会设置我的委托,重新启动位置更新,每当更新到来时,我的交互器就会被调用并触发请求。

根据断点,一切都可以正常工作到backgroundURLSession?.dataTask(with: urlRequest)。但由于某种原因,该请求永远不会被触发。

我显然检查了Background Modes 功能Location updatesBackground fetch

知道为什么吗?

【问题讨论】:

    标签: ios swift core-location background-process urlsession


    【解决方案1】:

    没错,一行

    backgroundURLSession?.dataTask(with: urlRequest)
    

    什么都不做。使用会话任务进行联网的方法是说resume,而你永远不会那样说。您的任务已创建并被丢弃。 (我很惊讶编译器没有对此发出警告。)

    【讨论】:

    • 我在你的代码中也看不到 SwiftUI 或 Combine。如果您不使用它们,请不要导入它们。
    • 这里没有太多的Combine,因为后台不支持dataTaskPublishers。至于resume(),谢谢,我一开始有完成块,但后台不支持块,所以我删除了它们。
    猜你喜欢
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 2015-09-05
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    相关资源
    最近更新 更多