16 Replies
      Latest reply on May 29, 2020 4:33 AM by eskimo
      garrett35 Level 1 Level 1 (0 points)

        Hey there,

         

        I have an App which should do something in background.

         

        So I wrote some code in AppDelegate:

         

        func applicationDidEnterBackground(_ application: UIApplication) {
                print("BackgroundActivity in Delagate")
                    Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { timer in
                        //Do something
                        } else {
                            //Do something different
                        }
                    }
            }

         

        Now, every time if the application enter background I get this error in console:

        Can't end BackgroundTask: no background task exists with identifier 1 (0x1), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.

         

        I tried to fix it with using

        DispatchQueue.global(qos: .background).async {
                    self.BackgroundActivity()
                    DispatchQueue.main.async {
                        print("Hello")
                    }
                }

        in viewDidLoad() of the initial view controller to start the background task already if the application is in foreground. The tast does not work and when I go to background I get the same error.

         

        Anyone an idea what to do?

         

        Thanks a lot!

        • Re: Timer im background Task not possible?
          Claude31 Level 8 Level 8 (9,215 points)

          Timers are not made to work in background, except some specific case. See:

          https://stackoverflow.com/questions/42319172/swift-3-how-to-make-timer-work-in-background

          and

          h ttps://www.raywenderlich.com/5817-background-modes-tutorial-getting-started

            • Re: Timer im background Task not possible?
              eskimo Apple Staff Apple Staff (13,945 points)

              As Claude31 says, running timers in the background is tricky because, in general, the system will suspend your app shortly after it moves to the background, and once the app is suspended your timers won’t fire.  Which brings us to this:

              I have an App which should do something in background.

              Can you explain more about what you’re trying to do here?  Some things are perfectly feasible (for example, using the background task API to get extra time to log out of a server) but others are not (for example, running a timer every 5 minutes while your app is in the background).  If you can explain more about your high-level goal, we should be able to point you in the right direction.

              Share and Enjoy

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

              ps DTS is closed 21 Dec through 1 Jan.

                • Re: Timer im background Task not possible?
                  garrett35 Level 1 Level 1 (0 points)

                  Thanks for the answers.

                   

                  If the App is in background it should wait for 30 minutes and send a push notification

                  (don't ask why, but that's the intention).

                    • Re: Timer im background Task not possible?
                      eskimo Apple Staff Apple Staff (13,945 points)

                      If the App is in background it should wait for 30 minutes and send a push notification

                      A push notification?  Or a local notification?  If it’s a local notification, you can schedule that to be delivered at a specific time.  If it’s a push notification, where your app needs to reach out over the network to tell your push provider in generate the notification, you’re probably out of luck.  There’s no general-purpose way for an iOS app to resume itself in the background at an arbitrary time.

                      (don't ask why, but that's the intention).

                      To be clear, the more background info you can give me, the more likely it is that I’ll be able to help.

                      Share and Enjoy

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

                        • Re: Timer im background Task not possible?
                          garrett35 Level 1 Level 1 (0 points)

                          Sry for the late reply.

                           

                          Yes it's actually a local notification. There is no web service needed.

                           

                          The only thing the application wants to do in background, is to wait for 30 minutes and then send a notification.

                          If you tap on the notification the user should be navigated into the app and all other steps are inclued there.

                            • Re: Timer im background Task not possible?
                              eskimo Apple Staff Apple Staff (13,945 points)

                              The only thing the application wants to do in background, is to wait for 30 minutes and then send a notification.

                              That’s possible, but it doesn’t work the way you describe it.  Rather, you schedule a local notification for a specific time and then your app suspends.  The system will present the notification on your behalf at the scheduled time.  If the user taps the notification, it’ll resume (or relaunch) your app and tell it about that.

                              Check out the UserNotifications, and specifically the UNCalendarNotificationTrigger and UNTimeIntervalNotificationTrigger triggers.

                              Share and Enjoy

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

                                • Re: Timer im background Task not possible?
                                  garrett35 Level 1 Level 1 (0 points)

                                  Thank you. So do I need both notification triggers or is one enough? If there is a choice I would prefer the interval notification trigger. (Listening also shows what I want). Do I need to create a new class for this or can I use a specific function? Remember the trigger should starts if application enters background... Thanks again!

                                    • Re: Timer im background Task not possible?
                                      eskimo Apple Staff Apple Staff (13,945 points)

                                      So do I need both notification triggers or is one enough?

                                      Just one is fine.  I mentioned both because the correct one to use depends on your specific problem.

                                      Share and Enjoy

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

                                        • Re: Timer im background Task not possible?
                                          garrett35 Level 1 Level 1 (0 points)

                                          My current code is the following:

                                          //Asking for permissions
                                                  let center = UNUserNotificationCenter.current()
                                                  print("Authorizsation:")
                                                  center.requestAuthorization(options: [.alert, .sound]) { granted, error in
                                                      print("Error")
                                                  }
                                                  
                                                  //create the notification
                                                  let content = UNMutableNotificationContent()
                                                  content.title = "Hello"
                                                  content.body = "30 Sec are over"
                                                  
                                                  let trigger = UNTimeIntervalNotificationTrigger(timeInterval: (30), repeats: true)
                                                  
                                                  // Create the request
                                                  let uuidString = UUID().uuidString
                                                  let request = UNNotificationRequest(identifier: uuidString,
                                                              content: content, trigger: trigger)
                                          
                                                  // Schedule the request with the system.
                                                  //let notificationCenter = UNUserNotificationCenter.current()
                                                  center.add(request) { (error) in
                                                     if error != nil {
                                                        print("Error2: \(error)")
                                                     }
                                                  }
                                          

                                           

                                          Bad thing is that nothing happens...

                                          In console I can see:

                                          Authorizsation:

                                          Error

                                           

                                          For testing I implement it in an action of a button. In future it should starts automatically with viewDidLoad() or applicationDidEnterBackground() or (much better) a system function after the iPhone is booting.

                                           

                                          Do you have any further ideas?

                                            • Re: Timer im background Task not possible?
                                              eskimo Apple Staff Apple Staff (13,945 points)

                                              First thing first, you need work out why you’re not authorised.  If you step on line 5, what does error look like?

                                              Share and Enjoy

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

                                                • Re: Timer im background Task not possible?
                                                  garrett35 Level 1 Level 1 (0 points)

                                                  Error is "nil".  (Even though I allowed notifications first time)

                                                   

                                                  Additionally I get this error in the console as soon as my app is running:

                                                  invalid mode 'kCFRunLoopCommonModes' provided to CFRunLoopRunSpecific - break on _CFRunLoopError_RunCalledWithInvalidMode to debug. This message will only appear once per execution.

                                                   

                                                  If I quit the app with swipe from bottom to top (iPhone 11 Simulator) I get the error code like I get with the timer. So it seems like the trigger is not working correctly:

                                                  Can't end BackgroundTask: no background task exists with identifier 1 (0x1), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.

                                                   

                                                   

                                                  I tried the same code in a macOS App and there it works... very strange...

                                                    • Re: Timer im background Task not possible?
                                                      eskimo Apple Staff Apple Staff (13,945 points)

                                                      error is nil

                                                      In which case, granted is true, right?

                                                      Additionally I get this error in the console as soon as my app is running:

                                                      Someone is attempting to run the run loop in the common modes.  This is nonsense.  You can schedule a run loop source in the common modes, but you always have to run a run loop in a specific mode.

                                                      You should do what the message says, that is, set a symbolic breakpoint on _CFRunLoopError_RunCalledWithInvalidMode and then look at the backtrace to see who is doing this.

                                                      Share and Enjoy

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

                                    • Re: Timer im background Task not possible?
                                      hmap Level 1 Level 1 (0 points)

                                      Hello, I have the same problem. I'm creating an app for Interval Training (HIIT) and I need a Timer to continue running even if the user exists the app to go to another app. I've seen many apps doing exactly this ("IntervalTimer" or "HIIT & Tabata")  but I can't find the way to do it. Do you have any suggestion?