Silent notification to trigger location retrieval

Hi,

we work fo a company selling refrigeration apparatus around the region. In the guarantee, we offer fast repair times with traveling repairpersons.

So we are building an app to be used by the company repair servicepeople around the region. The company need to be able to know who is the serviceperson nearest to the faulty apparatus, and send them to fix the apapratus.


Every person has (will have) an iOS app and will agree to have Location Updates Always or When In Use, so this is not an issue. Once they will have launched the app once, and agreed to the locaiton policy, the app will stay sleeping most of the times, obviously.


Once the company receives a repair request, we plan to query every serviceperson and decide the nearest. SInce we don't want to be heavy on the battery requirement, we would like (ideally) to query the location only when needed.

Our idea was to send a silent push notification when needed, then the app will awake in background, get a location fix, and call a backend server sending the position. After some seconds we expect to have most o f the locations on DB and we could start deciding which serviceperson to alert, with a proper notification on the app.


We have set up a basic app in XCode 9beta6 and iOS 11 beta (we work for the next release obiously since the app will go live after iOS11 release) that seems to work, but.. but actually only works when connected to XCode.


We have put all the relevant plist and entitlements, but as soon as we disconnect the device from XCode (unpliug the cable) we don't seem to receive any notification (or maybe we receive it but no data is written to our server?).


Silent push notifications are like this:

{"aps":{ "content-available":1}}



Then our app delegate

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
      
     
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
            (granted, error) in
        }
     
        application.registerForRemoteNotifications()
    
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
        locationManager.requestAlwaysAuthorization()
    
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.startUpdatingLocation()
    
        return true
    }


   func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
     
        let bgTask = bgManager()
        bgTask.registerBackgroundTask()

        locationManager.requestLocation()
     
        let delayInSeconds = 18.0
        DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {
            print("locationManager.updated")
            bgTask.endBackgroundTask()
            completionHandler(.newData)
        }



func locationManager(_ manager: CLLocationManager,
                         didUpdateLocations locations: [CLLocation])
    {
        print("DidUpdateLocation ",locations)
        
      
        locationManager.stopUpdatingLocation()
       
        let todoEndpoint: String = "http://......./apiserver to store coordinates"
        guard let url = URL(string: todoEndpoint) else {
            print("Error: cannot create URL")
            return
        }
        let urlRequest = URLRequest(url: url)
        let session = URLSession.shared
        let task = session.dataTask(with: urlRequest) { (data, urlResponse, error) in
            /
            if(data != nil){
                print("data Returned JSON ",data as Any, data?.hexEncodedString() as Any)
                if let returnData = String(data: data!, encoding: .utf8) {
                    print("JSON:", returnData)
                    DispatchQueue.main.async {
                        self.logDelegate?.logMessage("HTTP call made and Json received OK")
                    }
                  
                } else {
                    print(" not converted")
                }
            }
        }
        task.resume()
    }



The BGManager it's a simple class, found Googlgin on SO, to simulate a background task, hopefully allowing iOS to get a fix for the location. We have added it hoping it would improve things

class bgManager:NSObject{
    var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
    override init(){
        super.init()
    }
    func registerBackgroundTask() {
        backgroundTask = UIApplication.shared.beginBackgroundTask {
            [unowned self] in
            self.endBackgroundTask()
        }
    }
   
    func endBackgroundTask() {
        UIApplication.shared.endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
        print("End bg task")
    }
}



Anyway, any idea why it does not seem to work when we deploy and use the device off XCode? or it if deoes work it is random?

Thanks

Z

Replies

Hi,


just an update: I've added some file-based logging and I've discovered that indeed, even when off XCode, my app receives Silent Notifications and updates the location. Simply it is not synchronous: sometimes notifications got lost, other times they arrived kinda 10 minutes later..


Since I am using a testing sandbox, obviously, I thought that there was no throttling, but indeed it seems the case as specified here


"Silent notifications are not meant as a way to keep your app awake in the background, nor are they meant for high priority updates. APNs treats silent notifications as low priority and may throttle their delivery altogether if the total number becomes excessive. The actual limits are dynamic and can change based on conditions, but try not to send more than a few notifications per hour."


https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html


Maybe that's the source of the problem I've noticed.


Z

Maybe you are running in a bug that currently affects iOS 11 Betas, see http://openradar.appspot.com/34139840 or https://stackoverflow.com/questions/44796613/silent-pushes-not-delivered-to-the-app-on-ios-11


I would test it with iOS 10 and Xcode 8

Hi, I have the same problem of my project, may I know have you solving this? and how?