Parcourir la source

Rewritten iOS

Sebastián Katzer il y a 11 ans
Parent
commit
eb4f357d0f

+ 2 - 2
CHANGELOG.md

@@ -1,14 +1,14 @@
 ## ChangeLog
 #### Version 0.8.0 (not yet released)
 - [feature:] New method `hasPermission` to ask if the user has granted to display local notifications.
-- [feature:] New method `promptForPermission` to promt the user to grant permission to display local notifications.
+- [feature:] New method `registerPermission` to register permission to display local notifications.
 - [feature:] New Android specific `led:` flag.
 - [feature:] Add `isTriggered` & `getTriggeredIds` methods.
+- [enhancement:] iOS8 support.
 - [enhancement:] Android 2.x (SDK >= 7) support (Thanks to **khizarsonu**)
 - [enhancement:] Scope parameter for `isScheduled` and `getScheduledIds`
 - [enhancement:] Callbacks for `add`, `cancel` & `cancelAll`
 - [enhancement:] `image:` accepts remote URLs and local URIs (Android)
-- [enhancement:] __iOS8 Support__
 
 #### Version 0.7.4 (22.03.2014)
 - [bugfix:] Platform specific properties were ignored.

+ 8 - 8
README.md

@@ -19,7 +19,7 @@ The purpose of the plugin is to create an platform independent javascript interf
 
 
 ## Supported Platforms
-- **iOS**<br>
+- **iOS** _(up to iOS8)_<br>
 See [Local and Push Notification Programming Guide][ios_notification_guide] for detailed informations and screenshots.
 
 - **Android** *(SDK >=7)*<br>
@@ -71,14 +71,14 @@ More informations can be found [here][PGB_plugin].
 ## ChangeLog
 #### Version 0.8.0 (not yet released)
 - [feature:] New method `hasPermission` to ask if the user has granted to display local notifications.
-- [feature:] New method `promptForPermission` to promt the user to grant permission to display local notifications.
+- [feature:] New method `registerPermission` to register permission to display local notifications.
 - [feature:] New Android specific `led:` flag.
 - [feature:] Add `isTriggered` & `getTriggeredIds` methods.
+- [enhancement:] iOS8 support.
 - [enhancement:] Android 2.x (SDK >= 7) support (Thanks to **khizarsonu**)
 - [enhancement:] Scope parameter for `isScheduled` and `getScheduledIds`
 - [enhancement:] Callbacks for `add`, `cancel` & `cancelAll`
 - [enhancement:] `image:` accepts remote URLs and local URIs (Android)
-- [enhancement:] __iOS8 Support__
 
 #### Further informations
 - See [CHANGELOG.md][changelog] to get the full changelog for the plugin.
@@ -89,7 +89,7 @@ More informations can be found [here][PGB_plugin].
 The plugin creates the object ```window.plugin.notification.local``` with the following methods:
 
 1. [notification.local.hasPermission][has_permission]
-2. [notification.local.promptForPermission][prompt_for_permission]
+2. [notification.local.registerPermission][register_permission]
 3. [notification.local.add][add]
 4. [notification.local.cancel][cancel]
 5. [notification.local.cancelAll][cancelall]
@@ -125,15 +125,15 @@ window.plugin.notification.local.hasPermission(function (granted) {
 });
 ```
 
-### Prompt the user to grant permission for local notifications
-The user can be prompted to grant the required permission through the `notification.local.promptForPermission` interface.
+### Register permission for local notifications
+Required permissions can be registered through the `notification.local.registerPermission` interface.
 
 #### Further informations
 - The method is supported on each platform, however its only relevant for iOS8 and above.
 - The user will only get a prompt dialog for the first time. Later its only possible to change the setting via the notification center.
 
 ```javascript
