Geofencing stops working after 7-8 hours. It notifies only when I open the app

179 views Asked by At

I have implemented geofencing to detect the entry and exit from the region. It seems working fine when the app is in a foreground/background/terminated state initially. I am testing this functionality using GPX. When an app is terminated, I am getting entry exit notifications too. But I have observed that in many scenarios when an app is suspended or terminated for a longer period of time, Even though the user is entering and leaving the region, No notifications are triggered. When I open the app manually, I can see the entry,or exit notifications instantly.

Here is my code snippet.

class LocationService: NSObject, CLLocationManagerDelegate {
    
    static let sharedInstance: LocationService = { LocationService()
    }()
    
    var locationManager: CLLocationManager?
    var startLocation: CLLocation?
    var lastLocation: CLLocation?
    var delegate: LocationServiceDelegate?
    var isAuthorized: ((Bool) -> Void)?
    var boolSendUpdate = false
    var locationTimer = Timer()

    var isFirstTime:Bool!

    override init() {
       super.init()
        
        self.locationManager = CLLocationManager()
        guard let locationManager = self.locationManager else {
            return
        }
        //locationManager.desiredAccuracy = kCLLocationAccuracyBest // The accuracy of the location data
        locationManager.delegate = self
        locationManager.pausesLocationUpdatesAutomatically = false
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        locationManager.allowsBackgroundLocationUpdates = true//        if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self){
//            print("Available")
//        }
//
        NotificationCenter.default.addObserver(self, selector:#selector(startUpdatingLocation), name: UIApplication.didBecomeActiveNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector:#selector(stopUpdatingLocation), name: UIApplication.willTerminateNotification, object: nil)
    }
    
    func checkPermission(isAuthorized: ((Bool) -> Void)? = nil) {
        guard let locationManager = self.locationManager else {
            return
        }
        switch(CLLocationManager.authorizationStatus()) {
        case .authorizedAlways,.authorizedWhenInUse:
            self.startUpdatingLocation()
            isAuthorized?(true)
        // get the user location
        case .restricted, .denied:
            isAuthorized?(false)
            // redirect the users to settings
            popupAlert(title: NSLocalizedString("settings", comment: ""), message:go_to_settings, actionTitles: [NSLocalizedString("Cancel", comment: ""),NSLocalizedString("Settings", comment: "")], actions:[{action1 in
                
                },{action2 in
                    guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
                        return
                    }
                    if UIApplication.shared.canOpenURL(settingsUrl) {
                        UIApplication.shared.open(settingsUrl, completionHandler: { (success) in })
                    }
                }, nil])
        case .notDetermined:
            isAuthorized?(false)
            locationManager.requestWhenInUseAuthorization()
            
        @unknown default:
            isAuthorized?(false)
            locationManager.requestWhenInUseAuthorization()
        }
    }
    
    @objc func startUpdatingLocation() {
        self.locationManager?.startUpdatingLocation()
        self.locationManager?.requestAlwaysAuthorization()
    }
    
    @objc func stopUpdatingLocation() {
        if !CLLocationManager.significantLocationChangeMonitoringAvailable() {
           return
        }
        self.locationManager?.stopUpdatingLocation()
        self.locationManager?.startMonitoringSignificantLocationChanges()
    }
    
    func setUpGeofenceing(location:CLLocation,identifier:String = "",radius:CLLocationDistance,status:enumShiftStatus) {
        
        let geofenceRegionCenter = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
        let geofenceRegion = CLCircularRegion.init(center: geofenceRegionCenter, radius: radius, identifier: identifier)
        geofenceRegion.notifyOnExit = true
        geofenceRegion.notifyOnEntry = true
        
        if !CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
            print("Geofencing is not supported on this device!")
            UIApplication.shared.windows.first?.rootViewController?.presentAlert(withTitle:"MetroOne Officer", message: "Geofencing is not supported on this device!")
            return
        }
        if locationManager?.monitoredRegions.contains(geofenceRegion) == false {
            locationManager?.startMonitoring(for: geofenceRegion)
        }
       
    }
    
    func stopGeoFenceing(identifier: String = ""){

    }
    
    // CLLocationManagerDelegate
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        
        guard let delegate = self.delegate else {
            return
        }
        
        delegate.didChangeAuthorization(status: status)

    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else {
            return
        }
        // singleton for get last location
        self.lastLocation = location
        
        // use for real time update location
        updateLocation(currentLocation: location)
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        
        // do on error
        updateLocationDidFailWithError(error: error as NSError)
    }
    
    func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
        debugPrint("Started Monitoring for Region:::",region.description)
        guard #available(iOS 14, *) else {
            self.locationManager?.requestState(for:region)
            return
        }
    }
    
    func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
        debugPrint("error::\(error.localizedDescription)")
    }
    // Private function
    private func updateLocation(currentLocation: CLLocation){
        
        guard let delegate = self.delegate else {
            return
        }
        
        delegate.tracingLocation(currentLocation: currentLocation)
        
        
    }
    
    private func updateLocationDidFailWithError(error: NSError) {
        
        guard let delegate = self.delegate else {
            return
        }
        
        delegate.tracingLocationDidFailWithError(error: error)
    }
    
    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
       
        switch state {
            case .inside:
                postApiGeoFenceEntries(type: RegionType.In.rawValue, shiftStatus: enumShiftPostStatus.CheckIn.rawValue)
            case .outside:
                postApiGeoFenceEntries(type: RegionType.Out.rawValue, shiftStatus: enumShiftPostStatus.CheckOut.rawValue)
            case .unknown:
                print("Unknown")
            default:
                print("Default")
        }
    }
}

App delegate code snippet.

class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
        var window: UIWindow?
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch
            if launchOptions?[UIApplication.LaunchOptionsKey.location] != nil {
                _ = LocationService.sharedInstance
                UNUserNotificationCenter.current().delegate = self
            }
            return true
    }
}

I have also enabled location updates in capabilities. Please let me know if I am missing something.

Thank you.

0

There are 0 answers