Home/Code tips, Patches/Performing background fetches on iOS

Performing background fetches on iOS

Views:
218

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:

ProjectOptionsVersionInfoUIBackgroundModesFetch

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.

By | 2017-02-16T18:02:35+00:00 June 18, 2016 5:46 pm|Code tips, Patches|5 Comments

About the Author:

5 Comments

  1. acarlomagno June 21, 2016 at 11:56 pm - Reply

    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

    • admin June 22, 2016 at 7:44 am - Reply

      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.

  2. Steven Chesser October 31, 2016 at 12:02 pm - Reply

    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.

    • admin October 31, 2016 at 1:35 pm - Reply

      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.

      • Steven Chesser November 1, 2016 at 3:48 am - Reply

        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.

Leave a Reply

Show Buttons
Hide Buttons