Как установить временной интервал доставки уведомлений

localnotification

#1

Добрый день!
Начал разбираться с UNUserNotificationCenter.
Таким типовым образом образом добавляю уведомления

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(self.minutes * 60),
repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)

Возник вопрос, как сделать так, чтобы уведомления доставлялись в определенный промежуток времени, например с 9 утра до 9 вечера?

Если я правильно понял, то сделав уведомление, оно отправляется в UNUserNotificationCenter и при этом должен сработать trigger (например повторяем уведомление каждый час)

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3600, repeats: true)

А каков механизм для установки промежутка показа уведомлений?
Вариант: Отменять уведомления в 9 вечера и потом отправлять новый request в 9 утра.
Если это одно уведомление, тогда мне понятно, но как быть если их много (у них разный текст, интервалы и тд.)
Или есть какой то другой вариант. Как это обычно реализуется?
Заранее благодарю.


#2

триггер, это не только повторение, а само событие отправки в целом (время).

С этим проблема, что если приложение неактивно, то как вы удалите повторяющееся каждый час уведомление? Если только пушем будить в бекграунде приложение и в делегате пуша удалить нужное уведомление по id.

Здесь проще выглядит реализация отправки множества отдельных уведомлений на конкретное время:
вам известен интервал отправки (9-21 час) ; вам известен интервал повторения (60 мин) -> известно количество уведомлений и точное время отправки. Отправляете 12 уведомлений на конкретное время и всё.
А вот если надо повторять каждый день в это время, то тут как раз у этих 12 уведомлений будет триггер вида Calendar.current.dateComponents([.hour, .minute], from: yourDate) - то есть час и минута. Триггер повторения в true будет запускать это уведомление в этот час и минуту, те каждый день.

Пример других триггеров:
еженедельно
Calendar.current.dateComponents([.weekday, .hour, .minute], from: yourDate)

ежемесячно
Calendar.current.dateComponents([.day, .hour, .minute], from: yourDate)

ежегодно
Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: yourDate)

Так вы сможете точно управлять на какое время доставляются уведомления. Кроме того вы сможете сделать “окна тишины”, удалив часть уведомлений, попадающих в нужный интервал.


#3

Большая благодарность!
Сергей, несколько уточнений.
Если необходимо отправлять уведомления каждые 5 минут, за 10 часов это 120 шт. не возникнет ли у UNUserNotificationCenter подозрение, что я спамлю его? =))
Тем более, что по моей идее уведомлений может быть несколько…


#4

Юзера пожалейте ))) Мне кажется после первого десятка юзер вообще отключит уведомления от вашего приложения…

Не знаю, так много не отправлял :slight_smile:


#5

Возник дополнительный вопрос.
Уведомления я сделал (проблема с количеством все же есть, но пока не об этом).
Вопрос в том, как удалять уведомления?
UNUserNotificationCenter.current().removeAllPendingNotificationRequests() - чтобы удалить все уведомления сразу не подходит.
Мне нужно удалить только часть.
Что сделано.
При создании уведомления его идентификатор добавляется в массив.
Потом этот массив я сохраняю в coreData в текущую Entity. Создаю аттрибут - arrayOfId - transformable type. (это нормально?)
Далее, при удалении:

var test = [myNotifications.arrayOfId] (достаю из coreData)
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [test])

тут получаю ошибку Cannot convert value of type ‘[NSObject?]’ to expected element type ‘Array.ArrayLiteralElement’ (aka ‘String’)

массив test в консоли распечатывается так : [Optional([“73954FBD-6235-4925-9726-6DEB5FB815FC”, “D7B7E2C4-3EED-4001-9698-1FACF52AA6BA”])]
Помогите, кто может=)


#6
  1. покажите класс сущности myNotifications
  2. покажите как получаете данные из корДаты

При запросе данных из корДаты определённой сущности вы получите массив [NSObject?] Его надо кастить до нужного класса (сущности) и только потом обращаться за нужным параметром, ведь у NSObject нет ваших кастомных параметров - они только у вашей сущности.


#7

var myNotifications: MyNotification
Потом сделал массив (для тестов)
test = [myNotifications.arrayOfId] (arrayOfId - из корДаты - transformable, где хранятся все Id уведомлений)

Вот этот момент мне совсем не понятен… может в нем проблема

Вдруг пригодится …
var test = [myNotifications.arrayOfId]
print(“TEST (test)”)
print(“CoreD array (myNotifications.arrayOfId)”)

:pray::pray:


#8
  1. зачем вы массив помещаете в массив?

  2. как вы записываете данные в myNotifications.arrayOfId? Это UUID? Если UUID, то зачем, если идентификатор уведомления в String

  3. в общем попробуйте прокастить myNotifications.arrayOfId до вашего типа, например так:
    var test = myNotifications.arrayOfId as! [String]


#9

var test = myNotifications.arrayOfId as! [String]
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [test])
во второй строке подчеркивает test и выдает
Cannot convert value of type ‘[String]’ to expected element type ‘Array.ArrayLiteralElement’ (aka ‘String’)

Смотрите, я тут попробовал следующее:

let nc = UNUserNotificationCenter.current()
var test = [“9169EDED-61C5-496D-9494-771D7E5AA69F”, “1051A8E4-E280-4F13-9CCD-A1CC5EEB567B”]
nc.removePendingNotificationRequests(withIdentifiers: [test])
и таже самая ошибка
Cannot convert value of type ‘[String]’ to expected element type ‘Array<String>.ArrayLiteralElement’ (aka ‘String’)

Те проблема не в том, что данные из корДаты как то неверно обрабатываются… тут именно в

  • (void)removePendingNotificationRequestsWithIdentifiers:(NSArray<NSString *> *)identifiers;
    это из документации, мне не совсем понятно, как это расшифровывается…

Есть такой рабочий код

nc.getPendingNotificationRequests { (notificationRequests) in
 for notificationRequest:UNNotificationRequest in notificationRequests {
 UNUserNotificationCenter.current().removePendingNotificationRequests

(withIdentifiers: [notificationRequest.identifier])
Может быть в корДату надо не identifier записывать, а полностью notificationRequest, а потом из него доставать identifier?


#10

Да ё-маё! Зачем вы массив постоянно засовываете в другой массив!!!??
у вас myNotifications.arrayOfId уже массив NSArray! Вы его кастите до массива с нужным типом [String]! Это уже массив! Передавайте test (это уже массив!) в .removePendingNotificationRequests(withIdentifiers: test)


#11

Огромная Вам благодарность! Да туплю, некоторые вещи не понятны, но зато так интересно, особенно есть есть поддержка=))
:pray::pray::pray:


#12

Это опять я с вопросом=)
Для добавления уведомлений я использую цикл (прибавляя временной интервал, например по 5 минут)
в конце

UNUserNotificationCenter.current().add(request) { (error) in
print(“Error (error)”)
}

Проблема в том, что если начиная с текущего момента добавлять более примерно 70 request’oв то уведомления вообще не приходят. При этом в консоле - “Error nil” (т.е если сейчас 15:00, интервал с 15:00 до 17:00, каждую минуту)
Экспериментировал - если, например, сейчас 15:00, интервал с 01.00 до 15:30 каждую минуту, то уведомления приходят(870 шт).
В чем может быть причина? Как вообще узнать о наличии лимитов уведомлений, если в документации нет инфы?


#13

Подсказали, что в старой документации указано, что есть лимит в 64 уведомления.

An app can have only a limited number of scheduled notifications; the system keeps the soonest-firing 64 notifications (with automatically rescheduled notifications counting as a single notification) and discards the rest.

Интересно, есть ли другой способ решить проблему…