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.
Hello,
I saw that you are expert about background questions.
About “beacons” can you help me about listen the beacons when the app is in background mode ?
I have tried in some mode … but nothing.
Have you tried ?
regards
Antonello
I haven’t done any Beacon programming as yet, however from what I can work out from here:
http://developer.radiusnetworks.com/2013/11/13/ibeacon-monitoring-in-the-background-and-foreground.html
there needs (at least) to be a call to setNotifyEntryStateOnDisplay on the region for the beacon(s) in question, which the Delphi code does not do. I expect the TiOSBeaconManager.DoStartScan method in the System.IOS.Beacon unit would need to be modified to do just that, i.e. LBeaconIdentifier.GetRegion.setNotifyEntryStateOnDisplay(True), before the FLocationManager.startMonitoringForRegion call.
Going by the article, it appears the app would respond only when the phone is not in lock mode, however. I may some day want to do some work with Beacons myself, however at this point I can only guess.
Downloaded and ran this in 10.1 Update 1 … But nothing happens when app in background.
Let it run for 10 minutes and it seemed the FetchHandler never triggers.
Latest OS9 on my iPhone5 device.
It can be longer than 10 minutes; there’s no way to predict how long before it is called.
If you put the device into “lock” mode (i.e. press the power button to make the screen go black) however, it seems to fire at least once within 5-6 mins.
Yah that is what I ended up reading about, no way to predict. But it seems to be all over the place.
Sometimes its 10 minutes…. other times over an hour. Or sometimes not at all it seems. Basically unusable sadly in my case.
This is where Push Notifications would be nice but I’ve struggled on that as every customer of mine has their own servers and own devices. And I need their servers to push something to individual employees of theirs that there is “work to do” .. this was my half way attempt to do so if the app is running in background, to pool from the server. Which works, but i need it to run more often. But even then finding information about doing these push notifaction like needed has proven difficult, and the answer I get usually is just pool it in the background… 🙁 I need to find good methods of doing this for iOS and Android …
Waiting an hour or more is out of the question with this solution sadly. People need live or close to live updates when the app isn’t running and/or in the foreground.
Hello,
I know it is over a year since you posted this but I tried the Demo with Tokyo and it doesn’t work. 🙁
It runs, but when in background it never performs a fetch. I left it for 18 hours and it didn’t do anything. Is this still the best way to perform a fetch in the background or things have progressed?
Interesting that you’ve commented now, because I have been revisiting this very subject the last day or so. In the next day or so, I’ll be testing a rework of this functionality, so I’ll either reply here, or be posting a new article.
I’ve been trying to do it since yesterday and I have not been able to either. I need a lot of this, is there any way I can do something to ring an alarm at a specific time or make the app open alone at the chosen time, but even by turning the phone off and on?
Hi Dave, first of all I would like to thank you for the immense help you have given to the Delphi community, it is invaluable in your tutorials.
I would like to know if it is compatible with Delphi Rio 10.3.1, I did some tests but without success, the fetch is not triggered, even after 24 hours.
Thankful.
Hi Paulo, I’ll have a look at it in the next day or so, thanks!
Hi Dave, thanks.
Me too hope that u can take a look to this example code. I Work too with Delphi Rio 10.3.1,
I tried to do another test, using a notification, but to no avail. I saw this idea in stackoverflow, upon receiving a notification the ios app triggers fetchevent.
but in my case this did not work either.
I have tried, in vain, to make background fetch work over the last day or so. From a bit of research I note that others are having the same problem (using Swift or Objective-C). Background fetch seems notorious for not being able to provide what developers want.
You may be better off using location updates, however that can also be restrictive, especially if the user decides to turn off the “always” option, or remains stationary for extended periods.
> I tried to do another test, using a notification, but to no avail
Are you referring to silent push notifications? I’ve had some experience attempting to make that work, however this is also restrictive – the OS can decide not to do anything with the message. Non-silent push notifications should work (though depending on how often you send them, it may become annoying to the user) – I may take a look into doing a demo for that
Hi Dave, I tried with non-silent notifications, it also did not work, the fetch is not triggered.
The location updates I tested and worked, I hope the internet connection stays active.
Thank you very much.
Hi Dave, I tried with non-silent notifications, it also did not work, the fetch is not triggered.
The Location updates I tested and worked, I hope the internet connection stays active.
Thank you very much.
Hi again Dave, background location did not work either, I do not know if I’m doing something wrong.
I wonder if your example
of this link:
http://delphiworlds.com/2016/02/location-sensor-work-in-the-background-on-ios-9/
is applicable to delphi 10.3.1
or is some other adaptation necessary?
Thankful.
Hi Dave, it worked with your location background example,
Both location updates, as well as internet connectivity, can replace fetch mode smoothly.
I just made an adjustment so that it can work with the lctsmall parameter.
I added this call to function dostart
FLocater.setPausesLocationUpdatesAutomatically (False);
According to Apple documentation, when this parameter is true, IOS automatically disables GPS in the absence of motion, and is only reactivated when the application comes to the foreground.
Thank you very much.
Great to hear! I had been planning on revisiting that, so it is good to know it is working for you