EKEventStore Change Notifications Not Firing when app in Background - ios

I have registered for Calendar Change Notifications using the following:
- (void) registerForLocalCalendarChanges
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(localCalendarStoreChanged) name:EKEventStoreChangedNotification object:self.store ];
}
This should call the following when a change is made to the local calendar:
- (void) localCalendarStoreChanged
{
// This gets called when an event in store changes
// you have to go through the calendar to look for changes
// launch this in a thread of its own!
ashsysCalendarEventReporter *eventReport = [ashsysCalendarEventReporter new];
NSLog(#"Local Calendar Store Changed");
[NSThread detachNewThreadSelector:#selector(getCalendarEvents) toTarget:eventReport withObject:nil];
}
BUT...when I start the app, then send it to the background so I can change a calendar entry, nothing happens when I change the calendar entry. It DOES fire when I return to the app. But, of course that is not the objective.
store is defined in the header file with:
#property (strong,nonatomic) EKEventStore *store;
Update...forgot to show the stuff I have in the background fetch.
This is in didFinishLaunchingWithOptions
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
This is in the app delegate:
- (void) application:(UIApplication*) application performFetchWithCompletionHandler:(void (^) (UIBackgroundFetchResult))completionHandler
{
// UIBackgroundTaskIdentifier uploadCalInfo = [application beginBackgroundTaskWithExpirationHandler:nil];
NSLog(#"A fetch got called");
// ashsysCalendarEventReporter *eventReport = [ashsysCalendarEventReporter new];
// [eventReport getCalendarEvents];
// // [NSThread detachNewThreadSelector:#selector(getCalendarEvents) toTarget:eventReport withObject:nil];
// [application endBackgroundTask:uploadCalInfo];
completionHandler(UIBackgroundFetchResultNewData);
The performFetch gets called at what seem like random times some not at all related to the calendar. Is there a way to find out what is firing the background fetch? Is it always the calendar? The actual execution is commented out -- is it correct?
What am I missing?

I've been trying to find this answer out myself and I don't think there's an actual way to accomplish this. As per Apple's documentation, we're not allowed access to system resources while in a background state:
Stop using shared system resources before being suspended. Apps that interact with shared system resources such as the Address Book or calendar databases should stop using those resources before being suspended. Priority for such resources always goes to the foreground app. When your app is suspended, if it is found to be using a shared resource, the app is killed.
I'm still looking for a better answer/work around but would love to hear this from anyone else.

Related

how to set array of date to fireDate in local notification at a time

Actually in my app I'm starting more than two timers at different times. After certain time intervals I want notifications to fire. It's working fine when the app is on foreground but not in the background. How can I solve this?
Please help. Thanks!
You need to do following...
You need to turn on background mode.
In AppDelegate, Add this code to run app in background
Create a property
#property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTask;
and then do following...
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
DLOG(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
}];
if (self.backgroundTask == UIBackgroundTaskInvalid) {
DLOG(#"This application does not support background mode");
} else {
//if application supports background mode, we'll see this log.
DLOG(#"Application will continue to run in background");
}
}
I hope it will help you.
you can handle with both timer into this appdelgate method
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
when app going to background that time this method is called and your code still execute into this method, Hope this will help you.
Note : first enable background mode into Project Target -> Availability Tab -> Background Modes -> ON

How can I detect my app was launched for background fetch in didFinishLaunchingWithOptions method?

I want to check whether my app was launched for background fetch in my application delegate's didFinishLaunchingWithOptions. There is nothing in launchOptions dictionary. So is there any way to check it?
I know that I can check applicationState, but for some reason sometimes it returns UIApplicationStateBackground, even if I launch app normally.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (application.applicationState != UIApplicationStateBackground) {
// Analytics initialization code
}
}
I've created breakpoint at Analytics initialization code and sometimes it enters to this block even if I launch app normally!
I know that I can detect the state later when applicationDidBecomeActive or applicationDidEnterBackground will be called. If I will use these approach to detect the state I need to move my Analytics initialization code to some other place. If it remain in application:didFinishLaunchingWithOptions: it will be called every time when my app starts background fetch. So maybe I should just move Analytics initialization code to some other method and don't check applicationState in application:didFinishLaunchingWithOptions:? If so which method I can use for this?
Take a look at slides 19-21 of this presentation: http://www.slideshare.net/moliver816/background-fetch
Immediately upon launch, you can check if applicationState equals UIApplicationStateBackground in order to determine whether your app was launched into the background.
Otherwise, if you just want to know when your app is fetching data for background app refresh, you can do so inside the UIApplicationDelegate method application:performFetchWithCompletionHandler:.
You can wrap you analytics initialization code in a singleton using GCD dispatch once. That way you know it only runs one time per application load. Resume from background or any other states won't matter since the lifecycle is still continuous.
+ (Analytics*)sharedInstance
{
static dispatch_once_t onceToken;
static Analytics* sharedInstance;
dispatch_once(& onceToken, ^{
sharedInstance = [[self alloc] init];
//Do analytics initialization code here
});
return sharedInstance;
}
Try this one
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(AppIsInBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(AppIsActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
you have to call the selector : NSNotificationCenter is calling AppIsInBackground Selector (App in background)
- (void) AppIsInBackground:(NSNotification *) notification {
//Shut down the memory/processor intensive things and save any states for when the app is reinitialized
}
following is the delegate method which is called when the background fetch is performed by the iOS for our application.
This is a appDelegate method.
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
}

Stop location updates when app terminate

I'm developing an app which sends notifications when you are nearby of promoted places.
My problem is when I go to background and then I quit the app, I don't want the location services working when the app doesn't work (but I want them to work in background).
I saw only 3 apps which close the gps when the app is closed and I want to know how they did that, Facebook, Google Maps and Apple Maps, not Foursquare, not FieldTrips...
Thank you everybody.
you can add an observer for UIApplicationWillTerminateNotification where you start locationManager and than stop location updates
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
method to perform when you receive the notification
- (void)applicationWillTerminate:(NSNotification *)notification {
//stop location updates
}
I found the correct answer to my question becouse of #GuyS second post:
Adding that in your AppDelegate.m applicationDidEnterBackground
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:#selector(beginBackgroundTaskWithExpirationHandler:)]) {
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// Synchronize the cleanup call on the main thread in case
// the task actually finishes at around the same time.
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid)
{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
});
}];
}
}
And declaring that variable:
UIBackgroundTaskIdentifier bgTask;
After that you only have to stop your location services in applicationWillTerminate...
Thank you for your replies.
The solution provided by #GuyS in this topic should work. I'm getting the UIApplicationWillTerminateNotification in case the app is in background and then I close it by swiping up the snapshot. Please check whether you work correctly with NSNotificationCenter (especially adding and removing notification). Plus, please check the object you subscribed on the notification is alive when the app is in background.
Another similar solution is to place the code that disables GPS in appropriate UIApplicationDelegate callback in your AppDelegate method.
- (void)applicationWillTerminate:(UIApplication *)application {
//stop location updates
}

