3 Replies
      Latest reply on Apr 16, 2020 1:55 PM by eskimo
      mokhosla Level 1 Level 1 (0 points)

        Hi, I'm trying to schedule a background task to fetch a system parameter value at regular intervals. I've created a dummy iOS app using Xcode for the same and am making use of the new Background tasks framework to accomplish this.

         

        I've selected the 'Background fetch' and 'Background processing' checkboxes at the Capabilities sections, and defined two new tasks in the 'Permitted background task scheduler identifiers' entry in the Info.plist file. I've added the following code into AppDelegate class to schedule the background tasks and get it triggered when my app is in the background:

         

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

                BGTaskScheduler.shared.register(

                forTaskWithIdentifier: "com.mokhosla.fetchBrightness", using: nil) { task in

                    self.handleAppRefreshTask(task: task as! BGAppRefreshTask)

                }

                return true

            }

          

            func handleAppRefreshTask(task: BGAppRefreshTask) {

                scheduleBackgroundBrightnessFetch()

                let brightnessOperation = BrightnessOperation(brightness: UIScreen.main.brightness.description)

                task.expirationHandler = {

                    brightnessOperation.cancel()

                }

                brightnessOperation.completionBlock = {

                    task.setTaskCompleted(success: !brightnessOperation.isCancelled)

                }

                let operationQueue = OperationQueue()

                operationQueue.addOperation(brightnessOperation)

            }

          

            func scheduleBackgroundBrightnessFetch() {

                let taskRequest = BGAppRefreshTaskRequest(identifier: "com.mokhosla.fetchBrightness")

                taskRequest.earliestBeginDate = Date(timeIntervalSinceNow: 10)

                do {

                    try BGTaskScheduler.shared.submit(taskRequest)

                } catch {

                    print("error: \(error.localizedDescription)")

                }

            }

         

        Upon building the app and then moving it in the background, I find that the OS never trigggers the background task. I've gone through a few other threads on this forum and find other developers facing the same issue. Is there something wrong I'm doing there? Is this not the expected way to use BGTasksScheduler? Kindly help me understand what I'm doing wrong here. Thanks in advance!

        • Re: Background tasks scheduled using BGTaskScheduler not getting triggered
          eskimo Apple Staff Apple Staff (13,905 points)

          I'm trying to schedule a background task to fetch a system parameter value at regular intervals.

          It’s unlikely that an app refresh task will meet your needs here.  App refresh tasks are not a way to get regular execution time.  Rather, the intended use case centres around user activity.  The system observes the user’s behaviour and recognises that they interact with the app regularly.  It then starts running the app’s app refresh tasks so that the app can update its UI proactively, meaning:

          • The user is more likely to see up-to-date info in the multitasking UI.

          • The user doesn’t have to wait for the app to refresh the next time they bring it to the the front.

          So, unless you have an app that the user is checking regularly, an app refresh task won’t help you.  It’s unlikely that the system will ever decide to run your task and, even if it does, that commitment will fade away over time.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: Background tasks scheduled using BGTaskScheduler not getting triggered
              Siarhei Level 1 Level 1 (0 points)

              Thank you for the explanation eskimo,

              What about the "previous" iOS 12 approach ? I have created in Xcode 11 sample, trivial project which read/write from/to UserDefaults number of times performFetch is called.

              My point of using background fetch is for checking status of user's activation.

              When I debug the app it works smoothly. (i.e. Simulate Background Fetch in Xcode, or Options -> Launch Due to a background Fetch event).

              But It is not called on the real devices: iPhone 6, iOS 12.4, iPhone XS iOS 13.3.1

              here is the link:

              https://www.dropbox.com/s/gk63h6qmnxgeqg1/FetchTest.zip?dl=0

               

              The code is trivial, i've added "Required background modes in Info.plist, no luck .

              I tried running Debug & Release version it didn't work.

              Below is an excerpt from AppDelegate:

              func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      // Override point for customization after application launch.
                      print("!!! Did finish launching count \(getCount())")
                      application.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
                      return true
                  }
                 
                  func getCount() -> Int {
                      let def = UserDefaults.standard
                      let count = def.value(forKey: "count") as? Int ?? 0
                      return count
                  }
                 
                  func increaseCount() -> Int {
                      let def = UserDefaults.standard
                      let count = getCount()
                      def.set(count + 1, forKey: "count")
                      def.synchronize()
                      return count + 1
                  }
                 
                  func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
                      print("!!! New count \(increaseCount())")
                      completionHandler(.newData)
                  }

              Moreover, I took WWDC Background task sample code: and added there the same trivial logic count increment ( increaseCount ) logic. The code is here:

               

              https://www.dropbox.com/s/2lu7rz1lett2pzz/RefreshingAndMaintainingYourAppUsingBackgroundTasks.zip?dl=0

               

              But it doesn't work, I was opening the page with count, for a couple of times, so the system could find out, or study that I use the app, also connected the phone to the charger, but BG task doens't run. I even don't close the app, just move it into background.

              On Settings for the apps bg mode is enabled.

              It just doesn't work.

                • Re: Background tasks scheduled using BGTaskScheduler not getting triggered
                  eskimo Apple Staff Apple Staff (13,905 points)

                  I don’t have time to look at your whole post right now but this part is easy:

                  What about the "previous" iOS 12 approach?

                  The previous background fetch mechanism has the same ‘guarantees’ as BackgroundTasks framework, that is, none at all.  If you search through old DevForums posts, you’ll find many complaints along similar lines.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"