notes icon files apple app iphone cocoa-touch ios4 push-notification uilocalnotification

iphone - files - ios app icon generator



iPhone: Incrementando la insignia de la aplicación a través de una notificación local (10)

Agregue el siguiente código en su delegado de proyecto.

- (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"%s",__FUNCTION__); NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ; for (UILocalNotification *localNotification in arrayOfLocalNotifications) { NSLog(@"the notification: %@", localNotification); localNotification.applicationIconBadgeNumber= application.applicationIconBadgeNumber+1; } }

esto funciona para mi :-)

¿Es posible incrementar la insignia de la aplicación a través de una notificación local mientras la aplicación no se está ejecutando?

Sé cómo configurar la insignia, pero no he encontrado ninguna manera de incrementar este valor.

localNotification.applicationIconBadgeNumber = 23;

Actualización: encontré una solución (lejos de ser perfecta). Puede predecir qué sucederá si el usuario no abre la aplicación y agrega notificaciones para cada evento +1.

Un ejemplo:

  • Para el día 1: Count = 0
  • Para el día 2: localNotification.applicationIconBadgeNumber = 1;
  • Para el día 3: localNotification.applicationIconBadgeNumber = 2;
  • Para el día 4: localNotification.applicationIconBadgeNumber = 3;

==> Pon estas notificaciones en una matriz y configúralas antes de que la aplicación finalice.

Sin embargo, estoy buscando una solución mejor que esta solución.


Basado en Wassaahbbs y Bionicles respuestas arriba. Swift 4.0, para todas las versiones de iOS. Llame a esta función en func applicationDidBecomeActive(_ application: UIApplication) .

