[Из песочницы] Изменяем содержимое нотификации приложения iOS

Привет!

В этой статье я хочу поделиться своим опытом использования одного не очевидного (по крайней мере для меня) варианта изменения текста уведомления приложения, отправкой дополнительных данных через UNUserNotificationCenter.

Я надеюсь эта статья будет полезна для новичков в программировании под iOS на Swift. Предполагается, что у вас есть хотя бы некоторый опыт программирования под iOS на Swift. Я использовал Swift 5 и Xcode 10.2.1. И так, приступим.

Задача


У меня есть приложение, которое показывает пользователю уведомления. Уведомление состоит из основного текста и второстепенного текста.

Итак, идея заключается в том, чтобы сначала показать пользователю только основной текст, и, если пользователь хочет знать второстепенный текст, он должен нажать кнопку «показать» в уведомлении.

Я использую следующий метод, чтобы показать уведомление (все пояснения ниже):

1. Прежде всего, мы должны определить экземпляр UNUserNotificationCenter:

class NotificationService: NSObject, UNUserNotificationCenterDelegate {
    let notificationCenter = UNUserNotificationCenter.current()
}

2. Далее мы объявляем метод, который мы будем использовать для отправки уведомлений:

Мой метод запроса на уведомление
// 1
// Мы определяем метод, который принимает на вход тип Tuple с двумя строковыми параметрами.
// showBody - это параметр с типом Bool, который позволяет нам показывать или скрывать второстепенный текст в нашем уведомлении.
// withAction - также является параметром типа Bool, и он использует для скрытия кнопки действия, если кнопка "показать" была нажата.
// atDate date - это параметр типа Date, и мы используем его для того, чтобы запланировать триггер для нашего уведомления.
func showNotification(with item: (String, String), showBody: Bool, withAction: Bool, atDate date: Date) {
    // 2
    // Определяем наш контент
    let content = UNMutableNotificationContent()

    // 3
    // Присваиваем идентификатор нашему действию
    let userActionsIdentifier = "showMe”

    // 4
    // Присваиваем нашему контенту основной текст .
    content.title = item.0

    // 5
    // Для первого вызова метода, я устанавливаю этот параметр в false, для того, чтобы пользователь не видел второстепенный текст уведомления.
    if showBody { content.body = item.1 }

    // 6
    // Это самая важная часть - я присваиваю параметру notificationCenter userInfo значения нашего основного и второстепенного текстов.
    content.userInfo = [item.0: item.1]
    content.sound = UNNotificationSound.default

    // 7
    // При первом вызове функции я устанавливаю параметру withAction значение true, чтобы пользователь мог нажать кнопку "Show me".
    if withAction { content.categoryIdentifier = userActionsIdentifier }

    // 8
    // Устанавливаем уведомлению уникальный идентификатор, чтобы оно не пересекалось с другими в очереди.
    let notificationID = item.0

    // 9
    // Устанавливаем параметр даты для последующего использования.
    // В нашем случае я использую только часы, минуты и секунды от текущей даты.
    var dc = DateComponents()
    dc.hour = Calendar.current.component(.hour, from: date)
    dc.minute = Calendar.current.component(.minute, from: date)
    dc.second = Calendar.current.component(.second, from: date)

    // 10
    // Определяем наш триггер. Вы можете использовать иные триггеры, но в этом случае я использовал UNCalendarNotificationTrigger.
    let trigger = UNCalendarNotificationTrigger(dateMatching: dc, repeats: false)

    // 11
    // Определяем наш запрос на уведомление с объявлением идентификатора, запроса и триггера.
    let request = UNNotificationRequest(identifier: notificationID, content: content, trigger: trigger)

    // 12
    // Добавляем наш запрос в notificationCenter, и так же ловим ошибки.
    notificationCenter.add(request) { (error) in
        error == nil ? print("notifacation request was added at ", trigger.nextTriggerDate()!) :
        print(error.debugDescription)
    }

    // 13
    // Определяем наше действие пользователя. Оно позволит нашему пользователю нажать на кнопку уведомления и увидеть второстепенный текст. Определяем идентификатор действия и его текст.
    let action = UNNotificationAction(identifier: "showMe”, title: "Show me”, options: [])

    // 14
    // Определяем категорию действия.
    let category = UNNotificationCategory(identifier:userActionsIdentifier, actions: [action], intentIdentifiers: [], options: [])

    // 15
    // Наконец добавляем нашу категорию в notificationCenter.
    notificationCenter.setNotificationCategories([category])
}

Когда мы вызываем этот метод, мы увидим уведомление в определенное нами время.
Если пользователь потянет вниз уведомление, появится кнопка «Show me». Затем пользователь должен нажать эту кнопку, чтобы увидеть второстепенный текст. Чтобы сделать это, мы должны использовать метод делегата UNUserNotificationCenterDelegate:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { … }

Итак, код, который я использую в методе этого делегата следующим образом:

Мой метод делегата
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    print("didReceive response”)

    // 1
    // Используем оператор switch для поиска идентификатора действия
    switch response.actionIdentifier {
        case "showMe”:
        print("showMe action”)
 
        // 2
        // Здесь мы забираем данные из userInfo, которые мы передали в методе showNotification на шаге 6, и разворачиваем его в тип String.
        let mainText = response.notification.request.content.userInfo.keys.first! as! String

        // 3
        // Здесь мы снова забираем данные из userInfo, которые мы передали в методе showNotification на шаге 6, и снова разворачиваем его в тип String.
        let subText = response.notification.request.content.userInfo.values.first! as! String

        // 4
        // Здесь мы снова вызываем наш метод showNotificationlet, но с другими параметрами:
        // showBody теперь устанавливаем в true, а withAction в false (просто потому что больше нет необходимости в действии).
        self.showNotification(with: (mainText, subText), showBody: true, withAction: false, atDate: Date(timeInterval: 3, since: Date()))
 
       default:
       print("defaul action”)
    }
   
   completionHandler()
}

И вот как это выглядит:

xhl3rzw8nqf3utfsmihmv2s1-gm.gif

Внутри проекта (который вы можете скачать по ссылке ниже) есть еще немного кода, но сама суть идеи описана в этой статье.

Спасибо!

Ссылка на проект

© Habrahabr.ru