我一直在尝试在应用程序终止或终止时检索用户的位置,但到目前为止还没有任何运气。我已经实现了后台位置更新的常用方法,但它们仅在应用程序位于前台或后台时有效,而不是在应用程序完全终止时有效。
我相信苹果地图和谷歌地图等应用程序可以实现这一点,但我不确定他们是如何做到的。下面是我迄今为止尝试过的代码。有人可以建议如何在应用程序被终止或终止时跟踪位置吗?
下面是我当前的代码
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 应用程序终止,您也可以跟踪位置,但有特定条件允许这样做。 Apple 对隐私和后台位置使用有严格的指导方针,并且在应用程序终止时跟踪位置仅限于某些情况,例如重大位置变化或区域监控。
1.startMonitoringSignificantLocationChanges() 2.区域监控(地理围栏)
注意: 您必须请求 .always 授权才能在后台或应用程序终止时进行位置更新