func renumberBadgesOfPendingNotifications() { if #available(iOS 10.0, *) { UNUserNotificationCenter.current().getPendingNotificationRequests { pendingNotificationRequests in if pendingNotificationRequests.count > 0 { let notificationRequests = pendingNotificationRequests .filter { $0.trigger is UNCalendarNotificationTrigger } .sorted(by: { (r1, r2) -> Bool in let r1Trigger = r1.trigger as! UNCalendarNotificationTrigger let r2Trigger = r2.trigger as! UNCalendarNotificationTrigger let r1Date = r1Trigger.nextTriggerDate()! let r2Date = r2Trigger.nextTriggerDate()! return r1Date.compare(r2Date) == .orderedAscending }) let identifiers = notificationRequests.map { $0.identifier } UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: identifiers) notificationRequests.enumerated().forEach { (index, request) in if let trigger = request.trigger { let content = UNMutableNotificationContent() content.body = request.content.body content.sound = .default() content.badge = (index + 1) as NSNumber let request = UNNotificationRequest(identifier: request.identifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) } } } } } else if let pendingNotifications = UIApplication.shared.scheduledLocalNotifications, pendingNotifications.count > 0 { let notifications = pendingNotifications .filter { $0.fireDate != nil } .sorted(by: { n1, n2 in n1.fireDate!.compare(n2.fireDate!) == .orderedAscending }) notifications.forEach { UIApplication.shared.cancelLocalNotification($0) } notifications.enumerated().forEach { (index, notification) in notification.applicationIconBadgeNumber = index + 1 UIApplication.shared.scheduleLocalNotification(notification) } } }


Como alternativa a la solución de Bionicle, uno puede usar un NSSortDescriptor para manejar la clasificación basada en el campo fireDate. De nuevo, esta solución brinda todos los beneficios de la respuesta original de Whasssaaahhh, pero también significa que puede manejar las notificaciones que se agregan en un orden no cronológico, por ejemplo, agregar una notificación en 30 segundos y luego en 20 segundos. Llamo a la función siguiente cuando agrego una notificación local y cuando regreso a la aplicación.

// When we add/remove local notifications, if we call this function, it will ensure each notification // will have an ascending badge number specified. - (void)renumberBadgesOfPendingNotifications { // Clear the badge on the icon [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // First get a copy of all pending notifications (unfortunately you cannot ''modify'' a pending notification) NSMutableArray * pendingNotifications = [[[UIApplication sharedApplication] scheduledLocalNotifications] mutableCopy]; // Sorted by fire date. NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"fireDate" ascending:TRUE]; [pendingNotifications sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]; [sortDescriptor release]; // if there are any pending notifications -> adjust their badge number if (pendingNotifications.count != 0) { // clear all pending notifications [[UIApplication sharedApplication] cancelAllLocalNotifications]; // the for loop will ''restore'' the pending notifications, but with corrected badge numbers // note : a more advanced method could ''sort'' the notifications first !!! NSUInteger badgeNbr = 1; for (UILocalNotification *notification in pendingNotifications) { // modify the badgeNumber notification.applicationIconBadgeNumber = badgeNbr++; // schedule ''again'' [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } } // Release our copy. [pendingNotifications release]; }


He encontrado, implementado y probado una ''solución alternativa'' para (al parecer) auto incrementar el número de la insignia del ícono de la aplicación, que funciona bien con notificaciones locales no repetitivas

De hecho, no es posible para UILocalNotifications tener iOS ''automáticamente'' actualizar / incrementar el número de la placa cuando se disparan múltiples notificaciones locales, y el usuario ''las ignora'' o no las maneja inmediatamente, por lo que se ''acumulan'' en la Notificación centrar.

Además, "agregar algún método de devolución de llamada" a su aplicación no puede ocuparse del "incremento automático", ya que todo el proceso de notificación es manejado "desde afuera" de su aplicación por iOS, su aplicación ni siquiera necesita ejecutarse.

Sin embargo, hay una solución, que se basa en el conocimiento que encontré durante la experimentación, porque la documentación de XCode es demasiado vaga en la propiedad de la insignia.

  • la insignia es solo un "entero", en realidad más como una "etiqueta ficticia" que asigna a la propiedad applicationIconBadgeNumber, justo antes de registrar la notificación. Puedes darle cualquier valor: cuando se active la notificación, iOS agregará ese valor a la insignia, sea lo que sea que hayas configurado en el momento en que registraste la notificación. No hay ningún ''incremento automático'' mágico u otra manipulación por iOS (tal vez eso sea diferente con las notificaciones push, pero ese no es el tema aquí). iOS simplemente toma el número (entero) de la notificación registrada y lo coloca en la insignia.

Por lo tanto, para una ''solución alternativa'' su aplicación debe proporcionar el número de credencial correcto e incrementado para cada notificación que crea y registra ''en la parte superior de las notificaciones pendientes''.

Dado que su aplicación no se puede ver en el futuro, y sabe qué eventos manejará de inmediato, y cuáles dejará "pendientes" por un tiempo, hay un truco para hacer:

Cuando su aplicación maneja las notificaciones (tocando las notificaciones, ícono, ...), usted tiene que:

  1. obtener una copia de todas las notificaciones pendientes
  2. ''renumerar'' el número de distintivo de estas notificaciones pendientes
  3. eliminar todas las notificaciones pendientes
  4. vuelve a registrar la copia de las notificaciones con sus números corregidos de placa

Además, cuando su aplicación registra una nueva notificación, primero debe verificar cuántas notificaciones están pendientes y registrar la nueva notificación con:

badgeNbr = nbrOfPendingNotifications + 1;

Al mirar mi código, se aclarará. Probé esto, y definitivamente está funcionando:

En su método ''registerLocalNotification'', debe hacer esto:

NSUInteger nextBadgeNumber = [[[UIApplication sharedApplication] scheduledLocalNotifications] count] + 1; localNotification.applicationIconBadgeNumber = nextBadgeNumber;

Cuando maneje la notificación (appDelegate), debe llamar al siguiente método, que borra la insignia en el ícono y renumera las insignias para las notificaciones pendientes (si hay alguna)

Tenga en cuenta que el próximo código funciona bien para eventos registrados ''secuenciales''. Si quiere ''agregar'' eventos entre los pendientes, primero deberá ''reordenar'' estos eventos. No llegué tan lejos, pero creo que es posible.

- (void)renumberBadgesOfPendingNotifications { // clear the badge on the icon [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // first get a copy of all pending notifications (unfortunately you cannot ''modify'' a pending notification) NSArray *pendingNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; // if there are any pending notifications -> adjust their badge number if (pendingNotifications.count != 0) { // clear all pending notifications [[UIApplication sharedApplication] cancelAllLocalNotifications]; // the for loop will ''restore'' the pending notifications, but with corrected badge numbers // note : a more advanced method could ''sort'' the notifications first !!! NSUInteger badgeNbr = 1; for (UILocalNotification *notification in pendingNotifications) { // modify the badgeNumber notification.applicationIconBadgeNumber = badgeNbr++; // schedule ''again'' [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } } }

Para ser verdaderamente "a prueba de balas", este método debe ser código ''atómico'' (kernel), evitando que el iOS se active durante la ejecución de este método. Tendremos que tomar este riesgo aquí, las posibilidades son muy pequeñas, esto sucederá.

Esta es mi primera contribución a , por lo que puedes comentar también si no estoy siguiendo las ''reglas'' aquí


La única forma en que podrá configurar dinámicamente el número de la insignia cuando su aplicación no se esté ejecutando es mediante notificaciones automáticas. Tendrás que rastrear las actualizaciones en el lado del servidor.


La respuesta de Whasssaaahhh fue muy útil para mí. También necesitaba ordenar las notificaciones basadas en sus fireDates. Aquí está el código de Whasssaaahhh con mi código para ordenar las notificaciones usando el método de delegado de NSArray para ordenar - [NSArray sortedArrayUsingComparator:^(id obj1, id obj2) {}];

- (void)renumberBadgesOfPendingNotifications { // clear the badge on the icon [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; // first get a copy of all pending notifications (unfortunately you cannot ''modify'' a pending notification) // Sort the pending notifications first by their fireDate NSArray *pendingNotifications = [[[UIApplication sharedApplication] scheduledLocalNotifications] sortedArrayUsingComparator:^(id obj1, id obj2) { if ([obj1 isKindOfClass:[UILocalNotification class]] && [obj2 isKindOfClass:[UILocalNotification class]]) { UILocalNotification *notif1 = (UILocalNotification *)obj1; UILocalNotification *notif2 = (UILocalNotification *)obj2; return [notif1.fireDate compare:notif2.fireDate]; } return NSOrderedSame; }]; // if there are any pending notifications -> adjust their badge number if (pendingNotifications.count != 0) { // clear all pending notifications [[UIApplication sharedApplication] cancelAllLocalNotifications]; // the for loop will ''restore'' the pending notifications, but with corrected badge numbers // note : a more advanced method could ''sort'' the notifications first !!! NSUInteger badgeNbr = 1; for (UILocalNotification *notification in pendingNotifications) { // modify the badgeNumber notification.applicationIconBadgeNumber = badgeNbr++; // schedule ''again'' [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } } }

Después de algún tiempo, necesité implementar esto en Swift pero también necesitaba apoyar las notificaciones locales repetitivas . He encontrado una solución en Swift.

Solución para Swift 2.3

func renumberBadgesOfPendingNotifications() { let app = UIApplication.sharedApplication() let pendingNotifications = app.scheduledLocalNotifications // clear the badge on the icon app.applicationIconBadgeNumber = 0 // first get a copy of all pending notifications (unfortunately you cannot ''modify'' a pending notification) // if there are any pending notifications -> adjust their badge number if let pendings = pendingNotifications where pendings.count > 0 { // Reassign firedate. var notifications = pendings var i = 0 for notif in notifications { if notif.fireDate?.compare(NSDate()) == NSComparisonResult.OrderedAscending && notif.repeatInterval.rawValue == NSCalendarUnit.init(rawValue:0).rawValue { // Skip notification scheduled earlier than current date time // and if it is has NO REPEAT INTERVAL } else { notif.fireDate = getFireDate(notif) } i+=1 } // sorted by fire date. notifications = pendings.sort({ p1, p2 in p1.fireDate!.compare(p2.fireDate!) == .OrderedAscending }) // clear all pending notifications app.cancelAllLocalNotifications() // the for loop will ''restore'' the pending notifications, but with corrected badge numbers var badgeNumber: Int = 1 for n in notifications { // modify the badgeNumber n.applicationIconBadgeNumber = badgeNumber badgeNumber+=1 // schedule ''again'' app.scheduleLocalNotification(n) } } } private func getFireDate(notification:UILocalNotification?) -> NSDate? { if notification == nil { return nil } let currentDate: NSDate = NSDate().dateByRemovingSeconds() let originalDate: NSDate = notification!.fireDate! var fireDate: NSDate? = originalDate if originalDate.compare(currentDate) == NSComparisonResult.OrderedAscending || originalDate.compare(currentDate) == NSComparisonResult.OrderedSame { let currentDateTimeInterval = currentDate.timeIntervalSinceReferenceDate let originalDateTimeInterval = originalDate.timeIntervalSinceReferenceDate var frequency:NSTimeInterval = 0 switch notification?.repeatInterval { case NSCalendarUnit.Hour?: frequency = currentDate.dateByAddingHours(1).timeIntervalSinceDate(currentDate) print(frequency) break case NSCalendarUnit.Day?: frequency = currentDate.dateByAddingDays(1).timeIntervalSinceDate(currentDate) print(frequency) break case NSCalendarUnit.WeekOfYear?: frequency = currentDate.dateByAddingDays(7).timeIntervalSinceDate(currentDate) print(frequency) break case NSCalendarUnit.Month?: frequency = currentDate.dateByAddingMonths(1).timeIntervalSinceDate(currentDate) print(frequency) break case NSCalendarUnit.Year?: frequency = currentDate.dateByAddingYears(1).timeIntervalSinceDate(currentDate) print(frequency) break default: originalDate } let timeIntervalDiff = (((currentDateTimeInterval - originalDateTimeInterval) / frequency) + frequency) + originalDateTimeInterval fireDate = NSDate(timeIntervalSinceReferenceDate: timeIntervalDiff) } return fireDate?.dateByRemovingSeconds() }

Nota: dateByAddingHours, dateByAddingHours, dateByAddingMonths, dateByAddingYears, dateByRemovingSeconds son métodos de una extensión de fecha que estoy usando y son métodos autodescriptivos que puede implementar por su cuenta.


La respuesta de Whasssaabhhh en Swift 2.1, con clasificación

func renumberBadgesOfPendingNotifications() { let app = UIApplication.sharedApplication() let pendingNotifications = app.scheduledLocalNotifications // clear the badge on the icon app.applicationIconBadgeNumber = 0 // first get a copy of all pending notifications (unfortunately you cannot ''modify'' a pending notification) // if there are any pending notifications -> adjust their badge number if let pendings = pendingNotifications where pendings.count > 0 { // sorted by fire date. let notifications = pendings.sort({ p1, p2 in p1.fireDate!.compare(p2.fireDate!) == .OrderedAscending }) // clear all pending notifications app.cancelAllLocalNotifications() // the for loop will ''restore'' the pending notifications, but with corrected badge numbers var badgeNumber = 1 for n in notifications { // modify the badgeNumber n.applicationIconBadgeNumber = badgeNumber++ // schedule ''again'' app.scheduleLocalNotification(n) } } }


Según la documentation , creo que no puede aumentar el valor de la insignia, cuando su aplicación no se está ejecutando. Establece el número de la insignia cuando programa su notificación, por lo que no es posible incrementarla.

Una aplicación es responsable de administrar el número de placa que se muestra en su icono. Por ejemplo, si una aplicación de mensajería de texto procesa todos los mensajes entrantes después de recibir una notificación local, debe eliminar la insignia del icono estableciendo la propiedad applicationIconBadgeNumber del objeto UIApplication en 0.


Según las respuestas de Wassaahbbs y Bionicles anteriores, para Swift 3.0 esto parece funcionar para la repetición de notificaciones locales . Lo tengo trabajando para configurar 4 notificaciones locales, cada una de las cuales se puede activar y desactivar de forma independiente.

La función renumberBadgesOfPendingNotifications se llama en AppDelegate applicationDidBecomeActive para que las credenciales se actualicen si el usuario abre la aplicación después de recibir una notificación. Y también en un settingsVC donde una función setNotification configura las notificaciones en primer lugar y en caso de que el usuario active o desactive una notificación, necesitando una actualización de la insignia.

Además, la insignia se establece en 0 en applicationDidBecomeActive con UIApplication.shared.applicationIconBadgeNumber = 0.

func renumberBadgesOfPendingNotifications() { // first get a copy of all pending notifications (unfortunately you cannot ''modify'' a pending notification) let pendingNotifications = UIApplication.shared.scheduledLocalNotifications print("AppDel there are /(pendingNotifications?.count) pending notifs now") // if there are any pending notifications -> adjust their badge number if var pendings = pendingNotifications, pendings.count > 0 { // sort into earlier and later pendings var notifications = pendings var earlierNotifs = [UILocalNotification]() var laterNotifs = [UILocalNotification]() for pending in pendings { // Skip notification scheduled earlier than current date time if pending.fireDate?.compare(NSDate() as Date) == ComparisonResult.orderedAscending { // and use this if it has NO REPEAT INTERVAL && notif.repeatInterval.rawValue == NSCalendar.Unit.init(rawValue:0).rawValue { // track earlier and later pendings earlierNotifs.append(pending) } else { laterNotifs.append(pending) } } print("AppDel there are /(earlierNotifs.count) earlier notifications") print("AppDel there are /(laterNotifs.count) later notifications") // change the badge on the notifications due later pendings = laterNotifs // sorted by fireDate. notifications = pendings.sorted(by: { p1, p2 in p1.fireDate!.compare(p2.fireDate!) == .orderedAscending }) // clear all pending notifications. i.e the laterNotifs for pending in pendings { UIApplication.shared.cancelLocalNotification(pending) } // the for loop will ''restore'' the pending notifications, but with corrected badge numbers var laterBadgeNumber = 0 for n in notifications { // modify the badgeNumber laterBadgeNumber += 1 n.applicationIconBadgeNumber = laterBadgeNumber // schedule ''again'' UIApplication.shared.scheduleLocalNotification(n) print("AppDel later notif scheduled with badgenumber /(n.applicationIconBadgeNumber)") } // change the badge on the notifications due earlier pendings = earlierNotifs // sorted by fireDate. notifications = pendings.sorted(by: { p1, p2 in p1.fireDate!.compare(p2.fireDate!) == .orderedAscending }) // clear all pending notifications. i.e the laterNotifs for pending in pendings { UIApplication.shared.cancelLocalNotification(pending) } // the for loop will ''restore'' the pending notifications, but with corrected badge numbers var earlierBadgeNumber = laterBadgeNumber for n in notifications { // modify the badgeNumber earlierBadgeNumber += 1 n.applicationIconBadgeNumber = earlierBadgeNumber // schedule ''again'' UIApplication.shared.scheduleLocalNotification(n) print("AppDel earlier notif scheduled with badgenumber /(n.applicationIconBadgeNumber)") } } }


desde iOS10 es posible definir el número de la placa directamente en el UNMutableNotificationContent.

Aquí lo que funciona para mí:

Estoy trabajando en una aplicación que agrega notificaciones basadas en una fecha (con CalendarComponents), mi desencadenante es UNCalendarNotificationTrigger. Mi código es simple:

let content = UNMutableNotificationContent() content.title = "Title" content.body = "Your message" content.sound = .default() content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + 1)

Acerca de content.badge , el documento dice:

var badge: NSNumber? {set set}

Descripción El número que se aplicará al ícono de la aplicación.

Utilice esta propiedad para especificar el número que se aplicará al ícono de la aplicación cuando llegue la notificación. Si su aplicación no está autorizada para mostrar notificaciones basadas en distintivos, esta propiedad se ignorará.

Especifique el número 0 para eliminar la insignia actual, si está presente. Especifique un número mayor que 0 para mostrar una insignia con ese número. Especifique nil para dejar la insignia actual sin cambios.

SDK iOS 10.0+, TVOS 10.0+, watchOS 3.0+

La credencial se incrementa cuando se agrega una notificación, incluso si la aplicación no se está ejecutando. Puedes borrar el número de la insignia donde quieras en la aplicación con:

UIApplication.shared.applicationIconBadgeNumber = 0