Отменить и перенести UserNotification (старый UILocalNotification), начиная с настраиваемой даты в iOS 10

Я планирую ежедневно UserNorification срабатывать каждый день в определенное время, уведомляя пользователя о том, что нужно что-то сделать. Но если пользователь сделает это за X часов до запуска уведомления, мне нужно отменить сегодняшнее уведомление, на мой взгляд, отменить все и снова перенести расписание, но с завтрашнего конкретного времени. Например, если сегодня уведомление должно срабатывать в 11:00, а пользователь "сделать это" в 10:00, уведомление 11:00 не должно запускаться, и мне нужно снова запланировать это в то же время, но начиная с завтрашнего дня. . И этот цикл продолжается и продолжается, как и завтра. Мои вопросы:

  1. Следует ли мне отменить расписание первых ежедневных уведомлений, используя следующий код: UNUserNotificationCenter.current().removeAllPendingNotificationRequests()?

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


person Slavcho    schedule 17.12.2016    source источник
comment
Реализуют ли ваши уведомления настраиваемый интерфейс (например, вы предоставляете UNNotificationContentExtension)?   -  person spassas    schedule 20.12.2016
comment
Нет, у них просто заголовок и тело. Напоминание пользователю, что нужно что-то сделать. Но если он сделает это за 1 час до жестко запрограммированных 11:00, уведомление не должно быть представлено в этот день, а будет продолжено на следующий день.   -  person Slavcho    schedule 20.12.2016
comment
Я сделал это в предыдущей структуре уведомлений. Я добавляю некоторую информацию о пользователе с каждым типом уведомления и когда пользователь выполняет предыдущие шаги. Я получаю это конкретное уведомление, отменяю его и повторно регистрирую с указанием даты завтра.   -  person Muhammad Zohaib Ehsan    schedule 27.12.2016
comment
На данный момент это единственное решение, использующее старый фреймворк. Но не нужно отправлять параметры в userInfo. Изменения, которые может внести пользователь, находятся в приложении, поэтому, когда он это сделает, я буду знать, что будет следующим уведомлением, отменим его и перенесу на завтра.   -  person Slavcho    schedule 27.12.2016
comment
но просто для того, чтобы узнать, как узнать, какое уведомление нужно отменить. Вы должны дать ему какой-либо идентификатор ИЛИ отфильтровать его по дате?   -  person Muhammad Zohaib Ehsan    schedule 27.12.2016
comment
Хорошо, вы добиваетесь обоих. Я делаю это с помощью математики currentTime.hours == firstNotFireHour - ›отменить Сначала. И соответственно для каждого уведомления, потому что их дата меняется, а час - нет.   -  person Slavcho    schedule 27.12.2016
comment
Я конвертирую текущее время в секунды, а время уведомления в секунды и вычитаю их, чтобы увидеть, до или после него. Простая математика. Затем я отменяю их все и снова меняю расписание в отношении продукта, подлежащего вычитанию.   -  person Slavcho    schedule 19.01.2017


Ответы (2)


К сожалению, такой вид планирования стал до смешного сложным с фреймворком уведомлений в iOS 10. Единственный способ, которым я мог найти что-то подобное, - это использовать гибрид UNCalendarNotificationTrigger и UNTimeIntervalNotificationTrigger И реализовать UNNotificationContentExtension.

Концепция следующая:

Каждый раз, когда выполняется ваше действие, вам необходимо перенести уведомления. Если время раньше, чем желаемое время уведомления (например, 11:00 в вашем примере), вместо использования календарного триггера для перепланирования используйте триггер временного интервала, чтобы установить одно временное неповторяющееся уведомление на следующий день (давайте назовите это tempNotification)

let nextDayAt11AMDate = /* the timestamp of tomorrow at 11am */
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: nextDayAt11AMDate.timeIntervalSinceDate(NSDate()), repeats: false)
/* schedule tempNotification */

Когда это уведомление получено (и при условии, что UNNotificationContentExtension был реализован), в контроллере представления вашего расширения didReceive: метод, который вызывается при получении уведомления, отмените существующие уведомления и запланируйте фактическое повторяющееся уведомление, обычно используя триггер календаря (назовем его actualNoticfication)

let date = DateComponents()
date.hour = 11
date.minute = 00 
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)
/* schedule actualNotification */

Это долгий обходной путь, вероятно, не очень эффективный и не на 100% надежный (например, если устройство закрывается, когда приходит tempNotification, то actualNotification не будет запланировано), но он охватывает большинство случаев. Я был бы очень рад найти способ получше ...

person spassas    schedule 20.12.2016
comment
Итак, когда приложение приостановлено и получено tempNotification, код не будет запущен, верно? Я полагаю, что с новым фреймворком для этого нет решения. Но спасибо за ваши усилия. - person Slavcho; 20.12.2016
comment
@Slavcho Нет, если приложение приостановлено, код будет работать; при получении уведомления расширение содержимого запускается независимо от состояния приложения. Все усложняется, когда устройство полностью выключено. - person spassas; 20.12.2016
comment
Что ж, в таком случае я попробую решение, и если оно сработает, я его приму. Просто нужно посмотреть, как UNNotificationContentExtension работает. - person Slavcho; 20.12.2016
comment
UNNotificationContentExtension используется только для устройств с / использующих 3D Touch. Так что в моем случае с iPhone 6 я не могу заставить его работать ... Или, если у вас есть демо, чтобы показать мне, я попробую. - person Slavcho; 21.12.2016
comment
@Slavcho UNNotificationContentExtension работает на всех устройствах iOS 10 (те, на которых не включена функция 3D Touch, могут получить доступ к содержимому уведомлений, нажав кнопку просмотра). Тем не менее, вам не нужно взаимодействовать с уведомлением для вызова didReceive:. Я постараюсь предоставить еще немного кода позже (к сожалению, сегодня очень загруженный день). - person spassas; 21.12.2016
comment
Я все реализовал, настраиваемое уведомление отображается, но didReceive не вызывается. Я что-то упускаю? - person Slavcho; 21.12.2016
comment
Теперь я понимаю. Он вызывается, когда я нажимаю на уведомление - ›перетаскивая вниз. Есть ли способ вызвать didReceive без взаимодействия с уведомлением? - person Slavcho; 21.12.2016
comment
Я думаю, вы имеете в виду UNNotificationServiceExtension, а не UNNotificationContentExtension - person Rizwan Sattar; 22.05.2017
comment
@RizwanSattar вопрос касается локальных уведомлений, UNNotificationServiceExtension доступен для удаленных уведомлений - person spassas; 22.05.2017
comment
@spassas Я вижу - значит, вам нужно реализовать фиктивный UIViewController для расширения содержимого, которое на самом деле не будет отображать пользовательский интерфейс, потому что didReceive: вызывается даже без взаимодействия с уведомлением? - person Rizwan Sattar; 22.05.2017
comment
У меня такая же проблема с @Slavcho, что didReceive: вызывается только при взаимодействии с уведомлением. - person Joseph Williamson; 06.10.2017

После исследования это невозможно с новым UserNotifications Framework. Для этого мы должны использовать старый UILocalNotification подход. Поскольку этот код устарел в iOS10, я изменил поддерживаемую версию на 9+, поэтому предупреждений не будет. Это постоянный подход, но можно надеяться, что Apple внедрит и расширит старую функцию в новой структуре.

person Slavcho    schedule 19.01.2017
comment
Вы нашли какое-нибудь решение в новом фреймворке? - person Viktor Sec; 04.02.2021
comment
Не пробовал ... - person Slavcho; 04.02.2021