APPLocalNotification.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. /*
  2. Copyright 2013-2014 appPlant UG
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing,
  12. software distributed under the License is distributed on an
  13. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. KIND, either express or implied. See the License for the
  15. specific language governing permissions and limitations
  16. under the License.
  17. */
  18. #import "APPLocalNotification.h"
  19. @interface APPLocalNotification (Private)
  20. // Schedules a new local notification and fies the coresponding event
  21. - (void) scheduleNotificationWithProperties:(NSMutableDictionary*)properties;
  22. // Cancels the given local notification and fires the cancel event
  23. - (void) cancelNotification:(UILocalNotification*)notification fireEvent:(BOOL)fireEvent;
  24. // Cancels all local notification with are older then
  25. - (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds;
  26. // Retrurns a key-value dictionary for repeat intervals
  27. - (NSMutableDictionary*) repeatDict;
  28. // Returns the userDict for a local notification
  29. - (NSDictionary*) userDict:(NSMutableDictionary*)options;
  30. // Creates an notification object based on the given properties
  31. - (UILocalNotification*) notificationWithProperties:(NSMutableDictionary*)options;
  32. // Calls the cancel or trigger event after a local notification was received
  33. - (void) didReceiveLocalNotification:(NSNotification*)localNotification;
  34. // Calls the cancel or trigger event after a local notification was received
  35. - (void) didFinishLaunchingWithOptions:(NSNotification*)notification;
  36. // Registers obervers for the following events after plugin was initialized.
  37. - (void) pluginInitialize;
  38. // Clears all single repeating notifications which are older then 5 days
  39. - (void) onAppTerminate;
  40. // Checks weather the given string is empty or not
  41. - (BOOL) stringIsNullOrEmpty:(NSString*)str;
  42. // Checks wether a notification with an ID is scheduled or not
  43. - (BOOL) isNotificationScheduledWithId:(NSString*)id;
  44. // Retrieves the local notification by its ID
  45. - (UILocalNotification*) notificationWithId:(NSString*)id;
  46. // Retrieves the application state
  47. - (NSString*) applicationState;
  48. // Retrieves all scheduled notifications
  49. - (NSArray*) scheduledNotifications;
  50. // Simply invokes the callback without any parameter
  51. - (void) execCallback:(CDVInvokedUrlCommand*)command;
  52. // Fires the given event
  53. - (void) fireEvent:(NSString*)event id:(NSString*)id json:(NSString*)json;
  54. @end
  55. @interface APPLocalNotification ()
  56. // Retrieves all scheduled notifications
  57. @property (readonly, getter=scheduledNotifications) NSArray* scheduledNotifications;
  58. // Retrieves the application state
  59. @property (readonly, getter=applicationState) NSString* applicationState;
  60. // All events will be queued until deviceready has been fired
  61. @property (readwrite, assign) BOOL deviceready;
  62. // Event queue
  63. @property (readonly, nonatomic, retain) NSMutableArray* eventQueue;
  64. @end
  65. @implementation APPLocalNotification
  66. @synthesize deviceready, eventQueue, applicationState, scheduledNotifications;
  67. /**
  68. * Executes all queued events.
  69. */
  70. - (void) deviceready:(CDVInvokedUrlCommand*)command
  71. {
  72. deviceready = YES;
  73. for (NSString* js in eventQueue) {
  74. [self.commandDelegate evalJs:js];
  75. }
  76. [eventQueue removeAllObjects];
  77. }
  78. /**
  79. * Schedules a new local notification.
  80. *
  81. * @param {NSMutableDictionary} properties
  82. * The properties of the notification
  83. */
  84. - (void) add:(CDVInvokedUrlCommand*)command
  85. {
  86. [self.commandDelegate runInBackground:^{
  87. NSArray* arguments = [command arguments];
  88. NSMutableDictionary* properties = [arguments objectAtIndex:0];
  89. NSString* id = [properties objectForKey:@"id"];
  90. if ([self isNotificationScheduledWithId:id]) {
  91. UILocalNotification* notification = [self notificationWithId:id];
  92. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC),
  93. dispatch_get_main_queue(), ^{
  94. [self cancelNotification:notification fireEvent:NO];
  95. });
  96. }
  97. [self scheduleNotificationWithProperties:properties];
  98. }];
  99. }
  100. /**
  101. * Cancels a given local notification.
  102. *
  103. * @param {NSString} id
  104. * The ID of the local notification
  105. */
  106. - (void) cancel:(CDVInvokedUrlCommand*)command
  107. {
  108. [self.commandDelegate runInBackground:^{
  109. NSArray* arguments = [command arguments];
  110. NSString* id = [arguments objectAtIndex:0];
  111. UILocalNotification* notification = [self notificationWithId:id];
  112. if (notification) {
  113. [self cancelNotification:notification fireEvent:YES];
  114. }
  115. [self execCallback:command];
  116. }];
  117. }
  118. /**
  119. * Cancels all currently scheduled notifications.
  120. */
  121. - (void) cancelAll:(CDVInvokedUrlCommand*)command
  122. {
  123. [self.commandDelegate runInBackground:^{
  124. NSArray* notifications = self.scheduledNotifications;
  125. for (UILocalNotification* notification in notifications) {
  126. [self cancelNotification:notification fireEvent:YES];
  127. }
  128. [[UIApplication sharedApplication]
  129. cancelAllLocalNotifications];
  130. [[UIApplication sharedApplication]
  131. setApplicationIconBadgeNumber:0];
  132. [self execCallback:command];
  133. }];
  134. }
  135. /**
  136. * Checks wether a notification with an ID is scheduled.
  137. *
  138. * @param {NSString} id
  139. * The ID of the notification
  140. * @param callback
  141. * The callback function to be called with the result
  142. */
  143. - (void) isScheduled:(CDVInvokedUrlCommand*)command
  144. {
  145. [self.commandDelegate runInBackground:^{
  146. NSArray* arguments = [command arguments];
  147. NSString* id = [arguments objectAtIndex:0];
  148. bool isScheduled = [self isNotificationScheduledWithId:id];
  149. CDVPluginResult* result;
  150. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  151. messageAsBool:isScheduled];
  152. [self.commandDelegate sendPluginResult:result
  153. callbackId:command.callbackId];
  154. }];
  155. }
  156. /**
  157. * Retrieves a list of ids from all currently pending notifications.
  158. *
  159. * @param callback
  160. * The callback function to be called with the result
  161. */
  162. - (void) getScheduledIds:(CDVInvokedUrlCommand*)command
  163. {
  164. [self.commandDelegate runInBackground:^{
  165. NSArray* notifications = self.scheduledNotifications;
  166. NSMutableArray* scheduledIds = [[NSMutableArray alloc] init];
  167. CDVPluginResult* result;
  168. for (UILocalNotification* notification in notifications)
  169. {
  170. NSString* id = [notification.userInfo objectForKey:@"id"];
  171. [scheduledIds addObject:id];
  172. }
  173. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  174. messageAsArray:scheduledIds];
  175. [self.commandDelegate sendPluginResult:result
  176. callbackId:command.callbackId];
  177. }];
  178. }
  179. /**
  180. * Schedules a new local notification and fies the coresponding event.
  181. *
  182. * @param {NSMutableDictionary} properties
  183. * The properties of the notification
  184. */
  185. - (void) scheduleNotificationWithProperties:(NSMutableDictionary*)properties
  186. {
  187. UILocalNotification* notification = [self notificationWithProperties:
  188. properties];
  189. NSDictionary* userInfo = notification.userInfo;
  190. NSString* id = [userInfo objectForKey:@"id"];
  191. NSString* json = [userInfo objectForKey:@"json"];
  192. [self fireEvent:@"add" id:id json:json];
  193. [[UIApplication sharedApplication]
  194. scheduleLocalNotification:notification];
  195. }
  196. /**
  197. * Cancels the given local notification
  198. * and fires the cancel event.
  199. *
  200. * @param {NSString} id
  201. * The ID of the local notification
  202. */
  203. - (void) cancelNotification:(UILocalNotification*)notification
  204. fireEvent:(BOOL)fireEvent
  205. {
  206. NSDictionary* userInfo = notification.userInfo;
  207. NSString* id = [userInfo objectForKey:@"id"];
  208. NSString* json = [userInfo objectForKey:@"json"];
  209. [[UIApplication sharedApplication]
  210. cancelLocalNotification:notification];
  211. if (fireEvent) {
  212. [self fireEvent:@"cancel" id:id json:json];
  213. }
  214. }
  215. /**
  216. * Cancels all local notification with are older then
  217. * a specific amount of seconds
  218. *
  219. * @param {float} seconds
  220. * The time interval in seconds
  221. */
  222. - (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
  223. {
  224. NSDate* now = [NSDate date];
  225. NSArray* notifications = self.scheduledNotifications;
  226. for (UILocalNotification* notification in notifications)
  227. {
  228. NSDate* fireDate = notification.fireDate;
  229. NSTimeInterval fireDateDistance = [now timeIntervalSinceDate:
  230. fireDate];
  231. if (notification.repeatInterval == NSEraCalendarUnit
  232. && fireDateDistance > seconds) {
  233. [self cancelNotification:notification fireEvent:YES];
  234. }
  235. }
  236. }
  237. /**
  238. * Retrurns a key-value dictionary for repeat intervals.
  239. *
  240. * @return {NSMutableDictionary}
  241. */
  242. - (NSMutableDictionary*) repeatDict
  243. {
  244. NSMutableDictionary* repeatDict = [[NSMutableDictionary alloc] init];
  245. #ifdef NSCalendarUnitHour
  246. [repeatDict setObject:
  247. [NSNumber numberWithInt:NSCalendarUnitSecond] forKey:@"secondly"];
  248. [repeatDict setObject:
  249. [NSNumber numberWithInt:NSCalendarUnitMinute] forKey:@"minutely"];
  250. [repeatDict setObject:
  251. [NSNumber numberWithInt:NSCalendarUnitHour] forKey:@"hourly"];
  252. [repeatDict setObject:
  253. [NSNumber numberWithInt:NSCalendarUnitDay] forKey:@"daily"];
  254. [repeatDict setObject:
  255. [NSNumber numberWithInt:NSWeekCalendarUnit] forKey:@"weekly"];
  256. [repeatDict setObject:
  257. [NSNumber numberWithInt:NSCalendarUnitMonth] forKey:@"monthly"];
  258. [repeatDict setObject:
  259. [NSNumber numberWithInt:NSCalendarUnitYear] forKey:@"yearly"];
  260. #else
  261. [repeatDict setObject:
  262. [NSNumber numberWithInt:NSSecondCalendarUnit] forKey:@"secondly"];
  263. [repeatDict setObject:
  264. [NSNumber numberWithInt:NSMinuteCalendarUnit] forKey:@"minutely"];
  265. [repeatDict setObject:
  266. [NSNumber numberWithInt:NSHourCalendarUnit] forKey:@"hourly"];
  267. [repeatDict setObject:
  268. [NSNumber numberWithInt:NSDayCalendarUnit] forKey:@"daily"];
  269. [repeatDict setObject:
  270. [NSNumber numberWithInt:NSWeekCalendarUnit] forKey:@"weekly"];
  271. [repeatDict setObject:
  272. [NSNumber numberWithInt:NSMonthCalendarUnit] forKey:@"monthly"];
  273. [repeatDict setObject:
  274. [NSNumber numberWithInt:NSYearCalendarUnit] forKey:@"yearly"];
  275. #endif
  276. [repeatDict setObject:
  277. [NSNumber numberWithInt:NSEraCalendarUnit] forKey:@""];
  278. return repeatDict;
  279. }
  280. /**
  281. * Returns the userDict for a local notification.
  282. *
  283. * @param {NSMutableDictionary} options
  284. * The properties for the local notification
  285. * @return {NSDictionary}
  286. */
  287. - (NSDictionary*) userDict:(NSMutableDictionary*)options
  288. {
  289. NSString* id = [options objectForKey:@"id"];
  290. NSString* ac = [options objectForKey:@"autoCancel"];
  291. NSString* js = [options objectForKey:@"json"];
  292. return [NSDictionary dictionaryWithObjectsAndKeys:
  293. id, @"id", ac, @"autoCancel", js, @"json", nil];
  294. }
  295. /**
  296. * Creates an notification object based on the given properties.
  297. *
  298. * @param {NSMutableDictionary} properties
  299. * The properties for the local notification
  300. * @return {UILocalNotification}
  301. */
  302. - (UILocalNotification*) notificationWithProperties:(NSMutableDictionary*)options
  303. {
  304. UILocalNotification* notification = [[UILocalNotification alloc] init];
  305. double timestamp = [[options objectForKey:@"date"] doubleValue];
  306. NSString* msg = [options objectForKey:@"message"];
  307. NSString* title = [options objectForKey:@"title"];
  308. NSString* sound = [options objectForKey:@"sound"];
  309. NSString* repeat = [options objectForKey:@"repeat"];
  310. NSInteger badge = [[options objectForKey:@"badge"] intValue];
  311. notification.fireDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
  312. notification.timeZone = [NSTimeZone defaultTimeZone];
  313. notification.userInfo = [self userDict:options];
  314. notification.applicationIconBadgeNumber = badge;
  315. notification.repeatInterval = [[[self repeatDict] objectForKey:repeat]
  316. intValue];
  317. if (![self stringIsNullOrEmpty:msg])
  318. {
  319. if (![self stringIsNullOrEmpty:title]) {
  320. notification.alertBody = [NSString stringWithFormat:
  321. @"%@\n%@", title, msg];
  322. } else {
  323. notification.alertBody = msg;
  324. }
  325. }
  326. if (sound != (NSString*)[NSNull null])
  327. {
  328. if ([sound isEqualToString:@""]) {
  329. notification.soundName = UILocalNotificationDefaultSoundName;
  330. } else {
  331. notification.soundName = sound;
  332. }
  333. }
  334. return notification;
  335. }
  336. /**
  337. * Calls the cancel or trigger event after a local notification was received.
  338. * Cancels the local notification if autoCancel was set to true.
  339. */
  340. - (void) didReceiveLocalNotification:(NSNotification*)localNotification
  341. {
  342. UILocalNotification* notification = [localNotification object];
  343. NSDictionary* userInfo = notification.userInfo;
  344. NSString* id = [userInfo objectForKey:@"id"];
  345. NSString* json = [userInfo objectForKey:@"json"];
  346. BOOL autoCancel = [[userInfo objectForKey:@"autoCancel"] boolValue];
  347. NSDate* now = [NSDate date];
  348. NSDate* fireDate = notification.fireDate;
  349. NSTimeInterval fireDateDistance = [now timeIntervalSinceDate:fireDate];
  350. NSString* event = (fireDateDistance < 1) ? @"trigger" : @"click";
  351. if (autoCancel && [event isEqualToString:@"click"]) {
  352. [self cancelNotification:notification fireEvent:YES];
  353. }
  354. [self fireEvent:event id:id json:json];
  355. }
  356. /**
  357. * Calls the cancel or trigger event after a local notification was received.
  358. */
  359. - (void) didFinishLaunchingWithOptions:(NSNotification*)notification
  360. {
  361. NSDictionary* launchOptions = [notification userInfo];
  362. UILocalNotification* localNotification = [launchOptions objectForKey:
  363. UIApplicationLaunchOptionsLocalNotificationKey];
  364. if (localNotification) {
  365. [self didReceiveLocalNotification:
  366. [NSNotification notificationWithName:CDVLocalNotification
  367. object:localNotification]];
  368. }
  369. }
  370. /**
  371. * Registers obervers for the following events after plugin was initialized.
  372. * didReceiveLocalNotification:
  373. * didFinishLaunchingWithOptions:
  374. */
  375. - (void) pluginInitialize
  376. {
  377. NSNotificationCenter* notificationCenter = [NSNotificationCenter
  378. defaultCenter];
  379. eventQueue = [[NSMutableArray alloc] init];
  380. [notificationCenter addObserver:self
  381. selector:@selector(didReceiveLocalNotification:)
  382. name:CDVLocalNotification
  383. object:nil];
  384. [notificationCenter addObserver:self
  385. selector:@selector(didFinishLaunchingWithOptions:)
  386. name:UIApplicationDidFinishLaunchingNotification
  387. object:nil];
  388. }
  389. /**
  390. * Clears all single repeating notifications which are older then 5 days
  391. * before the app terminates.
  392. */
  393. - (void) onAppTerminate
  394. {
  395. [self cancelAllNotificationsWhichAreOlderThen:432000];
  396. }
  397. /**
  398. * Checks weather the given string is empty or not.
  399. *
  400. * @param {NSString} str The string to be check
  401. * @return {BOOL}
  402. */
  403. - (BOOL) stringIsNullOrEmpty:(NSString*)str
  404. {
  405. if (str == (NSString*)[NSNull null]) {
  406. return YES;
  407. }
  408. if ([str isEqualToString:@""]) {
  409. return YES;
  410. }
  411. return NO;
  412. }
  413. /**
  414. * Checks wether a notification with an ID is scheduled or not.
  415. *
  416. * @param id
  417. * The ID of the notification
  418. * @return BOOL
  419. */
  420. - (BOOL) isNotificationScheduledWithId:(NSString*)id
  421. {
  422. UILocalNotification* notification = [self notificationWithId:id];
  423. return notification != NULL;
  424. }
  425. /**
  426. * Retrieves the local notification by its ID.
  427. *
  428. * @param {NSString} id
  429. * The ID of the notification
  430. * @return UILocalNotification*
  431. */
  432. - (UILocalNotification*) notificationWithId:(NSString*)id
  433. {
  434. NSArray* notifications = self.scheduledNotifications;
  435. for (UILocalNotification* notification in notifications)
  436. {
  437. NSString* notId = [notification.userInfo objectForKey:@"id"];
  438. if ([notId isEqualToString:id]) {
  439. return notification;
  440. }
  441. }
  442. return NULL;
  443. }
  444. /**
  445. * Retrieves the application state
  446. *
  447. * @return {NSString}
  448. * Either "background" or "foreground"
  449. */
  450. - (NSString*) applicationState
  451. {
  452. UIApplicationState state = [[UIApplication sharedApplication]
  453. applicationState];
  454. bool isActive = state == UIApplicationStateActive;
  455. return isActive ? @"foreground" : @"background";
  456. }
  457. /**
  458. * Retrieves all scheduled notifications.
  459. *
  460. * @return {NSArray}
  461. * A list of all scheduled local notifications
  462. */
  463. - (NSArray*) scheduledNotifications
  464. {
  465. NSMutableArray* notificationsWithoutNIL = [[NSMutableArray alloc]
  466. init];
  467. NSArray* notifications = [[UIApplication sharedApplication]
  468. scheduledLocalNotifications];
  469. for (UILocalNotification* notification in notifications)
  470. {
  471. if (notification) {
  472. [notificationsWithoutNIL addObject:notification];
  473. }
  474. }
  475. return notificationsWithoutNIL;
  476. }
  477. /**
  478. * Simply invokes the callback without any parameter.
  479. */
  480. - (void) execCallback:(CDVInvokedUrlCommand*)command
  481. {
  482. CDVPluginResult *result = [CDVPluginResult
  483. resultWithStatus:CDVCommandStatus_OK];
  484. [self.commandDelegate sendPluginResult:result
  485. callbackId:command.callbackId];
  486. }
  487. /**
  488. * Fires the given event.
  489. *
  490. * @param {NSString} event
  491. * The Name of the event
  492. * @param {NSString} id
  493. * The ID of the notification
  494. * @param {NSString} json
  495. * A custom (JSON) string
  496. */
  497. - (void) fireEvent:(NSString*)event id:(NSString*)id json:(NSString*)json
  498. {
  499. NSString* appState = self.applicationState;
  500. NSString* params = [NSString stringWithFormat:
  501. @"\"%@\",\"%@\",\\'%@\\'",
  502. id, appState, json];
  503. NSString* js = [NSString stringWithFormat:
  504. @"setTimeout('plugin.notification.local.on%@(%@)',0)",
  505. event, params];
  506. if (deviceready) {
  507. [self.commandDelegate evalJs:js];
  508. } else {
  509. [self.eventQueue addObject:js];
  510. }
  511. }
  512. @end