This document details how to add the background mode of fetch into the Titanium SDK. It is important to note that once these updates are performed you will be able to attach a listener to be called when the fetch background mode is triggered.
After the below updates are made, you can clear your Titanium project and run this sample app.js to view how it works.
The first step in adding the fetch background mode is to create the const values that will later be used when adding or listening to notification center.
To do this first open the TiBase.h file and add the const of
extern NSString * const kTiFetchBackground;
I did this on line 572 right below the kTiLocalNotification value
Then open the TiBase.m file and add the const of
NSString * const kTiFetchBackground = @"TiFetchBackground";
I did this on line 148 right below the kTiLocalNotification value
The next step in the process is to add the UIApplicationDelegate method performFetchWithCompletionHandler. We only need to add one method in this file, but it is an important one.To do this open the TiApp.m file and find the applicationWillEnterForeground method on 495. Under this method add the snippet below.
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
int64_t delayInSeconds = 29;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
completionHandler(UIBackgroundFetchResultNewData);
});
[[NSNotificationCenter defaultCenter] postNotificationName:kTiFetchBackground object:self];
}
What the above does is send a notification that the fetch method has been called. This will make a call over to the TiAppiOSProxy covered in the next step.
###IMPORTANT### You will notice that we create a 30 second "timer" after we post our notification. Since we don't have anyway to verify that the JavaScript event has been processed we assume it will take the max amount of time allowed by app (30 seconds). Once the timer has elapsed we call completionHandler(UIBackgroundFetchResultNewData).
The final step is to update TiAppiOSProxy.m.
This is really simple. First I add some const values for our properties and to be used in our methods.
int const TiFetchIntervalMin = 0;
int const TiFetchIntervalNever = -1;
Then I just update the _listenerAdded method to allow for the fetch event to be registered.
-(void)_listenerAdded:(NSString*)type count:(int)count
{
if (count == 1 && [type isEqual:@"notification"])
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:kTiLocalNotification object:nil];
}
if (count == 1 && [type isEqual:@"fetch"])
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveFetchNotification:)
name:kTiFetchBackground object:nil];
}
}
I then update _listenerRemoved to allow for the user to remove the fetch event.
-(void)_listenerRemoved:(NSString*)type count:(int)count
{
if (count == 0 && [type isEqual:@"notification"])
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiLocalNotification object:nil];
}
if (count == 0 && [type isEqual:@"fetch"])
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiFetchBackground object:nil];
}
}
Then you want to add the method that fires the listener as shown below.
-(void)didReceiveFetchNotification:(NSNotification*)note
{
[self fireEvent:@"fetch" withObject:nil];
}
We now can add the method that lets us set the interval. I used the same name as iOS does. You can pass in either one of the property values or a double check the method will then use to create a NSInterval with. To turn this off you pass in the BACKGROUND_FETCH_INTERVAL_NEVER property.
-(void)setMinimumBackgroundFetchInterval:(id)value
{
ENSURE_SINGLE_ARG(value, NSNumber);
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_0
if([value intValue] == TiFetchIntervalNever){
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalNever];
}else{
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:[value doubleValue]];
}
#endif
}
The very last update is to add the new properties as shown below.
MAKE_SYSTEM_PROP(BACKGROUND_FETCH_INTERVAL_MINIMUM,TiFetchIntervalMin);
MAKE_SYSTEM_PROP(BACKGROUND_FETCH_INTERVAL_NEVER,TiFetchIntervalNever);
Hey Ben this actually looks exactly what i would also do, to implement this feature. The only thing i would suggest is to conditionally compiling in the iOS7 code or using performselector:withArg: so that the compiler will not complain about the unkown methods if you try compiling the SDK from a older iOS version(i.e. anything lower that 7). Besides that this looks extremely good. Good job Ben. You can go ahead and make that minor change, and set up the PR for it.
NOTE: Do make the changes in master branch (3.2.0) and not on 3.1.2 as that it is already a released branch.