APPLocalNotification.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. /*
  2. * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
  3. *
  4. * @APPPLANT_LICENSE_HEADER_START@
  5. *
  6. * This file contains Original Code and/or Modifications of Original Code
  7. * as defined in and that are subject to the Apache License
  8. * Version 2.0 (the 'License'). You may not use this file except in
  9. * compliance with the License. Please obtain a copy of the License at
  10. * http://opensource.org/licenses/Apache-2.0/ and read it before using this
  11. * file.
  12. *
  13. * The Original Code and all software distributed under the License are
  14. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18. * Please see the License for the specific language governing rights and
  19. * limitations under the License.
  20. *
  21. * @APPPLANT_LICENSE_HEADER_END@
  22. */
  23. #import "APPLocalNotification.h"
  24. #import "APPLocalNotificationOptions.h"
  25. #import "UNUserNotificationCenter+APPLocalNotification.h"
  26. #import "UNNotificationRequest+APPLocalNotification.h"
  27. #import "UNMutableNotificationContent+APPLocalNotification.h"
  28. #import "APPLocalNotificationOptions.ios9.h"
  29. #import "UIApplication+APPLocalNotification.ios9.h"
  30. #import "UILocalNotification+APPLocalNotification.ios9.h"
  31. #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
  32. @interface APPLocalNotification ()
  33. // Property reader for [self app]
  34. @property (readonly, getter=app) UIApplication* app;
  35. // Property reader for [self center]
  36. @property (readonly, getter=center) UNUserNotificationCenter* center;
  37. // All events will be queued until deviceready has been fired
  38. @property (readwrite, assign) BOOL deviceready;
  39. // Event queue
  40. @property (readonly, nonatomic, retain) NSMutableArray* eventQueue;
  41. // IOS9: TODO remove later
  42. @property (nonatomic, retain) CDVInvokedUrlCommand* command;
  43. @end
  44. @implementation APPLocalNotification
  45. @synthesize deviceready, eventQueue;
  46. #pragma mark -
  47. #pragma mark Interface
  48. /**
  49. * Execute all queued events.
  50. */
  51. - (void) deviceready:(CDVInvokedUrlCommand*)command
  52. {
  53. deviceready = YES;
  54. for (NSString* js in eventQueue) {
  55. [self.commandDelegate evalJs:js];
  56. }
  57. [eventQueue removeAllObjects];
  58. }
  59. /**
  60. * Schedule a set of notifications.
  61. *
  62. * @param properties
  63. * A dict of properties for each notification
  64. */
  65. - (void) schedule:(CDVInvokedUrlCommand*)command
  66. {
  67. NSArray* notifications = command.arguments;
  68. [self.commandDelegate runInBackground:^{
  69. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  70. for (NSDictionary* options in notifications) {
  71. UNMutableNotificationContent* notification;
  72. notification = [[UNMutableNotificationContent alloc]
  73. initWithOptions:options];
  74. [self scheduleNotification:notification];
  75. //[self fireEvent:@"add" notification:notification];
  76. }
  77. } else {
  78. for (NSDictionary* options in notifications) {
  79. UILocalNotification* notification;
  80. notification = [[UILocalNotification alloc]
  81. initWithOptions:options];
  82. [self scheduleLocalNotification:[notification copy]];
  83. [self fireEvent:@"schedule" localnotification:notification];
  84. if (notifications.count > 1) {
  85. [NSThread sleepForTimeInterval:0.01];
  86. }
  87. }
  88. }
  89. [self execCallback:command];
  90. }];
  91. }
  92. /**
  93. * Update a set of notifications.
  94. *
  95. * @param properties
  96. * A dict of properties for each notification
  97. */
  98. - (void) update:(CDVInvokedUrlCommand*)command
  99. {
  100. NSArray* notifications = command.arguments;
  101. [self.commandDelegate runInBackground:^{
  102. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  103. for (NSDictionary* options in notifications) {
  104. NSNumber* id = [options objectForKey:@"id"];
  105. UNNotificationRequest* notification;
  106. notification = [self.center getNotificationWithId:id];
  107. if (!notification)
  108. continue;
  109. // [self updateNotification:[notification copy]
  110. // withOptions:options];
  111. //
  112. // [self fireEvent:@"update" notification:notification];
  113. //
  114. // if (notifications.count > 1) {
  115. // [NSThread sleepForTimeInterval:0.01];
  116. // }
  117. }
  118. } else {
  119. for (NSDictionary* options in notifications) {
  120. NSNumber* id = [options objectForKey:@"id"];
  121. UILocalNotification* notification;
  122. notification = [self.app localNotificationWithId:id];
  123. if (!notification)
  124. continue;
  125. [self updateLocalNotification:[notification copy]
  126. withOptions:options];
  127. [self fireEvent:@"update" localnotification:notification];
  128. if (notifications.count > 1) {
  129. [NSThread sleepForTimeInterval:0.01];
  130. }
  131. }
  132. }
  133. [self execCallback:command];
  134. }];
  135. }
  136. /**
  137. * Cancel a set of notifications.
  138. *
  139. * @param ids
  140. * The IDs of the notifications
  141. */
  142. - (void) cancel:(CDVInvokedUrlCommand*)command
  143. {
  144. [self.commandDelegate runInBackground:^{
  145. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  146. for (NSNumber* id in command.arguments) {
  147. UNNotificationRequest* notification;
  148. notification = [self.center getNotificationWithId:id];
  149. if (!notification)
  150. continue;
  151. [self.center cancelNotification:notification];
  152. [self fireEvent:@"cancel" notification:notification];
  153. }
  154. } else {
  155. for (NSNumber* id in command.arguments) {
  156. UILocalNotification* notification;
  157. notification = [self.app localNotificationWithId:id];
  158. if (!notification)
  159. continue;
  160. [self.app cancelLocalNotification:notification];
  161. [self fireEvent:@"cancel" localnotification:notification];
  162. }
  163. }
  164. [self execCallback:command];
  165. }];
  166. }
  167. /**
  168. * Cancel all local notifications.
  169. */
  170. - (void) cancelAll:(CDVInvokedUrlCommand*)command
  171. {
  172. [self.commandDelegate runInBackground:^{
  173. [self cancelAllNotifications];
  174. [self fireEvent:@"cancelall"];
  175. [self execCallback:command];
  176. }];
  177. }
  178. /**
  179. * Clear a set of notifications.
  180. *
  181. * @param ids
  182. * The IDs of the notifications
  183. */
  184. - (void) clear:(CDVInvokedUrlCommand*)command
  185. {
  186. [self.commandDelegate runInBackground:^{
  187. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  188. for (NSNumber* id in command.arguments) {
  189. UNNotificationRequest* notification;
  190. notification = [self.center getNotificationWithId:id];
  191. if (!notification)
  192. continue;
  193. [self.center clearNotification:notification];
  194. [self fireEvent:@"clear" notification:notification];
  195. }
  196. } else {
  197. for (NSNumber* id in command.arguments) {
  198. UILocalNotification* notification;
  199. notification = [self.app localNotificationWithId:id];
  200. if (!notification)
  201. continue;
  202. [self.app clearLocalNotification:notification];
  203. [self fireEvent:@"clear" localnotification:notification];
  204. }
  205. }
  206. [self execCallback:command];
  207. }];
  208. }
  209. /**
  210. * Clear all local notifications.
  211. */
  212. - (void) clearAll:(CDVInvokedUrlCommand*)command
  213. {
  214. [self.commandDelegate runInBackground:^{
  215. [self clearAllNotifications];
  216. [self fireEvent:@"clearall"];
  217. [self execCallback:command];
  218. }];
  219. }
  220. /**
  221. * If a notification by ID is present.
  222. *
  223. * @param id
  224. * The ID of the notification
  225. */
  226. - (void) isPresent:(CDVInvokedUrlCommand *)command
  227. {
  228. [self isPresent:command type:NotifcationTypeAll];
  229. }
  230. /**
  231. * If a notification by ID is scheduled.
  232. *
  233. * @param id
  234. * The ID of the notification
  235. */
  236. - (void) isScheduled:(CDVInvokedUrlCommand*)command
  237. {
  238. [self isPresent:command type:NotifcationTypeScheduled];
  239. }
  240. /**
  241. * Check if a notification with an ID is triggered.
  242. *
  243. * @param id
  244. * The ID of the notification
  245. */
  246. - (void) isTriggered:(CDVInvokedUrlCommand*)command
  247. {
  248. [self isPresent:command type:NotifcationTypeTriggered];
  249. }
  250. /**
  251. * Check if a notification with an ID exists.
  252. *
  253. * @param type
  254. * The notification life cycle type
  255. */
  256. - (void) isPresent:(CDVInvokedUrlCommand*)command
  257. type:(APPNotificationType)type;
  258. {
  259. [self.commandDelegate runInBackground:^{
  260. NSNumber* id = [command argumentAtIndex:0];
  261. BOOL exist;
  262. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  263. exist = [self.center notificationExist:id type:type];
  264. } else {
  265. if (type == NotifcationTypeAll) {
  266. exist = [self.app localNotificationExist:id];
  267. } else {
  268. exist = [self.app localNotificationExist:id type:type];
  269. }
  270. }
  271. CDVPluginResult* result;
  272. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  273. messageAsBool:exist];
  274. [self.commandDelegate sendPluginResult:result
  275. callbackId:command.callbackId];
  276. }];
  277. }
  278. /**
  279. * List all ids from all local notifications.
  280. */
  281. - (void) getAllIds:(CDVInvokedUrlCommand*)command
  282. {
  283. [self getIds:command byType:NotifcationTypeAll];
  284. }
  285. /**
  286. * List all ids from all pending notifications.
  287. */
  288. - (void) getScheduledIds:(CDVInvokedUrlCommand*)command
  289. {
  290. [self getIds:command byType:NotifcationTypeScheduled];
  291. }
  292. /**
  293. * List all ids from all triggered notifications.
  294. */
  295. - (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
  296. {
  297. [self getIds:command byType:NotifcationTypeTriggered];
  298. }
  299. /**
  300. * List of ids for given local notifications.
  301. *
  302. * @param type
  303. * Notification life cycle type
  304. * @param ids
  305. * The IDs of the notifications
  306. */
  307. - (void) getIds:(CDVInvokedUrlCommand*)command
  308. byType:(APPNotificationType)type;
  309. {
  310. [self.commandDelegate runInBackground:^{
  311. NSArray* ids;
  312. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  313. ids = [self.center getNotificationIdsByType:type];
  314. } else {
  315. if (type == NotifcationTypeAll) {
  316. ids = [self.app localNotificationIds];
  317. } else {
  318. ids = [self.app localNotificationIdsByType:type];
  319. }
  320. }
  321. CDVPluginResult* result;
  322. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  323. messageAsArray:ids];
  324. [self.commandDelegate sendPluginResult:result
  325. callbackId:command.callbackId];
  326. }];
  327. }
  328. /**
  329. * Propertys for given local notification.
  330. */
  331. - (void) getSingle:(CDVInvokedUrlCommand*)command
  332. {
  333. [self getOption:command byType:NotifcationTypeAll];
  334. }
  335. /**
  336. * Propertya for given scheduled notification.
  337. */
  338. - (void) getSingleScheduled:(CDVInvokedUrlCommand*)command
  339. {
  340. [self getOption:command byType:NotifcationTypeScheduled];
  341. }
  342. // Propertys for given triggered notification
  343. - (void) getSingleTriggered:(CDVInvokedUrlCommand*)command
  344. {
  345. [self getOption:command byType:NotifcationTypeTriggered];
  346. }
  347. /**
  348. * Property list for given local notifications.
  349. *
  350. * @param ids
  351. * The IDs of the notifications
  352. */
  353. - (void) getAll:(CDVInvokedUrlCommand*)command
  354. {
  355. [self getOptions:command byType:NotifcationTypeAll];
  356. }
  357. /**
  358. * Property list for given scheduled notifications.
  359. *
  360. * @param ids
  361. * The IDs of the notifications
  362. */
  363. - (void) getScheduled:(CDVInvokedUrlCommand*)command
  364. {
  365. [self getOptions:command byType:NotifcationTypeScheduled];
  366. }
  367. /**
  368. * Property list for given triggered notifications.
  369. *
  370. * @param ids
  371. * The IDs of the notifications
  372. */
  373. - (void) getTriggered:(CDVInvokedUrlCommand *)command
  374. {
  375. [self getOptions:command byType:NotifcationTypeTriggered];
  376. }
  377. /**
  378. * Propertys for given triggered notification.
  379. *
  380. * @param type
  381. * Notification life cycle type
  382. * @param ids
  383. * The ID of the notification
  384. */
  385. - (void) getOption:(CDVInvokedUrlCommand*)command
  386. byType:(APPNotificationType)type;
  387. {
  388. [self.commandDelegate runInBackground:^{
  389. NSArray* ids = command.arguments;
  390. NSArray* notifications;
  391. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  392. notifications = [self.center getNotificationOptionsByType:type
  393. andId:ids];
  394. } else {
  395. if (type == NotifcationTypeAll) {
  396. notifications = [self.app localNotificationOptionsById:ids];
  397. }
  398. else {
  399. notifications = [self.app localNotificationOptionsByType:type
  400. andId:ids];
  401. }
  402. }
  403. CDVPluginResult* result;
  404. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  405. messageAsDictionary:[notifications firstObject]];
  406. [self.commandDelegate sendPluginResult:result
  407. callbackId:command.callbackId];
  408. }];
  409. }
  410. /**
  411. * Property list for given triggered notifications.
  412. *
  413. * @param type
  414. * Notification life cycle type
  415. * @param ids
  416. * The IDs of the notifications
  417. */
  418. - (void) getOptions:(CDVInvokedUrlCommand*)command
  419. byType:(APPNotificationType)type;
  420. {
  421. [self.commandDelegate runInBackground:^{
  422. NSArray* ids = command.arguments;
  423. NSArray* notifications;
  424. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  425. if (type == NotifcationTypeAll && ids.count == 0) {
  426. notifications = [self.center getNotificationOptions];
  427. }
  428. else if (type == NotifcationTypeAll) {
  429. notifications = [self.center getNotificationOptionsById:ids];
  430. }
  431. else if (ids.count == 0) {
  432. notifications = [self.center getNotificationOptionsByType:type];
  433. }
  434. else {
  435. notifications = [self.center getNotificationOptionsByType:type
  436. andId:ids];
  437. }
  438. } else {
  439. if (type == NotifcationTypeAll && ids.count == 0) {
  440. notifications = [self.app localNotificationOptions];
  441. }
  442. else if (type == NotifcationTypeAll) {
  443. notifications = [self.app localNotificationOptionsById:ids];
  444. }
  445. else if (ids.count == 0) {
  446. notifications = [self.app localNotificationOptionsByType:type];
  447. }
  448. else {
  449. notifications = [self.app localNotificationOptionsByType:type
  450. andId:ids];
  451. }
  452. }
  453. CDVPluginResult* result;
  454. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  455. messageAsArray:notifications];
  456. [self.commandDelegate sendPluginResult:result
  457. callbackId:command.callbackId];
  458. }];
  459. }
  460. /**
  461. * Inform if the app has the permission to show
  462. * badges and local notifications.
  463. */
  464. - (void) hasPermission:(CDVInvokedUrlCommand*)command
  465. {
  466. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  467. [self.commandDelegate runInBackground:^{
  468. [self.center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings* settings) {
  469. BOOL authorized = settings.authorizationStatus == UNAuthorizationStatusAuthorized;
  470. BOOL enabled = settings.notificationCenterSetting == UNNotificationSettingEnabled;
  471. BOOL permitted = authorized && enabled;
  472. CDVPluginResult* result;
  473. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  474. messageAsBool:permitted];
  475. [self.commandDelegate sendPluginResult:result
  476. callbackId:command.callbackId];
  477. }];
  478. }];
  479. } else {
  480. [self.commandDelegate runInBackground:^{
  481. CDVPluginResult* result;
  482. BOOL hasPermission;
  483. hasPermission = [self.app hasPermissionToScheduleLocalNotifications];
  484. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  485. messageAsBool:hasPermission];
  486. [self.commandDelegate sendPluginResult:result
  487. callbackId:command.callbackId];
  488. }];
  489. }
  490. }
  491. /**
  492. * Ask for permission to show badges.
  493. */
  494. - (void) registerPermission:(CDVInvokedUrlCommand*)command
  495. {
  496. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  497. [self.commandDelegate runInBackground:^{
  498. UNAuthorizationOptions options =
  499. (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert);
  500. [self.center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError* e) {
  501. [self hasPermission:command];
  502. }];
  503. }];
  504. } else {
  505. if ([[UIApplication sharedApplication]
  506. respondsToSelector:@selector(registerUserNotificationSettings:)])
  507. {
  508. _command = command;
  509. [self.commandDelegate runInBackground:^{
  510. [self.app registerPermissionToScheduleLocalNotifications];
  511. }];
  512. } else {
  513. [self hasPermission:command];
  514. }
  515. }
  516. }
  517. #pragma mark -
  518. #pragma mark Core Logic
  519. /**
  520. * Schedule the local notification.
  521. */
  522. - (void) scheduleNotification:(UNMutableNotificationContent*)notification
  523. {
  524. [self.center addNotificationRequest:notification.request
  525. withCompletionHandler:^(NSError* e) {
  526. [self fireEvent:@"add" notification:notification.request];
  527. }];
  528. }
  529. /**
  530. * Update the local notification.
  531. */
  532. - (void) updateNotification:(UILocalNotification*)notification
  533. withOptions:(NSDictionary*)newOptions
  534. {
  535. NSMutableDictionary* options = [notification.userInfo mutableCopy];
  536. [options addEntriesFromDictionary:newOptions];
  537. [options setObject:[NSDate date] forKey:@"updatedAt"];
  538. // notification = [[UILocalNotification alloc]
  539. // initWithOptions:options];
  540. //
  541. // [self scheduleLocalNotification:notification];
  542. }
  543. /**
  544. * Cancel all local notifications.
  545. */
  546. - (void) cancelAllNotifications
  547. {
  548. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  549. [self.center cancelAllNotifications];
  550. } else {
  551. [self.app cancelAllLocalNotifications];
  552. }
  553. [self.app setApplicationIconBadgeNumber:0];
  554. }
  555. /**
  556. * Clear all local notifications.
  557. */
  558. - (void) clearAllNotifications
  559. {
  560. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  561. [self.center clearAllNotifications];
  562. } else {
  563. [self.app clearAllLocalNotifications];
  564. }
  565. [self.app setApplicationIconBadgeNumber:0];
  566. }
  567. #pragma mark -
  568. #pragma mark Delegates
  569. /**
  570. * Called when a notification is delivered to a foreground app.
  571. */
  572. - (void) userNotificationCenter:(UNUserNotificationCenter *)center
  573. willPresentNotification:(UNNotification *)notification
  574. withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
  575. {
  576. [self fireEvent:@"trigger" notification:notification.request];
  577. completionHandler(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert);
  578. }
  579. /**
  580. * Called to let your app know which action was selected by the user for a given
  581. * notification.
  582. */
  583. - (void) userNotificationCenter:(UNUserNotificationCenter *)center
  584. didReceiveNotificationResponse:(UNNotificationResponse *)response
  585. withCompletionHandler:(void (^)())completionHandler
  586. {
  587. UNNotificationRequest* notification = response.notification.request;
  588. [self fireEvent:@"click" notification:notification];
  589. if ([notification.options isRepeating]) {
  590. [self.center clearNotification:notification];
  591. [self fireEvent:@"clear" notification:notification];
  592. } else {
  593. [self.center cancelNotification:notification];
  594. [self fireEvent:@"cancel" notification:notification];
  595. }
  596. completionHandler();
  597. }
  598. #pragma mark -
  599. #pragma mark Life Cycle
  600. /**
  601. * Registers obervers after plugin was initialized.
  602. */
  603. - (void) pluginInitialize
  604. {
  605. eventQueue = [[NSMutableArray alloc] init];
  606. self.center.delegate = self;
  607. }
  608. #pragma mark -
  609. #pragma mark Helper
  610. /**
  611. * Retrieves the application state
  612. *
  613. * @return
  614. * Either "background" or "foreground"
  615. */
  616. - (NSString*) applicationState
  617. {
  618. UIApplicationState state = [self.app applicationState];
  619. bool isActive = state == UIApplicationStateActive;
  620. return isActive ? @"foreground" : @"background";
  621. }
  622. /**
  623. * Simply invokes the callback without any parameter.
  624. */
  625. - (void) execCallback:(CDVInvokedUrlCommand*)command
  626. {
  627. CDVPluginResult *result = [CDVPluginResult
  628. resultWithStatus:CDVCommandStatus_OK];
  629. [self.commandDelegate sendPluginResult:result
  630. callbackId:command.callbackId];
  631. }
  632. /**
  633. * Short hand for shared application instance.
  634. */
  635. - (UIApplication*) app
  636. {
  637. return [UIApplication sharedApplication];
  638. }
  639. /**
  640. * Short hand for current notification center.
  641. */
  642. - (UNUserNotificationCenter*) center
  643. {
  644. return [UNUserNotificationCenter currentNotificationCenter];
  645. }
  646. /**
  647. * Fire general event.
  648. */
  649. - (void) fireEvent:(NSString*)event
  650. {
  651. [self fireEvent:event notification:NULL];
  652. }
  653. /**
  654. * Fire event for local notification.
  655. */
  656. - (void) fireEvent:(NSString*)event
  657. notification:(UNNotificationRequest*)notification
  658. {
  659. NSString* js;
  660. NSString* appState = [self applicationState];
  661. NSString* params = [NSString stringWithFormat:@"\"%@\"", appState];
  662. if (notification) {
  663. NSString* args = [notification encodeToJSON];
  664. params = [NSString stringWithFormat:@"%@,'%@'", args, appState];
  665. }
  666. js = [NSString stringWithFormat:
  667. @"cordova.plugins.notification.local.core.fireEvent('%@', %@)",
  668. event, params];
  669. if (deviceready) {
  670. [self.commandDelegate evalJs:js];
  671. } else {
  672. [self.eventQueue addObject:js];
  673. }
  674. }
  675. #pragma mark -
  676. #pragma mark ios 9
  677. /**
  678. * Schedule the local notification.
  679. */
  680. - (void) scheduleLocalNotification:(UILocalNotification*)notification
  681. {
  682. [self cancelForerunnerLocalNotification:notification];
  683. [self.app scheduleLocalNotification:notification];
  684. }
  685. /**
  686. * Update the local notification.
  687. */
  688. - (void) updateLocalNotification:(UILocalNotification*)notification
  689. withOptions:(NSDictionary*)newOptions
  690. {
  691. NSMutableDictionary* options = [notification.userInfo mutableCopy];
  692. [options addEntriesFromDictionary:newOptions];
  693. [options setObject:[NSDate date] forKey:@"updatedAt"];
  694. notification = [[UILocalNotification alloc]
  695. initWithOptions:options];
  696. [self scheduleLocalNotification:notification];
  697. }
  698. /**
  699. * Cancel a maybe given forerunner with the same ID.
  700. */
  701. - (void) cancelForerunnerLocalNotification:(UILocalNotification*)notification
  702. {
  703. NSNumber* id = notification.options.id;
  704. UILocalNotification* forerunner;
  705. forerunner = [self.app localNotificationWithId:id];
  706. if (!forerunner)
  707. return;
  708. [self.app cancelLocalNotification:forerunner];
  709. }
  710. /**
  711. * Cancels all non-repeating local notification older then
  712. * a specific amount of seconds
  713. */
  714. - (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
  715. {
  716. NSArray* notifications;
  717. notifications = [self.app localNotifications];
  718. for (UILocalNotification* notification in notifications)
  719. {
  720. if (![notification isRepeating]
  721. && notification.timeIntervalSinceFireDate > seconds)
  722. {
  723. [self.app cancelLocalNotification:notification];
  724. [self fireEvent:@"cancel" localnotification:notification];
  725. }
  726. }
  727. }
  728. /**
  729. * Calls the cancel or trigger event after a local notification was received.
  730. * Cancels the local notification if autoCancel was set to true.
  731. */
  732. - (void) didReceiveLocalNotification:(NSNotification*)localNotification
  733. {
  734. UILocalNotification* notification = [localNotification object];
  735. if ([notification userInfo] == NULL || [notification wasUpdated])
  736. return;
  737. NSTimeInterval timeInterval = [notification timeIntervalSinceLastTrigger];
  738. NSString* event = timeInterval < 0.2 && deviceready ? @"trigger" : @"click";
  739. [self fireEvent:event localnotification:notification];
  740. if (![event isEqualToString:@"click"])
  741. return;
  742. if ([notification isRepeating]) {
  743. [self fireEvent:@"clear" localnotification:notification];
  744. } else {
  745. [self.app cancelLocalNotification:notification];
  746. [self fireEvent:@"cancel" localnotification:notification];
  747. }
  748. }
  749. /**
  750. * Called when app has started
  751. * (by clicking on a local notification).
  752. */
  753. - (void) didFinishLaunchingWithOptions:(NSNotification*)notification
  754. {
  755. NSDictionary* launchOptions = [notification userInfo];
  756. UILocalNotification* localNotification;
  757. localNotification = [launchOptions objectForKey:
  758. UIApplicationLaunchOptionsLocalNotificationKey];
  759. if (localNotification) {
  760. [self didReceiveLocalNotification:
  761. [NSNotification notificationWithName:CDVLocalNotification
  762. object:localNotification]];
  763. }
  764. }
  765. /**
  766. * Called on notification settings registration is completed.
  767. */
  768. - (void) didRegisterUserNotificationSettings:(UIUserNotificationSettings*)settings
  769. {
  770. if (_command) {
  771. [self hasPermission:_command];
  772. _command = NULL;
  773. }
  774. }
  775. /**
  776. * Cancels all single non-repeating notifications which are older then 5 days
  777. * before the app terminates.
  778. */
  779. - (void) onAppTerminate
  780. {
  781. [self cancelAllNotificationsWhichAreOlderThen:432000];
  782. }
  783. /**
  784. * Fire event for local notification.
  785. */
  786. - (void) fireEvent:(NSString*)event localnotification:(UILocalNotification*)notification
  787. {
  788. NSString* js;
  789. NSString* params = [NSString stringWithFormat:
  790. @"\"%@\"", self.applicationState];
  791. if (notification) {
  792. NSString* args = [notification encodeToJSON];
  793. params = [NSString stringWithFormat:
  794. @"%@,'%@'",
  795. args, self.applicationState];
  796. }
  797. js = [NSString stringWithFormat:
  798. @"cordova.plugins.notification.local.core.fireEvent('%@', %@)",
  799. event, params];
  800. if (deviceready) {
  801. [self.commandDelegate evalJs:js];
  802. } else {
  803. [self.eventQueue addObject:js];
  804. }
  805. }
  806. @end