简体   繁体   中英

How to prevent iOS app from being suspended

I have an iOS app that needs to track user's geolocation for a research project. However, the app gets automatically suspended by the iOS after a few hours and the geolocation tracking stops working.

Geofencing is not sufficient for my case as it's not accurate enough.

Is there any way to can prevent the app from getting suspended (unless user manually terminate it)?

One way I thought of is to play a silent music indefinitely, and display the music controls on lockscreen through MPRemoteCommandCenter , like how Spotify works.

Would that keep the app alive? (as I believe Spotify never gets killed unless user manually terminate it?)

I have similar app which uses user location for tracking. Check if you have all these permissions in info.plist. And specifically tell users why you are using location permissions

<key>NSLocationAlwaysUsageDescription</key>
<string>Application needs permission to access your current location. 
</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Application needs permission to access your current location. 
</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>

Here is a part of my code. I have removed the unwanted part so you might have to edit while using it.

import GooglePlaces
import GoogleMaps



class StartRideViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate{

var mapView: GMSMapView!
var locationManager = CLLocationManager()

override func viewDidLoad() {
    super.viewDidLoad()

let notificationCenter = NotificationCenter.default
    notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)
    notificationCenter.addObserver(self, selector: #selector(appMovedToForeGround), name: Notification.Name.UIApplicationDidBecomeActive, object: nil)

}


@objc func appMovedToBackground() {
    print("App moved to background!")
    print(isStartRide)
    if isStartRide == false{
        btn_Share.isHidden = true
        locationManager.allowsBackgroundLocationUpdates = false
        locationManager.stopUpdatingLocation()
    }
}

@objc func appMovedToForeGround() {
    //getMeRidersData()
}

func initiateLocation(){
locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        locationManager.distanceFilter = 1
        locationManager.startUpdatingLocation()
        //locationManager.startUpdatingHeading()
        locationManager.allowsBackgroundLocationUpdates = true

        //checkForLocationServices()
        checkLocationAuthorizationStatus()

guard let myLatitude = locationManager.location?.coordinate.latitude else{
        return
    }
    guard let myLongitude = locationManager.location?.coordinate.longitude 
else{
        return
    }


    showMap(myLatitude:myLatitude, myLongitude:myLongitude)

}
func showMap(myLatitude:Double, myLongitude:Double){
    let camera = GMSCameraPosition.camera(withLatitude: myLatitude, 
longitude: myLongitude, zoom: 17)
    mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
    //mapView = GMSMapView.map(withFrame: CGRect(x: 0, y: 0, width: 
self.view.frame.width, height: self.view.frame.height - 250), camera: camera)

    mapView?.center = self.view.center
    self.view.addSubview(mapView!)

    mapView.padding = UIEdgeInsetsMake(150, 0, 80, 0)
    mapView.settings.myLocationButton = true
    mapView.delegate = self
    //mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    mapView.isMyLocationEnabled = true
    frameForMapView.addSubview(mapView)

}

func checkLocationAuthorizationStatus() {
    let status = CLLocationManager.authorizationStatus()
    if status == CLAuthorizationStatus.notDetermined{
        print("NotDetermined")
        locationManager.requestWhenInUseAuthorization()
        CLLocationManager.locationServicesEnabled()
        locationManager.requestLocation()
    }else {
        print("Problem with authorization")
    }
}


// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location: CLLocation = locations.last!
    print("Location: \(location)")
    moveMyImageOnMap()
    print(isStartRide, gotCounterFromLastRide , counter)
    if isStartRide && gotCounterFromLastRide{
        updateMyLocationToDataBase()
    }
}

//    func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
//        print(newHeading)
//    }

// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    switch status {
    case .restricted:
        print("Location access was restricted.")
    case .denied:
        print("User denied access to location.")
        // Display the map using the default location.
    case .notDetermined:
        print("Location status not determined.")
    case .authorizedAlways: fallthrough
    case .authorizedWhenInUse:
        print("Location status is OK.")
        if mapView != nil {
            mapView.isMyLocationEnabled = true
        }

    }
}

// Handle location manager errors.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    locationManager.stopUpdatingLocation()
    print("Error: \(error)")

    let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String

    let msg :String = "You have denied the app to access your location. Please enable the location services in your settings for the app to get the location";
    let alertController = UIAlertController(title: "Allow \(appName) to access your location while you are using the app?", message: msg, preferredStyle: .alert)
    let cancelAction = UIAlertAction(title: "CANCEL", style: UIAlertActionStyle.default, handler: nil)

    let settingsAction = UIAlertAction(title: "SETTINGS", style: .default) { (_) -> Void in
        guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
            return
        }

        if UIApplication.shared.canOpenURL(settingsUrl) {
            UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                print("Settings opened: \(success)") // Prints true
            })
        }
    }


    alertController.addAction(cancelAction)
    alertController.addAction(settingsAction)

    self.present(alertController, animated: true, completion: nil)
}


}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM