Objective-C: App with a reminder that will work even when app is killed or phone is restarted

228 Views Asked by At

At the following code, I managed to trigger my checkSchedule method every 15secs(for testing purposes), checkSchedule will send an API and then check if there is any appointments. If there is a result detected by connectionFinishLoading, it will notify the user.

The current code will work if the app is in the foreground or background.

However, I wish to get it to work when the app is killed or the phone is restarted and the app is not launched. Basically, the function is something like the Any.do app (A reminder App), the reminder will trigger even when the app is killed or the phone restarted. Any pointers or help is gladly appreciated.

@AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [self startTimerLoop];

    return YES;
}

//==== This loop will run every hour and call Check Schedule,
//==== It will break the 3 min barrier
-(void)startTimerLoop{
    //NSLog(@"Hi I am in the timer .. %@ ", [NSDate date]);
    [objTimer invalidate];
    objTimer = nil;

    //===repeat every 15 secs for testing purposes
    bgTask = UIBackgroundTaskInvalid;
    UIApplication *app = [UIApplication sharedApplication];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{}];
    objTimer = [NSTimer scheduledTimerWithTimeInterval:15 target:self   selector:@selector(checkSchedule) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:objTimer forMode:UITrackingRunLoopMode];

}

//=== Check from 2 hours from now if there is any classes
//=== it will send and web API and is it return a result,
//=== it will notify the user
-(void)checkSchedule{

    //=== Initialize the responseData Mutable Data
    self.responseData = [NSMutableData data];

    //=== Call the stored txtMemCode, something like session ---
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *sMemCode = [defaults objectForKey:@"txtMemCode"];

    NSDate *now = [NSDate date];
    NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
    [outputFormatter setDateFormat:@"HH:mm"];
    NSString *sTime = [outputFormatter stringFromDate:now];
    sTime = [sTime stringByReplacingOccurrencesOfString:@":" withString:@"%3A"];
    //====Check from 2 hours from now====
    NSTimeInterval secInTwoHours = 2*60*60; //=== sec in 2 hours
    NSDate *twoHoursAhead = [now dateByAddingTimeInterval:secInTwoHours];
    NSString *sTime2Hours = [outputFormatter stringFromDate:twoHoursAhead];
    sTime2Hours = [sTime2Hours stringByReplacingOccurrencesOfString:@":" withString:@"%3A"];

    if (sMemCode != nil) {
        //=== Pass the string to web and get the return State response.write
        sURL = gURL;
        sURL = [sURL stringByAppendingString:@"/apps/checkBooking.asp?"];
        sURL = [sURL stringByAppendingString:@"memCode="];
        sURL = [sURL stringByAppendingString:sMemCode];
        sURL = [sURL stringByAppendingString:@"&tocheck="];
        sURL = [sURL stringByAppendingString:sTime];
        sURL = [sURL stringByAppendingString:@"&tocheck2="];
        sURL = [sURL stringByAppendingString:sTime2Hours];

        NSLog(@" The sURL : %@ ", sURL);

        NSURLRequest *requestState = [NSURLRequest requestWithURL:[NSURL URLWithString:sURL]];

        (void) [[NSURLConnection alloc] initWithRequest:requestState delegate:self];
    }
}

//=== This getting the return results from the called API.
//=== If there is a result, it will notify the user.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"connectionDidFinishLoading");
    NSLog(@"=========Succeeded! Received %d bytes of data",[self.responseData length]);

    NSString *sResponseData = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
    NSLog(@"=======*************** This Response.write stuff %@", sResponseData);

    NSString *sSeparator= @"|";

    NSRange range = [sResponseData rangeOfString:sSeparator];
    NSInteger position = range.location + range.length;
    NSString *sRecords = [sResponseData substringToIndex:position-1];
    NSString *sRemaining = [sResponseData substringFromIndex:position];

    if ([sRecords isEqualToString:@"0"]){
        NSLog(@" There is no classes ");
    }else {
        range = [sRemaining rangeOfString:sSeparator];
        position = range.location + range.length;
        NSString *sMessage = [sRemaining substringToIndex:position-1];
        NSString *sTime = [sRemaining substringFromIndex:position];

        NSString *sBody = sMessage;
        sBody = [sBody stringByAppendingString:@" "];
        sBody = [sBody stringByAppendingString:sTime];

        UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];

        content.title = [NSString localizedUserNotificationStringForKey:@"Class Reminder!"
                                                          arguments:nil];

        content.body = [NSString localizedUserNotificationStringForKey:sBody
                                                         arguments:nil];
        content.sound = [UNNotificationSound defaultSound];

        UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];

        UNNotificationRequest *notificationRequest = [UNNotificationRequest requestWithIdentifier:@"NotificationIdentifier" content:content trigger:trigger];

        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center addNotificationRequest:notificationRequest
             withCompletionHandler:^(NSError * _Nullable error) {
                 NSLog(@"completed!");
         }];
    }

    [[UIApplication sharedApplication] endIgnoringInteractionEvents];

}
1

There are 1 best solutions below

0
On BEST ANSWER

Must follow the instruction at Firebase to set up remote notification.

// Handle incoming notification messages while app is in the foreground.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
   willPresentNotification:(UNNotification *)notification
     withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
// Print message ID.
NSDictionary *userInfo = notification.request.content.userInfo;
if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"**3 :  Message ID: %@", userInfo[kGCMMessageIDKey]);
}

// Print full message.
NSLog(@" **4 : %@", userInfo);

//==== This will show the notification while APP is in the foreground
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
//completionHandler(UNNotificationPresentationOptionNone);

}