当我的 iOS 应用程序在 Swift 中被杀死或终止时,如何获取用户的位置?

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

我一直在尝试在应用程序终止或终止时检索用户的位置,但到目前为止还没有任何运气。我已经实现了后台位置更新的常用方法,但它们仅在应用程序位于前台或后台时有效,而不是在应用程序完全终止时有效。

我相信苹果地图和谷歌地图等应用程序可以实现这一点,但我不确定他们是如何做到的。下面是我迄今为止尝试过的代码。有人可以建议如何在应用程序被终止或终止时跟踪位置吗?

下面是我当前的代码

import UIKit
import MapKit

class ViewController: UIViewController {
    @IBOutlet weak var lblLatitude: UILabel!
    @IBOutlet weak var lblLongitude: UILabel!
    @IBOutlet weak var lblSavedLocation: UILabel!
    @IBOutlet weak var lblArrayCount: UILabel!

    var locManager = CLLocationManager()
    var currentLocation: CLLocation!
    private var backgroundTask = UIBackgroundTaskIdentifier.invalid
    private var timer: Timer?

    var locationDataSaved = [String]()
    var count = Int()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Request Always Authorization
        locManager.requestAlwaysAuthorization()
        locManager.delegate = self

        // Start monitoring location
        startMonitoring()
        loadAndPrintSavedLocations()
    }

    func startMonitoring() {
        locManager.allowsBackgroundLocationUpdates = true
        locManager.pausesLocationUpdatesAutomatically = false
        locManager.startUpdatingLocation()
    }

    func getLocationData() {
        if (CLLocationManager.authorizationStatus() == .authorizedWhenInUse || CLLocationManager.authorizationStatus() == .authorizedAlways) {
            guard let currentLocation = self.locManager.location else {
                return
            }

            lblLatitude.text = "\(currentLocation.coordinate.latitude)"
            lblLongitude.text = "\(currentLocation.coordinate.longitude)"

            let newLocationData = ["latitude": "\(currentLocation.coordinate.latitude)", "longitude": "\(currentLocation.coordinate.longitude)"]

            // Load existing locations
            var savedLocations = UserDefaults.standard.array(forKey: "locationDataSaved") as? [[String: String]] ?? []

            // Check for duplicates
            let isDuplicate = savedLocations.contains { location in
                location["latitude"] == newLocationData["latitude"] && location["longitude"] == newLocationData["longitude"]
            }

            // If not a duplicate, add to the saved locations
            if !isDuplicate {
                savedLocations.append(newLocationData)
                UserDefaults.standard.setValue(savedLocations, forKey: "locationDataSaved")
                print("Location added: Latitude: \(currentLocation.coordinate.latitude), Longitude: \(currentLocation.coordinate.longitude)")
                
                // Call postLocation to send the location to server
                postLocation(location: currentLocation)
            } else {
                print("Duplicate location, not added.")
            }
        }
    }

    private func loadAndPrintSavedLocations() {
        if let savedLocations = UserDefaults.standard.array(forKey: "locationDataSaved") as? [[String: String]] {
            var locationText = ""
            count = savedLocations.count
            lblArrayCount.text = "\(count)"
            for location in savedLocations {
                if let latitude = location["latitude"], let longitude = location["longitude"] {
                    print("Saved Location: Latitude: \(latitude), Longitude: \(longitude)")
                    locationText += "Latitude: \(latitude), Longitude: \(longitude)\n"
                }
                lblSavedLocation.text = locationText.isEmpty ? "No saved locations." : locationText
            }
        } else {
            print("No saved locations found.")
        }
    }

    func startBackgroundTimer() {
        timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(callApiInBackground), userInfo: nil, repeats: true)
    }

    @objc func callApiInBackground() {
        // This function will be called every 5 seconds
        postLocation(location: currentLocation)
    }

    func stopBackgroundTimer() {
        timer?.invalidate()
        timer = nil
    }

    deinit {
        stopBackgroundTimer()
    }
}

extension ViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Use the last known location
        if let location = locations.last {
            self.currentLocation = location
            getLocationData() // Process the location data

            // Start the background timer when location updates are received
            if UIApplication.shared.applicationState == .background {
                startBackgroundTimer()
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("LocationManager \(error)")
    }
}

extension ViewController {
    private func postLocation(location: CLLocation?) {
        guard let location = location else { return }

        if UIApplication.shared.applicationState == .background {
            backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "locationTaskName", expirationHandler: {
                UIApplication.shared.endBackgroundTask(self.backgroundTask)
                self.backgroundTask = UIBackgroundTaskIdentifier.invalid
            })

            DispatchQueue.global(qos: .background).async {
                self.postRequest(location: location) { [weak self] in
                    guard let self = self else { return }
                    UIApplication.shared.endBackgroundTask(self.backgroundTask)
                    self.backgroundTask = UIBackgroundTaskIdentifier.invalid
                }
            }
        } else {
            postRequest(location: location)
        }
    }

    private func postRequest(location: CLLocation, completion: (() -> Void)? = nil) {
        // Call your API
        callApi()
        completion?()
    }
}

extension ViewController {
    func callApi() {
        // The API URL
        guard let url = URL(string: "https://new-dev.artoon.in:8888/rwl-app-cms/Custom_script/ios_test") else {
            print("Invalid URL")
            return
        }

        // Create a URL session
        let session = URLSession.shared

        // Create a data task
        let task = session.dataTask(with: url) { (data, response, error) in
            // Check for errors
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            // Check for valid response
            guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
                print("Invalid response")
                return
            }

            // Check for data
            guard let data = data else {
                print("No data returned")
                return
            }

            // Handle the data (convert to string for demonstration)
            if let responseString = String(data: data, encoding: .utf8) {
                print("Response: \(responseString)")
            }
        }

        // Start the task
        task.resume()
    }
}
ios swift mapkit core-location locationmanager
1个回答
0
投票

是的,即使您的 iOS 应用程序终止,您也可以跟踪位置,但有特定条件允许这样做。 Apple 对隐私和后台位置使用有严格的指导方针,并且在应用程序终止时跟踪位置仅限于某些情况,例如重大位置变化或区域监控。

1.startMonitoringSignificantLocationChanges() 2.区域监控(地理围栏)

注意: 您必须请求 .always 授权才能在后台或应用程序终止时进行位置更新

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