I want to run the IOS background services like: I want to run the function in the background that will calculate the distance and then will upload that data and bool value to the Firebase after every 2 3 seconds even the app is kill or terminated and just will be stopped if user clicks on stop live location button. It has been done for the Android but how i will perform this for IOS. So, kindly help me to perform this action.
This code is working just for 30 seconds when app is closed or in background. But i want to run it for longer time.
import CoreLocation
import Firebase
import BackgroundTasks
import FirebaseFirestore
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
let locationManager = CLLocationManager()
var backgroundTask: UIBackgroundTaskIdentifier = .invalid
var nameCounter = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Request location authorization
locationManager.requestAlwaysAuthorization()
// Set up Firebase
FirebaseApp.configure()
let db = Firestore.firestore()
// Set up background fetch
if #available(iOS 13.0, *) {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.yourapp.backgroundfetch", using: nil) { task in
// Handle the background fetch task
self.handleAppRefreshTask(task: task as! BGAppRefreshTask)
}
}
return true
}
func startLocationService() {
// Set up location manager
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
// Start location updates
locationManager.startUpdatingLocation()
// Schedule the background fetch task to run every 15 minutes
if #available(iOS 13.0, *) {
let fetchTask = BGAppRefreshTaskRequest(identifier: "com.yourapp.backgroundfetch")
fetchTask.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
do {
try BGTaskScheduler.shared.submit(fetchTask)
print("Background fetch task scheduled")
} catch {
print("Error submitting background fetch task: \(error.localizedDescription)")
}
} else {
// On iOS 12 or earlier, extend the background task
backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "Location Updates") {
self.stopLocationService()
}
DispatchQueue.global(qos: .background).async {
// Schedule the long process to run every 1 minute in the background
Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { timer in
// Execute long process here...
let locationRef = Firestore.firestore().collection("location").document("user1")
guard let location = self.locationManager.location else { return }
let latitude = location.coordinate.latitude
let longitude = location.coordinate.longitude
let locationData = ["latitude": latitude, "longitude": longitude]
locationRef.setData(locationData, merge: true)
}
}
}
}
func stopLocationService() {
locationManager.stopUpdatingLocation()
if #available(iOS 13.0, *) {
BGTaskScheduler.shared.cancelAllTaskRequests()
} else {
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = .invalid
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Update the last location
let location = locations.last!
let lat = location.coordinate.latitude
let lon = location.coordinate.longitude
UserDefaults.standard.set(lat, forKey: "lastLatitude")
UserDefaults.standard.set(lon, forKey: "lastLongitude")
// Schedule the background fetch task to run every 15 minutes
if #available(iOS 13.0, *) {
let fetchTask = BGAppRefreshTaskRequest(identifier: "com.yourapp.backgroundfetch")
fetchTask.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
do {
try BGTaskScheduler.shared.submit(fetchTask)
print("Background fetch task scheduled")
} catch {
print("Error submitting background fetch task: \(error.localizedDescription)")
}
} else {
// On iOS 12 or earlier, extend the background task
UIApplication.shared.perform(#selector(UIApplication.endBackgroundTask), with: backgroundTask)
backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "Location Updates") {
self.stopLocationService()
}
}
if #available(iOS 13.0, *) {
if let task: BGTask = manager.backgroundTask {
task.setTaskCompleted(success: true)
}
} else {
// Fallback on earlier versions
}
}
@available(iOS 13.0, *)
func handleAppRefreshTask(task: BGAppRefreshTask) {
print("Handling app refresh task")
// Execute the long process here...
let db = Firestore.firestore()
let locationRef = db.collection("location").document("user1")
let lat1 = UserDefaults.standard.double(forKey: "lastLatitude")
let lon1 = UserDefaults.standard.double(forKey: "lastLongitude")
guard let location = locationManager.location else { return }
let lat2 = location.coordinate.latitude
let lon2 = location.coordinate.longitude
let distance = Calculatedistance.calculateDistance(lat1: lat1, lon1: lon1, lat2: lat2, lon2: lon2)
let name = "Location(nameCounter)"
nameCounter += 1
let locationData = ["name": name, "latitude": lat2, "longitude": lon2, "distance": distance]
locationRef.setData(locationData, merge: true) { error in
if let error = error {
print("Error writing location data to Firestore: (error.localizedDescription)")
} else {
print("Location data written to Firestore")
}
task.setTaskCompleted(success: error == nil)
}
// Schedule the next background fetch task
let nextFetch = Calendar.current.date(byAdding: .minute, value: 15, to: Date())!
let nextFetchTask = BGAppRefreshTaskRequest(identifier: "com.yourapp.backgroundfetch")
nextFetchTask.earliestBeginDate = nextFetch
do {
try BGTaskScheduler.shared.submit(nextFetchTask)
print("Scheduled next background fetch task for \(nextFetch)")
} catch {
print("Error submitting next background fetch task: \(error.localizedDescription)")
}
}
}
class Calculatedistance {
static func calculateDistance(lat1: Double?, lon1: Double?, lat2: Double, lon2: Double) -> Double {
print("position as initial \(lat1) \(lat2) \(lon1) \(lon2)")
guard let lat1 = lat1 else {
// Initial position not set
return 0
}
let p = 0.017453292519943295
let b = 0.5
let dLat = lat2 - lat1
let dLon = lon2 - (lon1 ?? 0.0)
let lat1Rad = lat1 * p
let lat2Rad = lat2 * p
let dLatRad = dLat * p
let dLonRad = dLon * p
let a = b - cos(dLatRad) / 2 + cos(lat1Rad) * cos(lat2Rad) * (1 - cos(dLonRad)) / 2
print("\(12742 * asin(sqrt(a)))")
return 12742 * asin(sqrt(a))
}
func radians(degree: Double) -> Double {
return degree * Double.pi / 180
}
}
``
This code is working just for 30 seconds when app is closed or in background. But i want to run it for longer time.