APPLocalNotification.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Copyright (c) 2013 by appPlant GmbH. 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 "APPNotificationOptions.h"
  25. #import "UNUserNotificationCenter+APPLocalNotification.h"
  26. #import "UNNotificationRequest+APPLocalNotification.h"
  27. #import "APPNotificationContent.h"
  28. @interface APPLocalNotification ()
  29. @property (strong, nonatomic) UIApplication* app;
  30. @property (strong, nonatomic) UNUserNotificationCenter* center;
  31. @property (readwrite, assign) BOOL deviceready;
  32. @property (readonly, nonatomic, retain) NSMutableArray* eventQueue;
  33. @end
  34. @implementation APPLocalNotification
  35. @synthesize deviceready, eventQueue;
  36. #pragma mark -
  37. #pragma mark Interface
  38. /**
  39. * Execute all queued events.
  40. *
  41. * @return [ Void ]
  42. */
  43. - (void) deviceready:(CDVInvokedUrlCommand*)command
  44. {
  45. deviceready = YES;
  46. for (NSString* js in eventQueue) {
  47. [self.commandDelegate evalJs:js];
  48. }
  49. [eventQueue removeAllObjects];
  50. }
  51. /**
  52. * Schedule notifications.
  53. *
  54. * @param [Array<Hash>] properties A list of key-value properties.
  55. *
  56. * @return [ Void ]
  57. */
  58. - (void) schedule:(CDVInvokedUrlCommand*)command
  59. {
  60. NSArray* notifications = command.arguments;
  61. [self.commandDelegate runInBackground:^{
  62. for (NSDictionary* options in notifications) {
  63. APPNotificationContent* notification;
  64. notification = [[APPNotificationContent alloc]
  65. initWithOptions:options];
  66. [self scheduleNotification:notification];
  67. }
  68. [self execCallback:command];
  69. }];
  70. }
  71. ///**
  72. // * Update a set of notifications.
  73. // *
  74. // * @param properties
  75. // * A dict of properties for each notification
  76. // */
  77. //- (void) update:(CDVInvokedUrlCommand*)command
  78. //{
  79. // NSArray* notifications = command.arguments;
  80. //
  81. // [self.commandDelegate runInBackground:^{
  82. // if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
  83. // for (NSDictionary* options in notifications) {
  84. // NSNumber* id = [options objectForKey:@"id"];
  85. // UNNotificationRequest* notification;
  86. //
  87. // notification = [self.center getNotificationWithId:id];
  88. //
  89. // if (!notification)
  90. // continue;
  91. //
  92. // // [self updateNotification:[notification copy]
  93. // // withOptions:options];
  94. // //
  95. // // [self fireEvent:@"update" notification:notification];
  96. // //
  97. // // if (notifications.count > 1) {
  98. // // [NSThread sleepForTimeInterval:0.01];
  99. // // }
  100. // }
  101. // } else {
  102. // for (NSDictionary* options in notifications) {
  103. // NSNumber* id = [options objectForKey:@"id"];
  104. // UILocalNotification* notification;
  105. //
  106. // notification = [self.app localNotificationWithId:id];
  107. //
  108. // if (!notification)
  109. // continue;
  110. //
  111. // [self updateLocalNotification:[notification copy]
  112. // withOptions:options];
  113. //
  114. // [self fireEvent:@"update" localnotification:notification];
  115. //
  116. // if (notifications.count > 1) {
  117. // [NSThread sleepForTimeInterval:0.01];
  118. // }
  119. // }
  120. // }
  121. //
  122. // [self execCallback:command];
  123. // }];
  124. //}
  125. /**
  126. * Clear notifications by id.
  127. *
  128. * @param [ Array<Int> ] The IDs of the notifications to clear.
  129. *
  130. * @return [ Void ]
  131. */
  132. - (void) clear:(CDVInvokedUrlCommand*)command
  133. {
  134. [self.commandDelegate runInBackground:^{
  135. for (NSNumber* id in command.arguments) {
  136. UNNotificationRequest* notification;
  137. notification = [self.center getNotificationWithId:id];
  138. if (!notification)
  139. continue;
  140. [self.center clearNotification:notification];
  141. [self fireEvent:@"clear" notification:notification];
  142. }
  143. [self execCallback:command];
  144. }];
  145. }
  146. /**
  147. * Clear all local notifications.
  148. *
  149. * @return [ Void ]
  150. */
  151. - (void) clearAll:(CDVInvokedUrlCommand*)command
  152. {
  153. [self.commandDelegate runInBackground:^{
  154. [self.center clearAllNotifications];
  155. [self.app setApplicationIconBadgeNumber:0];
  156. [self fireEvent:@"clearall"];
  157. [self execCallback:command];
  158. }];
  159. }
  160. /**
  161. * Cancel notifications by id.
  162. *
  163. * @param [ Array<Int> ] The IDs of the notifications to clear.
  164. *
  165. * @return [ Void ]
  166. */
  167. - (void) cancel:(CDVInvokedUrlCommand*)command
  168. {
  169. [self.commandDelegate runInBackground:^{
  170. for (NSNumber* id in command.arguments) {
  171. UNNotificationRequest* notification;
  172. notification = [self.center getNotificationWithId:id];
  173. if (!notification)
  174. continue;
  175. [self.center cancelNotification:notification];
  176. [self fireEvent:@"cancel" notification:notification];
  177. }
  178. [self execCallback:command];
  179. }];
  180. }
  181. /**
  182. * Cancel all local notifications.
  183. *
  184. * @return [ Void ]
  185. */
  186. - (void) cancelAll:(CDVInvokedUrlCommand*)command
  187. {
  188. [self.commandDelegate runInBackground:^{
  189. [self.center cancelAllNotifications];
  190. [self.app setApplicationIconBadgeNumber:0];
  191. [self fireEvent:@"cancelall"];
  192. [self execCallback:command];
  193. }];
  194. }
  195. /**
  196. * If a notification by ID is present.
  197. *
  198. * @param [ Number ]id The ID of the notification.
  199. *
  200. * @return [ Void ]
  201. */
  202. - (void) isPresent:(CDVInvokedUrlCommand *)command
  203. {
  204. [self exist:command byType:NotifcationTypeAll];
  205. }
  206. /**
  207. * If a notification by ID is scheduled.
  208. *
  209. * @param [ Number ]id The ID of the notification.
  210. *
  211. * @return [ Void ]
  212. */
  213. - (void) isScheduled:(CDVInvokedUrlCommand*)command
  214. {
  215. [self exist:command byType:NotifcationTypeScheduled];
  216. }
  217. /**
  218. * Check if a notification with an ID is triggered.
  219. *
  220. * @param [ Number ]id The ID of the notification.
  221. *
  222. * @return [ Void ]
  223. */
  224. - (void) isTriggered:(CDVInvokedUrlCommand*)command
  225. {
  226. [self exist:command byType:NotifcationTypeTriggered];
  227. }
  228. /**
  229. * Check if a notification exists by ID and type.
  230. *
  231. * @param [ APPNotificationType ] type The type of notifications to look for.
  232. *
  233. * @return [ Void ]
  234. */
  235. - (void) exist:(CDVInvokedUrlCommand*)command
  236. byType:(APPNotificationType)type;
  237. {
  238. [self.commandDelegate runInBackground:^{
  239. NSNumber* id = [command argumentAtIndex:0];
  240. BOOL exist = [_center notificationExist:id type:type];
  241. CDVPluginResult* result;
  242. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  243. messageAsBool:exist];
  244. [self.commandDelegate sendPluginResult:result
  245. callbackId:command.callbackId];
  246. }];
  247. }
  248. /**
  249. * List of all notification IDs.
  250. *
  251. * @return [ Void ]
  252. */
  253. - (void) ids:(CDVInvokedUrlCommand*)command
  254. {
  255. [self ids:command byType:NotifcationTypeAll];
  256. }
  257. /**
  258. * List of all scheduled notification IDs.
  259. *
  260. * @return [ Void ]
  261. */
  262. - (void) scheduledIds:(CDVInvokedUrlCommand*)command
  263. {
  264. [self ids:command byType:NotifcationTypeScheduled];
  265. }
  266. /**
  267. * List of all triggered notification IDs.
  268. *
  269. * @return [ Void ]
  270. */
  271. - (void) triggeredIds:(CDVInvokedUrlCommand*)command
  272. {
  273. [self ids:command byType:NotifcationTypeTriggered];
  274. }
  275. /**
  276. * List of ids for given local notifications.
  277. *
  278. * @param [ APPNotificationType ] type The type of notifications to look for.
  279. *
  280. * @return [ Void ]
  281. */
  282. - (void) ids:(CDVInvokedUrlCommand*)command
  283. byType:(APPNotificationType)type;
  284. {
  285. [self.commandDelegate runInBackground:^{
  286. NSArray* ids = [self.center getNotificationIdsByType:type];
  287. CDVPluginResult* result;
  288. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  289. messageAsArray:ids];
  290. [self.commandDelegate sendPluginResult:result
  291. callbackId:command.callbackId];
  292. }];
  293. }
  294. /**
  295. * Notification by id.
  296. *
  297. * @param [ Number ] id The id of the notification to return.
  298. *
  299. * @return [ Void ]
  300. */
  301. - (void) notification:(CDVInvokedUrlCommand*)command
  302. {
  303. [self notification:command byType:NotifcationTypeAll];
  304. }
  305. /**
  306. * Scheduled notification by id.
  307. *
  308. * @param [ Number ] id The id of the notification to return.
  309. *
  310. * @return [ Void ]
  311. */
  312. - (void) scheduledNotification:(CDVInvokedUrlCommand*)command
  313. {
  314. [self notification:command byType:NotifcationTypeScheduled];
  315. }
  316. /**
  317. * Triggered notification by id.
  318. *
  319. * @param [ Number ] id The id of the notification to return.
  320. *
  321. * @return [ Void ]
  322. */
  323. - (void) triggeredNotification:(CDVInvokedUrlCommand*)command
  324. {
  325. [self notification:command byType:NotifcationTypeTriggered];
  326. }
  327. /**
  328. * Notification by type and id.
  329. *
  330. * @param [ APPNotificationType ] type The type of notifications to look for.
  331. *
  332. * @return [ Void ]
  333. */
  334. - (void) notification:(CDVInvokedUrlCommand*)command
  335. byType:(APPNotificationType)type;
  336. {
  337. [self.commandDelegate runInBackground:^{
  338. NSArray* ids = command.arguments;
  339. NSArray* notifications;
  340. notifications = [_center getNotificationOptionsByType:type andId:ids];
  341. CDVPluginResult* result;
  342. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  343. messageAsDictionary:[notifications firstObject]];
  344. [self.commandDelegate sendPluginResult:result
  345. callbackId:command.callbackId];
  346. }];
  347. }
  348. /**
  349. * List of notifications by id.
  350. *
  351. * @param [ Array<Number> ] ids The ids of the notifications to return.
  352. *
  353. * @return [ Void ]
  354. */
  355. - (void) notifications:(CDVInvokedUrlCommand*)command
  356. {
  357. [self notifications:command byType:NotifcationTypeAll];
  358. }
  359. /**
  360. * List of scheduled notifications by id.
  361. *
  362. * @param [ Array<Number> ] ids The ids of the notifications to return.
  363. *
  364. * @return [ Void ]
  365. */
  366. - (void) scheduledNotifications:(CDVInvokedUrlCommand*)command
  367. {
  368. [self notifications:command byType:NotifcationTypeScheduled];
  369. }
  370. /**
  371. * List of triggered notifications by id.
  372. *
  373. * @param [ Array<Number> ] ids The ids of the notifications to return.
  374. *
  375. * @return [ Void ]
  376. */
  377. - (void) triggeredNotifications:(CDVInvokedUrlCommand *)command
  378. {
  379. [self notifications:command byType:NotifcationTypeTriggered];
  380. }
  381. /**
  382. * List of notifications by type and id.
  383. *
  384. * @param [ APPNotificationType ] type The type of notifications to look for.
  385. *
  386. * @return [ Void ]
  387. */
  388. - (void) notifications:(CDVInvokedUrlCommand*)command
  389. byType:(APPNotificationType)type;
  390. {
  391. [self.commandDelegate runInBackground:^{
  392. NSArray* ids = command.arguments;
  393. NSArray* notifications;
  394. if (type == NotifcationTypeAll && ids.count == 0) {
  395. notifications = [_center getNotificationOptions];
  396. }
  397. else if (type == NotifcationTypeAll) {
  398. notifications = [_center getNotificationOptionsById:ids];
  399. }
  400. else if (ids.count == 0) {
  401. notifications = [_center getNotificationOptionsByType:type];
  402. }
  403. else {
  404. notifications = [_center getNotificationOptionsByType:type
  405. andId:ids];
  406. }
  407. CDVPluginResult* result;
  408. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  409. messageAsArray:notifications];
  410. [self.commandDelegate sendPluginResult:result
  411. callbackId:command.callbackId];
  412. }];
  413. }
  414. /**
  415. * Check for permission to show notifications.
  416. *
  417. * @return [ Void ]
  418. */
  419. - (void) check:(CDVInvokedUrlCommand*)command
  420. {
  421. [_center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings* settings) {
  422. BOOL authorized = settings.authorizationStatus == UNAuthorizationStatusAuthorized;
  423. BOOL enabled = settings.notificationCenterSetting == UNNotificationSettingEnabled;
  424. BOOL permitted = authorized && enabled;
  425. CDVPluginResult* result;
  426. result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
  427. messageAsBool:permitted];
  428. [self.commandDelegate sendPluginResult:result
  429. callbackId:command.callbackId];
  430. }];
  431. }
  432. /**
  433. * Request for permission to show notifcations.
  434. *
  435. * @return [ Void ]
  436. */
  437. - (void) request:(CDVInvokedUrlCommand*)command
  438. {
  439. UNAuthorizationOptions options =
  440. (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert);
  441. [self.center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError* e) {
  442. [self check:command];
  443. }];
  444. }
  445. #pragma mark -
  446. #pragma mark Private
  447. /**
  448. * Schedule the local notification.
  449. */
  450. - (void) scheduleNotification:(APPNotificationContent*)notification
  451. {
  452. __weak APPLocalNotification* weakSelf = self;
  453. UNNotificationRequest* request = notification.request;
  454. [_center addNotificationRequest:request withCompletionHandler:^(NSError* e) {
  455. __strong APPLocalNotification* strongSelf = weakSelf;
  456. [strongSelf fireEvent:@"add" notification:request];
  457. }];
  458. }
  459. ///**
  460. // * Update the local notification.
  461. // */
  462. //- (void) updateNotification:(UILocalNotification*)notification
  463. // withOptions:(NSDictionary*)newOptions
  464. //{APPNotificationRequest*
  465. // NSMutableDictionary* options = [notification.userInfo mutableCopy];
  466. //
  467. // [options addEntriesFromDictionary:newOptions];
  468. // [options setObject:[NSDate date] forKey:@"updatedAt"];
  469. //
  470. //// notification = [[UILocalNotification alloc]
  471. //// initWithOptions:options];
  472. ////
  473. //// [self scheduleLocalNotification:notification];
  474. //}
  475. #pragma mark -
  476. #pragma mark UNUserNotificationCenterDelegate
  477. /**
  478. * Called when a notification is delivered to the app while being in foreground.
  479. */
  480. - (void) userNotificationCenter:(UNUserNotificationCenter *)center
  481. willPresentNotification:(UNNotification *)notification
  482. withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
  483. {
  484. [self fireEvent:@"trigger" notification:notification.request];
  485. completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
  486. }
  487. /**
  488. * Called to let your app know which action was selected by the user for a given
  489. * notification.
  490. */
  491. - (void) userNotificationCenter:(UNUserNotificationCenter *)center
  492. didReceiveNotificationResponse:(UNNotificationResponse *)response
  493. withCompletionHandler:(void (^)())completionHandler
  494. {
  495. UNNotificationRequest* notification = response.notification.request;
  496. NSString* action = response.actionIdentifier;
  497. NSString* event = action;
  498. if ([action isEqualToString:UNNotificationDefaultActionIdentifier]) {
  499. event = @"click";
  500. } else
  501. if ([action isEqualToString:UNNotificationDismissActionIdentifier]) {
  502. event = @"clear";
  503. }
  504. [self fireEvent:event notification:notification];
  505. completionHandler();
  506. }
  507. #pragma mark -
  508. #pragma mark Life Cycle
  509. /**
  510. * Registers obervers after plugin was initialized.
  511. */
  512. - (void) pluginInitialize
  513. {
  514. eventQueue = [[NSMutableArray alloc] init];
  515. _app = [UIApplication sharedApplication];
  516. _center = [UNUserNotificationCenter currentNotificationCenter];
  517. _center.delegate = self;
  518. [_center registerGeneralNotificationCategory];
  519. }
  520. #pragma mark -
  521. #pragma mark Helper
  522. /**
  523. * Retrieve the state of the application.
  524. *
  525. * @return "background" or "foreground"
  526. */
  527. - (NSString*) applicationState
  528. {
  529. UIApplicationState state = [_app applicationState];
  530. bool isActive = state == UIApplicationStateActive;
  531. return isActive ? @"foreground" : @"background";
  532. }
  533. /**
  534. * Simply invokes the callback without any parameter.
  535. */
  536. - (void) execCallback:(CDVInvokedUrlCommand*)command
  537. {
  538. CDVPluginResult *result = [CDVPluginResult
  539. resultWithStatus:CDVCommandStatus_OK];
  540. [self.commandDelegate sendPluginResult:result
  541. callbackId:command.callbackId];
  542. }
  543. /**
  544. * Fire general event.
  545. *
  546. * @param [ NSString* ] event The name of the event to fire.
  547. *
  548. * @return [ Void ]
  549. */
  550. - (void) fireEvent:(NSString*)event
  551. {
  552. [self fireEvent:event notification:NULL];
  553. }
  554. /**
  555. * Fire event for about a local notification.
  556. *
  557. * @param [ NSString* ] event The name of the event to fire.
  558. * @param [ APPNotificationRequest* ] notification The local notification.
  559. *
  560. * @return [ Void ]
  561. */
  562. - (void) fireEvent:(NSString*)event
  563. notification:(UNNotificationRequest*)request
  564. {
  565. NSString* js;
  566. NSString* appState = [self applicationState];
  567. NSString* params = [NSString stringWithFormat:@"\"%@\"", appState];
  568. if (request) {
  569. NSString* args = [request encodeToJSON];
  570. params = [NSString stringWithFormat:@"%@,'%@'", args, appState];
  571. }
  572. js = [NSString stringWithFormat:
  573. @"cordova.plugins.notification.local.core.fireEvent('%@', %@)",
  574. event, params];
  575. if (deviceready) {
  576. [self.commandDelegate evalJs:js];
  577. } else {
  578. [self.eventQueue addObject:js];
  579. }
  580. }
  581. @end