When retrieving data from the server in dispatch queue, how to handle application going to background?

I am creating an application where I am retrieving data from the server like below:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self retrievedatafromserver];
dispatch_async(dispatch_get_main_queue(), ^{
//UIUpdation, fetch the image/data from DB and update into your UI
});
});
How do I retrieve data from the server even if application goes to background?
Thanks & Regards
sumana
If Your scope of project is in only iOS 7 then you can use A new background mode which comes in the iOS 7 and onwards. You can fetch the data in background mode without any extra efforts of coding.
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
Now that your app already knows to initiate background fetch, let’s tell it what to do. The method -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler will assist in doing so. This method is called every time that a background fetch is performed, and should be included in the AppDelegate.m file. The complete version is provided below:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;
id topViewController = navigationController.topViewController;
if ([topViewController isKindOfClass:[ViewController class]]) {
[(ViewController*)topViewController insertNewObjectForFetchWithCompletionHandler:completionHandler];
} else {
NSLog(#"Not the right class %#.", [topViewController class]);
completionHandler(UIBackgroundFetchResultFailed);
}
}
Now in your controller. Do like that
- (void)insertNewObjectForFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"Update the tableview.");
self.numberOfnewPosts = [self getRandomNumberBetween:0 to:4];
NSLog(#"%d new fetched objects",self.numberOfnewPosts);
for(int i = 0; i < self.numberOfnewPosts; i++){
int addPost = [self getRandomNumberBetween:0 to:(int)([self.possibleTableData count]-1)];
[self insertObject:[self.possibleTableData objectAtIndex:addPost]];
}
/*
At the end of the fetch, invoke the completion handler.
*/
completionHandler(UIBackgroundFetchResultNewData);
}
Note :- If you have to give supportability on iOS 6 and below then avoid this approach. Because it's not available.
When your app enters background mode. you can access code for couple of seconds. Suppose the background queue is still performing and you entered background. then you might need to recall the method when app entered foreground. (take a bool variable and check whether the process is completed or not, if process is completed no issues. if not call the method again.).
If you want to make app run in background mode also then you need to request for background run mode in plist. See this link for reference only for these features we can active background run mode and you can active any of them according to you usage http://blogs.innovationm.com/support-for-applications-running-in-background-ios/

How to send a request to make API calls until a boolean is true

I'm really new to iOS and backend development so please bear with my lack of technical knowledge. I apologise for the potentially confusing title but here's my problem:
I'm trying to create an iOS app that allows the user to receive push notifications when the user's selected course's status is OPEN.
The way to check if a selected course status is OPEN is a GET request from my school's API, and a bit of parsing of the JSON response to extract the course status.
So how do I do this GET request constantly to check for the selected course's status, and send the user a push notification when it is OPEN?
It would be great if someone can point me towards a specific direction to research, thank you.
A push notification should come from a server somewhere. I think what you're looking for is a poll with a local notification if you want the app to be doing the work. The downside to this is the app has to be running for it to poll. I recommend watching this WWDC Session to learn more about how it works. To start the request doing the polling, you'd do something like this:
In your interface:
#property (nonatomic, retain) NSTimer *timer;
And in the implementation:
-(void)someMethodSomewhere
{
// Create a timer and automatically start it.
self.timer = [NSTimer scheduledTimerWithTimeInterval:10.0f // some number of seconds
target:self
selector:#selector(checkStatus)
userInfo:nil
repeats:YES];
}
-(void)checkStatus
{
// Perform request, check course status
if (/* course status is open */)
{
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.alertBody = #"The course is now open";
notification.fireDate = [NSDate date];
[[UIApplication sharedApplication]presentLocalNotificationNow:notification];
// Stop the timer
[self.timer invalidate];
}
}
Edit
To make it run in the background, you should probably read this document. The upshot is that you need to override the application:performFetchWithCompletionHandler: selector on your AppDelegate and from there call the checkStatus method from above. You can't, however, control how often this will get called. That's the job of the OS and to some degree the user's preferences. At the end of the processing, be sure to call the completion handler.
You must also set a minimum interval for fetching. In your app's application:didFinishLaunchingWithOptions:, you'll need to add something like this:
-(BOOL)application:(UIApplication*)app didFinishLaunchingWithOptions:
{
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
And assuming the code from above is also in the AppDelegate:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
[self checkStatus];
completionHandler(UIBackgroundFetchResultNewData);
}
You'll also have to set a property in your app's Info.plist file. You'll need to add the key UIBackgroundModes with the fetch value.

Resources