This article relates to any version of Delphi (or at least it should work) that can target iOS 7 or greater. The demo project was created using Delphi 10.1 Berlin.
There’s been the odd post to the Embarcadero forums as well as on StackOverflow about how to implement background fetches on iOS. Partly because it’s not an every day problem, and partly because it involves a little “trickery” to make it work. In one such question on StackOverflow, the poster actually ended up solving the problem themselves. I figured that I might want to use the solution later, and in case it was doing more than was necessary, set out to investigate whether it was possible using a little less “jumping through hoops”.
Sadly, it appears the only method that does work is by using their solution, however I’ve repackaged it to allow it to become “cross-platform”. also in a way that the method of calling the completion handler is separated from the background fetching code, so that it might be used elsewhere. A more detailed explanation follows:
Background fetches are a method introduced into iOS 7, whereby an application can be in the background, and periodically iOS will call a method in the application that allows a period of up to 30 seconds in order to for example, retrieve some data from the internet.
In order for applications to be enabled for background fetch, the “fetch” option needs to be checked in the UIBackgroundModes key in the Version Info section in the project options:
The method that iOS calls is named performFetchWithCompletionHandler, and is supposed to be implemented by the application delegate.
Problem #1: in FMX, this method has not been added. Fortunately, there’s a way of adding missing methods to the application delegate, using the Objective-C runtime function: class_addmethod.
Problem #2: When performFetchWithCompletionHandler is called, it passes a reference to what is called an Objective-C “block”, in the handler parameter. The trick is to convert the “block” into a method reference. Fortunately, the Objective-C runtime also has a function: imp_implementationWithBlock, that takes the block as a parameter, and returns a method reference.
For problems #1 and #2, I’ve put together a unit (ObjCRuntimePlus in the demo) that takes all this detail and wraps it up into something (hopefully) re-usable.
Problem #3: When an iOS app has been configured for background fetch, a desired interval needs to be set, because the default is for iOS to “never” call the background fetch. This interval is set by the setMinimumBackgroundFetchInterval method on UIApplication. The problem is that this method is not declared on UIApplication in the iOSapi.UIKit unit. Fortunately (again), one solution is to redeclare UIApplication in the background fetch code (in the BackgroundFetch.iOS unit in the demo), with only the methods that are needed. Going by my online research, setMinimumBackgroundFetchInterval should be called when the FinishedLaunching application event is sent, however it is possible that it could be called later.
The end result is in the demo project that follows. I’ve implemented the background fetch as a platform service (makes use of TPlatformServices), where it’s simply a case of obtaining the service, setting the OnFetch handler, and providing an implementation for it.
In order to see it in action, run the application, put iOS into lock mode, and wait around 5 minutes (it could be longer, as it can vary). I’m leaving it up to readers to implement the actual fetch when OnFetch is called. Remember though, that the fetch is limited to a maximum of 30 seconds.