Run IOS Background Services for longer time

0 votes

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.

Mar 31, 2023 in Flutter by Ashwini
• 5,430 points
2,273 views

1 answer to this question.

0 votes

To run an iOS app's background services for a longer time, you can use various techniques provided by Apple, depending on your specific use case. In general, you can use background tasks, background modes, and background fetches to keep your app running in the background and performing tasks while the app is not in use.

Based on the code snippet you provided, it seems like you have already implemented background tasks and background fetches to keep your app running in the background. However, your code has a limitation of only running for 30 seconds when the app is closed or in the background.

To overcome this limitation, you can use background processing capabilities provided by iOS, such as background fetch, background transfer service, and background sessions, to execute your long-running tasks. Here are some general tips to help you extend the background processing time of your app:

  1. Use Background Modes: Apple provides various background modes that allow you to perform specific tasks in the background, such as playing audio, receiving push notifications, and updating your location. You can enable these modes by adding the appropriate keys to your app's Info.plist file.

  2. Use Background Transfer Service: If your app needs to download or upload large files in the background, you can use the Background Transfer Service provided by iOS. This service allows your app to continue transferring files even if the app is suspended or terminated.

  3. Use Background Sessions: If your app needs to download or upload data in the background and requires more control over the transfer process, you can use background sessions. Background sessions allow your app to continue transferring data in the background, even if the app is suspended or terminated.

  4. Optimize your code: To minimize the amount of time your app spends in the background, you should optimize your code to execute your tasks as quickly and efficiently as possible. For example, you can use GCD (Grand Central Dispatch) to execute your tasks in the background and minimize the amount of CPU time your app uses.

Based on your specific use case, you can choose the appropriate background processing technique that best suits your app's needs. For example, if you need to perform location updates in the background, you can use the Core Location framework to receive location updates and upload them to Firebase using a background transfer service or a background session.

You can also use the following resources to learn more about background processing on iOS:

  1. Background Execution: https://developer.apple.com/documentation/backgroundtasks/background_execution
  2. Background Transfer Service: https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background
  3. Background Sessions: https://developer.apple.com/documentation/foundation/url_loading_system/uploading_data_in_the_background
  4. Core Location and Background Execution: https://developer.apple.com/documentation/corelocation/choosing_the_right_location_service_for_your_app/executing_location_updates_in_the_background
answered Mar 31, 2023 by Raji

Related Questions In Flutter

+1 vote
2 answers

flutter_background_service for iOS

If you're problem is solved then please ...READ MORE

answered Aug 18, 2023 in Flutter by Sneh
• 150 points
4,747 views
0 votes
1 answer
0 votes
1 answer

Run method on Widget build complete

You can use the WidgetsBindingObserver to be ...READ MORE

answered Mar 24, 2023 in Flutter by vijitha
725 views
0 votes
1 answer
0 votes
1 answer

Why is applicationWillTerminate not being called on the first launch of my app?

The applicationWillTerminate method is called by the ...READ MORE

answered Mar 18, 2023 in Android by vishalini
1,276 views
0 votes
1 answer

How can I change the app display name build with Flutter?

Yes, you can change the app display ...READ MORE

answered Mar 21, 2023 in Flutter by venky
1,849 views
0 votes
1 answer

3d Model In Flutter with GLB, OBJ, or GLTF file

To integrate a 3D model into Flutter ...READ MORE

answered Apr 13, 2023 in Flutter by pooja
1,213 views
0 votes
1 answer

Get User Group in Swift using AWS Cognito

The groups are exposed in the ID ...READ MORE

answered Nov 12, 2018 in AWS by Priyaj
• 58,090 points
1,317 views
0 votes
1 answer

Flutter plugin fails to build on iOS

It looks like the error is related ...READ MORE

answered Mar 31, 2023 in Flutter by chandru
1,193 views
0 votes
1 answer

Flutter TextField set textAlign for each line separately

By default, TextField widget aligns the text ...READ MORE

answered Apr 11, 2023 in Flutter by Tej
1,443 views
webinar REGISTER FOR FREE WEBINAR X
REGISTER NOW
webinar_success Thank you for registering Join Edureka Meetup community for 100+ Free Webinars each month JOIN MEETUP GROUP