-window.plugin.notification.local.promptForPermission();
+window.plugin.notification.local.registerPermission();
 ```
 
 ### Schedule local notifications
@@ -563,7 +563,7 @@ This software is released under the [Apache 2.0 License][apache2_license].
 [ontrigger]: #get-notified-when-a-local-notification-has-been-triggered
 [platform-specific-properties]: #platform-specifics
 [has_permission]: #determine-if-the-app-does-have-the-permission-to-show-local-notifications
-[prompt_for_permission]: #prompt-the-user-to-grant-permission-for-local-notifications
+[register_permission]: #register-permission-for-local-notifications
 [add]: #schedule-local-notifications
 [cancel]: #cancel-scheduled-local-notifications
 [cancelall]: #cancel-all-scheduled-local-notifications

+ 9 - 0
plugin.xml

@@ -35,6 +35,15 @@
 
         <header-file src="src/ios/APPLocalNotification.h" />
         <source-file src="src/ios/APPLocalNotification.m" />
+
+        <header-file src="src/ios/APPLocalNotificationOptions.h" />
+        <source-file src="src/ios/APPLocalNotificationOptions.m" />
+
+        <source-file src="src/ios/UIApplication+APPLocalNotification.h" />
+        <source-file src="src/ios/UIApplication+APPLocalNotification.m" />
+
+        <header-file src="src/ios/UILocalNotification+APPLocalNotification.h" />
+        <source-file src="src/ios/UILocalNotification+APPLocalNotification.m" />
     </platform>
 
     <!-- android -->

+ 2 - 2
src/ios/APPLocalNotification.h

@@ -38,7 +38,7 @@
 - (void) getScheduledIds:(CDVInvokedUrlCommand*)command;
 // Informs if the app has the permission to show notifications
 - (void) hasPermission:(CDVInvokedUrlCommand*)command;
-// Ask for permission to show notifications
-- (void) promptForPermission:(CDVInvokedUrlCommand*)command;
+// Registers permission to show notifications
+- (void) registerPermission:(CDVInvokedUrlCommand*)command;
 
 @end

+ 170 - 412
src/ios/APPLocalNotification.m

@@ -20,12 +20,14 @@
  */
 
 #import "APPLocalNotification.h"
+#import "APPLocalNotificationOptions.h"
+#import "UIApplication+APPLocalNotification.h"
+#import "UILocalNotification+APPLocalNotification.h"
+
 #import <Availability.h>
 
 @interface APPLocalNotification ()
 
-// Retrieves all scheduled notifications
-@property (readonly, getter=scheduledNotifications) NSArray* scheduledNotifications;
 // Retrieves the application state
 @property (readonly, getter=applicationState) NSString* applicationState;
 // All events will be queued until deviceready has been fired
@@ -37,13 +39,13 @@
 
 @implementation APPLocalNotification
 
-@synthesize deviceready, eventQueue, applicationState, scheduledNotifications;
+@synthesize deviceready, eventQueue;
 
 #pragma mark -
-#pragma mark Plugin interface methods
+#pragma mark Interface
 
 /**
- * Executes all queued events.
+ * Execute all queued events.
  */
 - (void) deviceready:(CDVInvokedUrlCommand*)command
 {
@@ -57,29 +59,24 @@
 }
 
 /**
- * Schedules a new local notification.
+ * Schedule a new local notification.
  *
- * @param {NSMutableDictionary} properties
- *      The properties of the notification
+ * @param properties
+ *      A dict of properties
  */
 - (void) add:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* arguments = [command arguments];
-        NSMutableDictionary* properties = [arguments objectAtIndex:0];
-
-        NSString* id = [properties objectForKey:@"id"];
+        NSDictionary* options = [[command arguments]
+                                 objectAtIndex:0];
 
-        if ([self isNotificationScheduledWithId:id]) {
-            UILocalNotification* notification = [self notificationWithId:id];
+        UILocalNotification* notification;
 
-            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC),
-                           dispatch_get_main_queue(), ^{
-                               [self cancelNotification:notification fireEvent:NO];
-                           });
-        }
+        notification = [[UILocalNotification alloc]
+                        initWithOptions:options];
 
-        [self scheduleNotificationWithProperties:properties];
+        [self scheduleLocalNotification:notification];
+        [self fireEvent:@"add" localNotification:notification];
         [self execCallback:command];
     }];
 }
@@ -87,21 +84,22 @@
 /**
  * Cancels a given local notification.
  *
- * @param {NSString} id
+ * @param id
  *      The ID of the local notification
  */
 - (void) cancel:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* arguments = [command arguments];
-        NSString* id       = [arguments objectAtIndex:0];
+        NSString* id = [[command arguments]
+                        objectAtIndex:0];
 
-        UILocalNotification* notification = [self notificationWithId:id];
+        UILocalNotification* notification;
 
-        if (notification) {
-            [self cancelNotification:notification fireEvent:YES];
-        }
+        notification = [[UIApplication sharedApplication]
+                        scheduledLocalNotificationWithId:id];
 
+        [self cancelLocalNotification:notification];
+        [self fireEvent:@"cancel" localNotification:notification];
         [self execCallback:command];
     }];
 }
@@ -112,37 +110,31 @@
 - (void) cancelAll:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* notifications = self.scheduledNotifications;
-
-        for (UILocalNotification* notification in notifications) {
-            [self cancelNotification:notification fireEvent:YES];
-        }
-
-        [[UIApplication sharedApplication]
-         cancelAllLocalNotifications];
-
-        [[UIApplication sharedApplication]
-         setApplicationIconBadgeNumber:0];
-
+        [self cancelAllLocalNotifications];
+        [self fireEvent:@"cancelall"];
         [self execCallback:command];
     }];
 }
 
 /**
- * Checks wether a notification with an ID is scheduled.
+ * If a notification by ID is scheduled.
  *
- * @param {NSString} id
+ * @param id
  *      The ID of the notification
- * @param callback
- *      The callback function to be called with the result
  */
 - (void) isScheduled:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* arguments = [command arguments];
-        NSString* id       = [arguments objectAtIndex:0];
-        bool isScheduled   = [self isNotificationScheduledWithId:id];
+        NSString* id = [[command arguments]
+                        objectAtIndex:0];
+
         CDVPluginResult* result;
+        UILocalNotification* notification;
+
+        notification = [[UIApplication sharedApplication]
+                        scheduledLocalNotificationWithId:id];
+
+        bool isScheduled = notification != NULL;
 
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                      messageAsBool:isScheduled];
@@ -153,25 +145,16 @@
 }
 
 /**
- * Retrieves a list of ids from all currently pending notifications.
- *
- * @param callback
- *      The callback function to be called with the result
+ * List of ids from all currently pending notifications.
  */
 - (void) getScheduledIds:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* notifications = self.scheduledNotifications;
-
-        NSMutableArray* scheduledIds = [[NSMutableArray alloc] init];
         CDVPluginResult* result;
+        NSArray* scheduledIds;
 
-        for (UILocalNotification* notification in notifications)
-        {
-            NSString* id = [notification.userInfo objectForKey:@"id"];
-
-            [scheduledIds addObject:id];
-        }
+        scheduledIds = [[UIApplication sharedApplication]
+                        scheduledLocalNotificationIds];
 
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                     messageAsArray:scheduledIds];
@@ -184,18 +167,22 @@
 /**
  * Checks wether a notification with an ID was triggered.
  *
- * @param {NSString} id
+ * @param id
  *      The ID of the notification
- * @param callback
- *      The callback function to be called with the result
  */
 - (void) isTriggered:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* arguments = [command arguments];
-        NSString* id       = [arguments objectAtIndex:0];
-        bool isTriggered   = [self isNotificationTriggeredWithId:id];
+        NSString* id = [[command arguments]
+                        objectAtIndex:0];
+
         CDVPluginResult* result;
+        UILocalNotification* notification;
+
+        notification = [[UIApplication sharedApplication]
+                        triggeredLocalNotificationWithId:id];
+
+        bool isTriggered = notification != NULL;
 
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                      messageAsBool:isTriggered];
@@ -207,31 +194,18 @@
 
 /**
  * Retrieves a list of ids from all currently triggered notifications.
- *
- * @param callback
- *      The callback function to be called with the result
  */
 - (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
 {
     [self.commandDelegate runInBackground:^{
-        NSArray* notifications = self.scheduledNotifications;
-
-        NSMutableArray* scheduledIds = [[NSMutableArray alloc] init];
         CDVPluginResult* result;
+        NSArray* triggeredIds;
 
-        for (UILocalNotification* notification in notifications)
-        {
-            if (![self isNotificationTriggered:notification]) {
-                continue;
-            }
-
-            NSString* id = [notification.userInfo objectForKey:@"id"];
-
-            [scheduledIds addObject:id];
-        }
+        triggeredIds = [[UIApplication sharedApplication]
+                        triggeredLocalNotificationIds];
 
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                    messageAsArray:scheduledIds];
+                                    messageAsArray:triggeredIds];
 
         [self.commandDelegate sendPluginResult:result
                                     callbackId:command.callbackId];
@@ -239,17 +213,17 @@
 }
 
 /**
- * Informs if the app has the permission to show
+ * Inform if the app has the permission to show
  * badges and local notifications.
- *
- * @param callback
- *      The function to be exec as the callback
  */
 - (void) hasPermission:(CDVInvokedUrlCommand *)command
 {
     [self.commandDelegate runInBackground:^{
         CDVPluginResult* result;
-        BOOL hasPermission = [self hasPermissionToSheduleNotifications];
+        BOOL hasPermission;
+
+        hasPermission = [[UIApplication sharedApplication]
+                         hasPermissionToScheduleLocalNotifications];
 
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                      messageAsBool:hasPermission];
@@ -261,174 +235,114 @@
 
 /**
  * Ask for permission to show badges.
- *
- * @param callback
- *      The function to be exec as the callback
  */
-- (void) promptForPermission:(CDVInvokedUrlCommand *)command
+- (void) registerPermission:(CDVInvokedUrlCommand *)command
 {
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
-    UIUserNotificationType types;
-    UIUserNotificationSettings *settings;
-
-    types = UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
-
-    settings = [UIUserNotificationSettings settingsForTypes:types
-                                                 categories:nil];
-
     [self.commandDelegate runInBackground:^{
         [[UIApplication sharedApplication]
-         registerUserNotificationSettings:settings];
+         registerPermissionToScheduleLocalNotifications];
     }];
-#endif
 }
 
 #pragma mark -
-#pragma mark Plugin core methods
+#pragma mark Core Logic
 
 /**
- * Schedules a new local notification and fies the coresponding event.
- *
- * @param {NSMutableDictionary} properties
- *      The properties of the notification
+ * Schedule the local notification.
  */
-- (void) scheduleNotificationWithProperties:(NSMutableDictionary*)properties
+- (void) scheduleLocalNotification:(UILocalNotification*)notification
 {
-    UILocalNotification* notification = [self notificationWithProperties:
-                                         properties];
+    [self cancelForerunnerLocalNotification:notification];
 
-    NSDictionary* userInfo = notification.userInfo;
-    NSString* id = [userInfo objectForKey:@"id"];
-    NSString* json = [userInfo objectForKey:@"json"];
+    NSString* state = self.applicationState;
 
-    [self fireEvent:@"add" id:id json:json];
+    if ([state isEqualToString:@"background"]) {
+        [[UIApplication sharedApplication]
+         presentLocalNotificationNow:notification];
+    }
 
     [[UIApplication sharedApplication]
      scheduleLocalNotification:notification];
 }
 
 /**
- * Cancels the given local notification
- * and fires the cancel event.
- *
- * @param {NSString} id
- *      The ID of the local notification
+ * Cancel the local notification.
  */
-- (void) cancelNotification:(UILocalNotification*)notification
-                  fireEvent:(BOOL)fireEvent
+- (void) cancelLocalNotification:(UILocalNotification*)notification
 {
-    NSDictionary* userInfo = notification.userInfo;
-    NSString* id           = [userInfo objectForKey:@"id"];
-    NSString* json         = [userInfo objectForKey:@"json"];
-
-    if (notification==nil) {
-        NSLog(@"cancelNotification: Notification equals nil");
-    }else{
-        [[UIApplication sharedApplication]
-         cancelLocalNotification:notification];
-    }
+    if (!notification)
+        return;
 
-    if (fireEvent) {
-        [self fireEvent:@"cancel" id:id json:json];
-    }
+    [[UIApplication sharedApplication]
+     cancelLocalNotification:notification];
 }
 
 /**
- * Cancels all local notification with are older then
- * a specific amount of seconds
- *
- * @param {float} seconds
- *      The time interval in seconds
+ * Cancel all currently scheduled notifications.
  */
-- (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
+- (void) cancelAllLocalNotifications
 {
-    NSDate* now = [NSDate date];
-
-    NSArray* notifications = self.scheduledNotifications;
+    NSArray* notifications;
 
-    for (UILocalNotification* notification in notifications)
-    {
-        NSDate* fireDate = notification.fireDate;
-        NSTimeInterval fireDateDistance = [now timeIntervalSinceDate:
-                                           fireDate];
+    notifications = [[UIApplication sharedApplication]
+                     scheduledLocalNotifications];
 
-        if (notification.repeatInterval == NSCalendarUnitEra
-            && fireDateDistance > seconds) {
-            [self cancelNotification:notification fireEvent:YES];
-        }
+    for (UILocalNotification* notification in notifications) {
+        [self cancelLocalNotification:notification];
     }
+
+    [[UIApplication sharedApplication]
+     cancelAllLocalNotifications];
+
+    [[UIApplication sharedApplication]
+     setApplicationIconBadgeNumber:0];
 }
 
 /**
- * Creates an notification object based on the given properties.
- *
- * @param {NSMutableDictionary} properties
- *      The properties for the local notification
- * @return {UILocalNotification}
+ * Cancel a maybe given forerunner with the same ID.
  */
-- (UILocalNotification*) notificationWithProperties:(NSMutableDictionary*)options
+- (void) cancelForerunnerLocalNotification:(UILocalNotification*)notification
 {
-    UILocalNotification* notification = [[UILocalNotification alloc] init];
-
-    double timestamp = [[options objectForKey:@"date"] doubleValue];
-    NSString* msg = [options objectForKey:@"message"];
-    NSString* title = [options objectForKey:@"title"];
-    NSString* sound = [options objectForKey:@"sound"];
-    NSString* repeat = [options objectForKey:@"repeat"];
-    NSInteger badge = [[options objectForKey:@"badge"] intValue];
+    NSString* id = notification.options.id;
+    UILocalNotification* forerunner;
 
-    notification.fireDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
-    notification.timeZone = [NSTimeZone defaultTimeZone];
-    notification.userInfo = [self userDict:options];
-    notification.applicationIconBadgeNumber = badge;
-
-    notification.repeatInterval = [[[self repeatDict] objectForKey:repeat]
-                                   intValue];
-
-    if (![self stringIsNullOrEmpty:msg])
-    {
-        if (![self stringIsNullOrEmpty:title]) {
-            notification.alertBody = [NSString stringWithFormat:
-                                      @"%@\n%@", title, msg];
-        } else {
-            notification.alertBody = msg;
-        }
-    }
+    forerunner = [[UIApplication sharedApplication]
+                  scheduledLocalNotificationWithId:id];
 
-    if (sound != (NSString*)[NSNull null])
-    {
-        if ([sound isEqualToString:@""]) {
-            notification.soundName = UILocalNotificationDefaultSoundName;
-        } else {
-            notification.soundName = sound;
-        }
-    }
+    if (!forerunner)
+        return;
 
-    return notification;
+    [self cancelLocalNotification:forerunner];
 }
 
+
 /**
- * If the app has the permission to show badges.
+ * Cancels all local notification with are older then
+ * a specific amount of seconds
+ *
+ * @param {float} seconds
+ *      The time interval in seconds
  */
-- (BOOL) hasPermissionToSheduleNotifications
+- (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
 {
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
-    UIUserNotificationType types;
-    UIUserNotificationSettings *settings;
-
-    settings = [[UIApplication sharedApplication]
-                currentUserNotificationSettings];
+    NSArray* notifications;
 
-    types = UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
+    notifications = [[UIApplication sharedApplication]
+                     scheduledLocalNotifications];
 
-    return (settings.types & types);
-#else
-    return YES;
-#endif
+    for (UILocalNotification* notification in notifications)
+    {
+        if (notification && notification.repeatInterval == NSCalendarUnitEra
+            && notification.timeIntervalSinceFireDate > seconds)
+        {
+            [self cancelLocalNotification:notification];
+            [self fireEvent:@"cancel" localNotification:notification];
+        }
+    }
 }
 
 #pragma mark -
-#pragma mark Plugin delegate and life cycle methods
+#pragma mark Delegates
 
 /**
  * Calls the cancel or trigger event after a local notification was received.
@@ -436,38 +350,36 @@
  */
 - (void) didReceiveLocalNotification:(NSNotification*)localNotification
 {
+    UIApplication* app = [UIApplication sharedApplication];
     UILocalNotification* notification = [localNotification object];
 
-    NSDictionary* userInfo = notification.userInfo;
-    NSString* id = [userInfo objectForKey:@"id"];
-    NSString* json = [userInfo objectForKey:@"json"];
-    BOOL autoCancel = [[userInfo objectForKey:@"autoCancel"] boolValue];
+    BOOL autoCancel = notification.options.autoCancel;
+    NSTimeInterval timeInterval = notification.timeIntervalSinceFireDate;
 
-    NSDate* now = [NSDate date];
-    NSDate* fireDate = notification.fireDate;
-    NSTimeInterval fireDateDistance = [now timeIntervalSinceDate:fireDate];
-    NSString* event = (fireDateDistance < 1) ? @"trigger" : @"click";
+    NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
 
-    if ([[self applicationState] isEqualToString:@"foreground"]) {
-        event = @"trigger";
-    }
+    app.applicationIconBadgeNumber -= 1;
+
+    [self fireEvent:event localNotification:notification];
 
     if (autoCancel && [event isEqualToString:@"click"]) {
-        [self cancelNotification:notification fireEvent:YES];
+        [self cancelLocalNotification:notification];
+        [self fireEvent:@"cancel" localNotification:notification];
     }
-
-    [self fireEvent:event id:id json:json];
 }
 
 /**
- * Calls the cancel or trigger event after a local notification was received.
+ * Called when app has started
+ * (by clicking on a local notification).
  */
 - (void) didFinishLaunchingWithOptions:(NSNotification*)notification
 {
     NSDictionary* launchOptions = [notification userInfo];
 
-    UILocalNotification* localNotification = [launchOptions objectForKey:
-                                              UIApplicationLaunchOptionsLocalNotificationKey];
+    UILocalNotification* localNotification;
+
+    localNotification = [launchOptions objectForKey:
+                         UIApplicationLaunchOptionsLocalNotificationKey];
 
     if (localNotification) {
         [self didReceiveLocalNotification:
@@ -476,6 +388,9 @@
     }
 }
 
+#pragma mark -
+#pragma mark Life Cycle
+
 /**
  * Registers obervers for the following events after plugin was initialized.
  *      didReceiveLocalNotification:
@@ -483,8 +398,10 @@
  */
 - (void) pluginInitialize
 {
-    NSNotificationCenter* notificationCenter = [NSNotificationCenter
-                                                defaultCenter];
+    NSNotificationCenter* notificationCenter;
+
+    notificationCenter = [NSNotificationCenter
+                          defaultCenter];
 
     eventQueue = [[NSMutableArray alloc] init];
 
@@ -509,153 +426,12 @@
 }
 
 #pragma mark -
-#pragma mark Plugin helper methods
-
-/**
- * Retrurns a key-value dictionary for repeat intervals.
- *
- * @return {NSMutableDictionary}
- */
-- (NSMutableDictionary*) repeatDict
-{
-    NSMutableDictionary* repeatDict = [[NSMutableDictionary alloc] init];
-
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitSecond] forKey:@"secondly"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitMinute] forKey:@"minutely"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitHour] forKey:@"hourly"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitDay] forKey:@"daily"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitWeekOfYear] forKey:@"weekly"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitMonth] forKey:@"monthly"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitYear] forKey:@"yearly"];
-    [repeatDict setObject:
-     [NSNumber numberWithInt:NSCalendarUnitEra] forKey:@""];
-
-    return repeatDict;
-}
-
-/**
- * Returns the userDict for a local notification.
- *
- * @param {NSMutableDictionary} options
- *      The properties for the local notification
- * @return {NSDictionary}
- */
-- (NSDictionary*) userDict:(NSMutableDictionary*)options
-{
-    NSString* id = [options objectForKey:@"id"];
-    NSString* ac = [options objectForKey:@"autoCancel"];
-    NSString* js = [options objectForKey:@"json"];
-
-    return [NSDictionary dictionaryWithObjectsAndKeys:
-            id, @"id", ac, @"autoCancel", js, @"json", nil];
-}
-
-/**
- * Checks weather the given string is empty or not.
- *
- * @param {NSString} str The string to be check
- * @return {BOOL}
- */
-- (BOOL) stringIsNullOrEmpty:(NSString*)str
-{
-    if (str == (NSString*)[NSNull null]) {
-        return YES;
-    }
-
-    if ([str isEqualToString:@""]) {
-        return YES;
-    }
-
-    return NO;
-}
-
-/**
- * Checks wether a notification with an ID is scheduled or not.
- *
- * @param id
- *      The ID of the notification
- * @return BOOL
- */
-- (BOOL) isNotificationScheduledWithId:(NSString*)id
-{
-    UILocalNotification* notification = [self notificationWithId:id];
-
-    return notification != NULL;
-}
-
-/**
- * Checks wether a notification with an ID was triggered or not.
- *
- * @param id
- *      The ID of the notification
- * @return BOOL
- */
-- (BOOL) isNotificationTriggeredWithId:(NSString*)id
-{
-    UILocalNotification* notification = [self notificationWithId:id];
-
-    if (notification == NULL) {
-        return NO;
-    }
-
-    return [self isNotificationTriggered:notification];
-}
-
-/**
- * Checks wether a notification was triggered or not.
- *
- * @param notification
- *      The notification
- * @return BOOL
- */
-- (BOOL) isNotificationTriggered:(UILocalNotification*)notification
-{
-    NSDate* now      = [NSDate date];
-    NSDate* fireDate = notification.fireDate;
-
-    bool isLaterThanOrEqualTo = !([now compare:fireDate] == NSOrderedAscending);
-
-    return isLaterThanOrEqualTo;
-}
-
-/**
- * Retrieves the local notification by its ID.
- *
- * @param {NSString} id
- *      The ID of the notification
- * @return UILocalNotification*
- */
-- (UILocalNotification*) notificationWithId:(NSString*)id
-{
-    NSArray* notifications = self.scheduledNotifications;
-
-    for (UILocalNotification* notification in notifications)
-    {
-        NSString* notId = NULL;
-        if ([[notification.userInfo objectForKey:@"id"] isKindOfClass:[NSString class]] ) {
-            notId = [notification.userInfo objectForKey:@"id"];
-        } else {
-            notId = [[notification.userInfo objectForKey:@"id"] stringValue];
-        }
-        if ([notId isEqualToString:id]) {
-            return notification;
-        }
-    }
-
-    return NULL;
-}
+#pragma mark Helper
 
 /**
  * Retrieves the application state
  *
- * @return {NSString}
+ * @return
  *      Either "background" or "foreground"
  */
 - (NSString*) applicationState
@@ -669,35 +445,8 @@
 }
 
 /**
- * Retrieves all scheduled notifications.
- *
- * @return {NSArray}
- *      A list of all scheduled local notifications
- */
-- (NSArray*) scheduledNotifications
-{
-    NSMutableArray* notificationsWithoutNIL = [[NSMutableArray alloc]
-                                               init];
-
-    NSArray* notifications = [[UIApplication sharedApplication]
-                              scheduledLocalNotifications];
-
-    for (UILocalNotification* notification in notifications)
-    {
-        if (notification) {
-            [notificationsWithoutNIL addObject:notification];
-        }
-    }
-
-    return notificationsWithoutNIL;
-}
-
-#pragma mark -
-#pragma mark Plugin callback methods
-
-/**
- * Simply invokes the callback without any parameter.
- */
+  * Simply invokes the callback without any parameter.
+  */
 - (void) execCallback:(CDVInvokedUrlCommand*)command
 {
     CDVPluginResult *result = [CDVPluginResult
@@ -708,26 +457,35 @@
 }
 
 /**
- * Fires the given event.
- *
- * @param {NSString} event
- *      The Name of the event
- * @param {NSString} id
- *      The ID of the notification
- * @param {NSString} json
- *      A custom (JSON) string
+ * Fire general event.
  */
-- (void) fireEvent:(NSString*)event id:(NSString*)id json:(NSString*)json
+- (void) fireEvent:(NSString*)event
 {
-    NSString* appState = self.applicationState;
+    [self fireEvent:event localNotification:NULL];
+}
 
+/**
+ * Fire event for local notification.
+ */
+- (void) fireEvent:(NSString*)event localNotification:(UILocalNotification*)notification
+{
+    NSString* js;
     NSString* params = [NSString stringWithFormat:
-                        @"\"%@\",\"%@\",\\'%@\\'",
-                        id, appState, json];
+                        @"\"%@\"", self.applicationState];
+
+    if (notification) {
+        NSString* id = notification.options.id;
+        NSString* json = notification.options.json;
+        NSString* args = [notification.options encodeToJSON];
+
+        params = [NSString stringWithFormat:
+                  @"\"%@\",\"%@\",\\'%@\\',JSON.parse(\\'%@\\')",
+                  id, self.applicationState, json, args];
+    }
 
-    NSString* js = [NSString stringWithFormat:
-                    @"setTimeout('plugin.notification.local.on%@(%@)',0)",
-                    event, params];
+    js = [NSString stringWithFormat:
+          @"setTimeout('plugin.notification.local.on%@(%@)',0)",
+          event, params];
 
     if (deviceready) {
         [self.commandDelegate evalJs:js];

+ 39 - 0
src/ios/APPLocalNotificationOptions.h

@@ -0,0 +1,39 @@
+/*
+ Copyright 2013-2014 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface APPLocalNotificationOptions : NSObject
+
+- (id) initWithDict:(NSDictionary*)dict;
+
+@property (readonly, getter=id) NSString* id;
+@property (readonly, getter=autoCancel) BOOL autoCancel;
+@property (readonly, getter=json) NSString* json;
+@property (readonly, getter=badgeNumber) NSInteger badgeNumber;
+@property (readonly, getter=alertBody) NSString* alertBody;
+@property (readonly, getter=soundName) NSString* soundName;
+@property (readonly, getter=fireDate) NSDate* fireDate;
+@property (readonly, getter=repeatInterval) NSCalendarUnit repeatInterval;
+@property (readonly, getter=userInfo) NSDictionary* userInfo;
+
+// Encode the user info dict to JSON
+- (NSString*) encodeToJSON;
+
+@end

+ 262 - 0
src/ios/APPLocalNotificationOptions.m

@@ -0,0 +1,262 @@
+/*
+ Copyright 2013-2014 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "APPLocalNotificationOptions.h"
+#import <Cordova/CDVAvailability.h>
+
+@interface APPLocalNotificationOptions ()
+
+// The dictionary which contains all notification properties
+@property(readwrite, assign) NSDictionary* dict;
+
+@end
+
+@implementation APPLocalNotificationOptions
+
+@synthesize dict;
+
+#pragma mark -
+#pragma mark Initialization
+
+/**
+ * Initialize the object with the given options when calling on JS side:
+ * notification.local.add(options)
+ */
+- (id) initWithDict:(NSDictionary*)dictionary
+{
+    self = [super init];
+
+    self.dict = dictionary;
+
+    return self;
+}
+
+#pragma mark -
+#pragma mark Attributes
+
+/**
+ * The notification's ID.
+ */
+- (NSString*) id
+{
+    return [dict objectForKey:@"id"];
+}
+
+/**
+ * The notification's title.
+ */
+- (NSString*) title
+{
+    return [dict objectForKey:@"title"];
+}
+
+/**
+ * The notification's message.
+ */
+- (NSString*) message
+{
+    return [dict objectForKey:@"message"];
+}
+
+/**
+ * The notification's auto cancel flag.
+ */
+- (BOOL) autoCancel
+{
+    if (IsAtLeastiOSVersion(@"8.0")){
+        return YES;
+    } else {
+        return [[dict objectForKey:@"autoCancel"] boolValue];
+    }
+}
+
+/**
+ * The notification's JSON data.
+ */
+- (NSString*) json
+{
+    return [dict objectForKey:@"json"];
+}
+
+/**
+ * The notification's badge number.
+ */
+- (NSInteger) badgeNumber
+{
+    return [[dict objectForKey:@"badge"] intValue];
+}
+
+#pragma mark -
+#pragma mark Complex Attributes
+
+/**
+ * The notification's alert body.
+ */
+- (NSString*) alertBody
+{
+    NSString* title = [self title];
+    NSString* msg = [self message];
+
+    NSString* alertBody = msg;
+
+    if (![self stringIsNullOrEmpty:title])
+    {
+        alertBody = [NSString stringWithFormat:@"%@\n%@",
+                     title, msg];
+    }
+
+    return alertBody;
+}
+
+/**
+ * The notification's sound path.
+ */
+- (NSString*) soundName
+{
+    NSString* path = [dict objectForKey:@"sound"];
+
+    if ([path hasPrefix:@"file:/"])
+    {
+        return [self soundNameForAsset:path];
+    }
+    else if ([path hasPrefix:@"res:"])
+    {
+        return [self soundNameForResource:path];
+    }
+
+    return UILocalNotificationDefaultSoundName;
+}
+
+/**
+ * The notification's fire date.
+ */
+- (NSDate*) fireDate
+{
+    double timestamp = [[dict objectForKey:@"date"]
+                        doubleValue];
+
+    return [NSDate dateWithTimeIntervalSince1970:timestamp];
+}
+
+/**
+ * The notification's repeat interval.
+ */
+- (NSCalendarUnit) repeatInterval
+{
+    NSString* interval = [dict objectForKey:@"repeat"];
+
+    if ([interval isEqualToString:@"secondly"])
+    {
+        return NSCalendarUnitSecond;
+    }
+    else if ([interval isEqualToString:@"minutely"])
+    {
+        return NSCalendarUnitMinute;
+    }
+    else if ([interval isEqualToString:@"hourly"])
+    {
+        return NSCalendarUnitHour;
+    }
+    else if ([interval isEqualToString:@"daily"])
+    {
+        return NSCalendarUnitDay;
+    }
+    else if ([interval isEqualToString:@"weekly"])
+    {
+        return NSCalendarUnitWeekOfYear;
+    }
+    else if ([interval isEqualToString:@"monthly"])
+    {
+        return NSCalendarUnitMonth;
+    }
+    else if ([interval isEqualToString:@"yearly"])
+    {
+        return NSCalendarUnitYear;
+    }
+
+    return NSCalendarUnitEra;
+}
+
+/**
+ * The notification's user info dict.
+ */
+- (NSDictionary*) userInfo
+{
+    return dict;
+}
+
+/**
+ * Encode the user info dict to JSON.
+ */
+- (NSString*) encodeToJSON
+{
+    NSString* json;
+    NSData* data;
+    NSMutableDictionary* obj = [dict mutableCopy];
+
+    [obj removeObjectForKey:@"json"];
+
+    data = [NSJSONSerialization dataWithJSONObject:obj
+                                           options:NSJSONWritingPrettyPrinted
+                                             error:Nil];
+
+    json = [[NSString alloc] initWithData:data
+                                 encoding:NSUTF8StringEncoding];
+
+    return [json stringByReplacingOccurrencesOfString:@"\n"
+                                           withString:@""];
+}
+
+#pragma mark -
+#pragma mark Helpers
+
+/**
+ * Convert relative path to valid sound name attribute.
+ */
+- (NSString*) soundNameForAsset:(NSString*)path
+{
+    return [path stringByReplacingOccurrencesOfString:@"file:/"
+                                           withString:@"www"];
+}
+
+/**
+ * Convert resource path to valid sound name attribute.
+ */
+- (NSString*) soundNameForResource:(NSString*)path
+{
+    return [path pathComponents].lastObject;
+}
+
+/**
+ * If the string is empty.
+ */
+- (BOOL) stringIsNullOrEmpty:(NSString*)str
+{
+    if (str == (NSString*)[NSNull null])
+        return YES;
+
+    if ([str isEqualToString:@""])
+        return YES;
+
+    return NO;
+}
+
+@end

+ 37 - 0
src/ios/UIApplication+APPLocalNotification.h

@@ -0,0 +1,37 @@
+/*
+ Copyright 2013-2014 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface UIApplication (APPLocalNotification)
+
+@property (readonly, getter=triggeredLocalNotifications) NSArray* triggeredLocalNotifications;
+@property (readonly, getter=triggeredLocalNotificationIds) NSArray* triggeredLocalNotificationIds;
+@property (readonly, getter=scheduledLocalNotificationIds) NSArray* scheduledLocalNotificationIds;
+
+// If the app has the permission to schedule local notifications
+- (BOOL) hasPermissionToScheduleLocalNotifications;
+// Ask for permission to schedule local notifications
+- (void) registerPermissionToScheduleLocalNotifications;
+// Get the scheduled local notification by ID
+- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id;
+// Get the triggered local notification by ID
+- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id;
+
+@end

+ 162 - 0
src/ios/UIApplication+APPLocalNotification.m

@@ -0,0 +1,162 @@
+/*
+ Copyright 2013-2014 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "UIApplication+APPLocalNotification.h"
+#import "UILocalNotification+APPLocalNotification.h"
+
+#import <Availability.h>
+
+@implementation UIApplication (APPLocalNotification)
+
+#pragma mark -
+#pragma mark Permissions
+
+/**
+ * If the app has the permission to schedule local notifications.
+ */
+- (BOOL) hasPermissionToScheduleLocalNotifications
+{
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
+    UIUserNotificationType types;
+    UIUserNotificationSettings *settings;
+
+    settings = [[UIApplication sharedApplication]
+                currentUserNotificationSettings];
+
+    types = UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
+
+    return (settings.types & types);
+#else
+    return YES;
+#endif
+}
+
+/**
+ * Ask for permission to schedule local notifications.
+ */
+- (void) registerPermissionToScheduleLocalNotifications
+{
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
+    UIUserNotificationType types;
+    UIUserNotificationSettings *settings;
+
+    types = UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
+
+    settings = [UIUserNotificationSettings settingsForTypes:types
+                                                 categories:nil];
+
+    [[UIApplication sharedApplication]
+     registerUserNotificationSettings:settings];
+#endif
+}
+
+#pragma mark -
+#pragma mark LocalNotifications
+
+/**
+ * List of all triggered local notifications which have been scheduled
+ * and not yet removed the notification center.
+ */
+- (NSArray*) triggeredLocalNotifications
+{
+    NSArray* scheduledNotifications = self.scheduledLocalNotifications;
+    NSMutableArray* triggeredNotifications = [[NSMutableArray alloc] init];
+
+    for (UILocalNotification* notification in scheduledNotifications)
+    {
+        if (notification && [notification wasTriggered])
+        {
+            [triggeredNotifications addObject:notification];
+        }
+    }
+
+    return triggeredNotifications;
+}
+
+/**
+ * List of all triggered local notifications IDs which have been scheduled
+ * and not yet removed the notification center.
+ */
+- (NSArray*) triggeredLocalNotificationIds
+{
+    NSArray* triggeredNotifications = self.triggeredLocalNotifications;
+    NSMutableArray* triggeredNotificationIds = [[NSMutableArray alloc] init];
+
+    for (UILocalNotification* notification in triggeredNotifications)
+    {
+        [triggeredNotificationIds addObject:notification.options.id];
+    }
+
+    return triggeredNotificationIds;
+}
+
+/**
+ * List of all scheduled local notifications IDs.
+ */
+- (NSArray*) scheduledLocalNotificationIds
+{
+    NSArray* scheduledNotifications = self.scheduledLocalNotifications;
+    NSMutableArray* scheduledNotificationIds = [[NSMutableArray alloc] init];
+
+    for (UILocalNotification* notification in scheduledNotifications)
+    {
+        if (notification)
+        {
+            [scheduledNotificationIds addObject:notification.options.id];
+        }
+    }
+
+    return scheduledNotificationIds;
+}
+
+/**
+ * Get the scheduled local notification by ID.
+ */
+- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id
+{
+    NSArray* notifications = self.scheduledLocalNotifications;
+
+    for (UILocalNotification* notification in notifications)
+    {
+        if (notification && [notification.options.id isEqualToString:id])
+        {
+            return notification;
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Get the triggered local notification by ID.
+ */
+- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id
+{
+    UILocalNotification* notification = [self scheduledLocalNotificationWithId:id];
+
+    if (notification && [notification wasTriggered]) {
+        return notification;
+    }
+
+    return NULL;
+}
+
+@end

+ 37 - 0
src/ios/UILocalNotification+APPLocalNotification.h

@@ -0,0 +1,37 @@
+/*
+ Copyright 2013-2014 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "APPLocalNotificationOptions.h"
+
+@interface UILocalNotification (APPLocalNotification)
+
+// Initialize a new local notification
+- (id) initWithOptions:(NSDictionary*)dict;
+// The options provided by the plug-in
+- (APPLocalNotificationOptions*) options;
+// Timeinterval since fire date
+- (NSTimeInterval) timeIntervalSinceFireDate;
+// If the fire date was in the past
+- (BOOL) wasInThePast;
+// If the notification was already triggered
+- (BOOL) wasTriggered;
+
+@end

+ 130 - 0
src/ios/UILocalNotification+APPLocalNotification.m

@@ -0,0 +1,130 @@
+/*
+ Copyright 2013-2014 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "UILocalNotification+APPLocalNotification.h"
+#import "APPLocalNotificationOptions.h"
+#import <objc/runtime.h>
+
+static char optionsKey;
+
+@implementation UILocalNotification (APPLocalNotification)
+
+#pragma mark -
+#pragma mark Init methods
+
+/**
+ * Initialize a local notification with the given options when calling on JS side:
+ * notification.local.add(options)
+ */
+- (id) initWithOptions:(NSDictionary*)dict
+{
+    self = [super init];
+
+    [self setUserInfo:dict];
+    [self __init];
+
+    return self;
+}
+
+/**
+ * Applies the given options when calling on JS side:
+ * notification.local.add(options)
+
+ */
+- (void) __init
+{
+    APPLocalNotificationOptions* options = self.options;
+
+    self.fireDate = options.fireDate;
+    self.timeZone = [NSTimeZone defaultTimeZone];
+    self.applicationIconBadgeNumber = options.badgeNumber;
+    self.repeatInterval = options.repeatInterval;
+    self.alertBody = options.alertBody;
+    self.soundName = options.soundName;
+}
+
+/**
+ * The options provided by the plug-in.
+ */
+- (APPLocalNotificationOptions*) options
+{
+    APPLocalNotificationOptions* options = [self getOptions];
+
+    if (!options) {
+        options = [[APPLocalNotificationOptions alloc]
+                   initWithDict:[self userInfo]];
+
+        [self setOptions:options];
+    }
+
+    return options;
+}
+
+/**
+ * Get associated option object
+ */
+- (APPLocalNotificationOptions*) getOptions
+{
+    return objc_getAssociatedObject(self, &optionsKey);
+}
+
+/**
+ * Set associated option object
+ */
+- (void) setOptions:(APPLocalNotificationOptions*)options
+{
+    objc_setAssociatedObject(self, &optionsKey,
+                             options, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+/**
+ * Timeinterval since fire date.
+ */
+- (NSTimeInterval) timeIntervalSinceFireDate
+{
+    NSDate* now      = [NSDate date];
+    NSDate* fireDate = self.options.fireDate;
+
+    return [now timeIntervalSinceDate:fireDate];
+}
+
+/**
+ * If the fire date was in the past.
+ */
+- (BOOL) wasInThePast
+{
+    return [self timeIntervalSinceFireDate] < 0;
+}
+
+/**
+ * If the notification was already triggered.
+ */
+- (BOOL) wasTriggered
+{
+    NSDate* now      = [NSDate date];
+    NSDate* fireDate = self.fireDate;
+
+    bool isLaterThanOrEqualTo = !([now compare:fireDate] == NSOrderedAscending);
+
+    return isLaterThanOrEqualTo;
+}
+
+@end