Использование SwiftUI, Combine, уведомлений, CloudKit и криптографии

Я должен начать эту статью с заявления об отказе от ответственности: она основана на iOS 13, Swift 5 и Xcode 11.x. Предупреждаем, если вы читаете это, и эти цифры выглядят устаревшими.

Я также должен предупредить вас, что уведомления - в основном удаленные - связаны с инфраструктурой Apple, а это значит, что вам понадобится учетная запись Apple Developer для их использования. Конечно, он вам также понадобится для использования CloudKit.

Наконец, это будет сериал. Вы не создадите свой собственный WotsApp за 20 минут. В основном я буду летать на сиденье в штанах. Это займет не менее десяти глав, и в этой статье мы расскажем о первых двух.

Давайте приступим к делу. Вы можете найти немало статей о кодировании уведомлений в Swift, хотя вскоре вы обнаружите, что все они неполные. Нет, я не шучу. На мой взгляд, они неполные, потому что в них отсутствует глава, объясняющая, как отправлять удаленные уведомления под iOS. Я никогда не встречал учебника, в котором рассказывалось бы, как публиковать уведомления в Swift. Все они советуют использовать сторонние утилиты. Итак, я исследовал эту тему и написал свой собственный.

Недостающее звено или заговор? Тем не менее, я попытаюсь охватить всю историю, описывая, как создать с ее помощью собственное приложение WhatsApp.

Глава 1

Так что же такое уведомления? Они бывают двух видов: локальные и удаленные. Вы создаете и публикуете локальные уведомления в одном приложении. Удаленные уведомления создаются на сервере или втором устройстве iOS и отправляются на то же и / или другое устройство iOS. Это особые элементы в арсенале iOS, потому что они могут работать как на переднем, так и на заднем плане.

В iOS 13 есть несколько типов уведомлений. Важными из них являются предупреждения, значки и звуки. Мы исследуем, что все они делают в коде.

Местные уведомления, хотя и не гарантированы, почти всегда будут приходить. Удаленные уведомления по своей сути менее надежны. Локальные уведомления тоже не имеют ограничений по количеству, а вот удаленные есть. Один общий аспект, который у них обоих, связан с дублированием. По умолчанию они никогда не прибудут. Таким образом, если вы отправите одно и то же уведомление дважды, оно будет отображаться только один раз.

Уже хватит теории. Начнем с создания нового приложения. Я назову это WotsApp. Вам тоже следует использовать SwiftUI, раз уж я собираюсь. Конечно, мы начинаем с разрешений, которые бывают двух уровней. Вверху вы можете включить / отключить все уведомления. На один уровень ниже вы можете различать типы.

Хорошо, первое, что нам нужно сделать в нашем коде, - это спросить разрешение на использование уведомлений. Откройте свой AppDelegate и создайте для него расширение. Сделайте его делегатом UNUserNotificationCenterDelegate.

Добавьте этот код и убедитесь, что вы вызываете его из своего didFinishLaunchingWithOptions метода.

Затем создайте новый класс и назовите его LocalNotification.swift. Добавьте к нему этот код:

Это создает базовый локальный объект уведомления, а затем отправляет его на локальное устройство, используя в нашем случае простой четырехсекундный триггер. Чтобы вызвать его, нам нужно перейти в наш ContentView.swift файл и добавить этот код:

Это создаст кнопку, которую вы можете нажать, чтобы активировать локальное уведомление. Запустите, скомпилируйте и посмотрите, что произойдет.

Какие? Ничего не произошло. Что ты сделал не так?

Ничего такого. Такое поведение iOS является преднамеренным. Уведомления не предназначены для того, чтобы вы вызывали их, когда ваше приложение находится на переднем плане, и они не отображаются по умолчанию. Вам нужно внести еще одно изменение в ваше AppDelegate.swift расширение, чтобы оно сработало. Добавьте к нему этот код:

Скомпилируйте и снова запустите. На этот раз это должно сработать как шарм.

Итак, у вас работают локальные уведомления. Хорошее начало. Но подождите ... нам нужны удаленные уведомления. Это уведомления, которые отправляются через сервер или, возможно, другое устройство iOS. Как они работают?

Во-первых, вам нужно получить разрешение на показ уведомлений - такое же разрешение, которое вам нужно для локальных, поэтому вы можете поставить галочку в этом поле. Следующим шагом для удаленных уведомлений является получение идентификатора устройства, на котором вы работаете. Это нужно, чтобы сообщить Apple, куда нужно отправлять удаленные уведомления. Вы можете начать работу с этим кодом, который вам нужно будет добавить в свой appDelegate.swift:

В результате будет получена 64-символьная строка, которая идентифицирует ваше устройство для Apple для уведомлений. Но будьте осторожны: если вы удалите и переустановите свое приложение, это будет другая 64-символьная строка. Второе предостережение, которое я обнаружил при написании этого приложения, заключается в том, что Apple переместила на нем столбы ворот. Таким образом, это будет работать на iOS 13, но я никогда не тестировал его на iOS 12, и он может сломаться на iOS 14. Проверьте с помощью Stack Overflow, который всегда является отличным источником для понимания подобных вещей.

Но прежде чем попробовать, нужно добавить возможность получать push-уведомления. Щелкните цель вашего проекта Xcode, перейдите к разделу «Подписание и возможности» и добавьте (со знаком «плюс» рядом со словом «Возможности») Push-уведомления.

После этого вы можете скомпилировать и запустить проект. На этот раз в консоли должен появиться 64-символьный шестнадцатеричный код. Хорошо, именно здесь большинство гидов советуют вам загрузить приложение для его тестирования. Я не собираюсь этого делать. Мы все здесь программисты. Нам нужен код, а не использование чужих приложений.

Глава 2

Теперь вам нужно проверить полученное заклинание. Для начала нам нужно войти в вашу учетную запись Apple и получить закрытый ключ, который вы будете использовать в своем запросе на публикацию уведомлений. Откройте веб-браузер и войдите в свою учетную запись Apple Developer. На странице "Обзор" вы увидите вкладку, которая называется Сертификаты, идентификаторы и профили.

Нажмите на него, а затем нажмите на элемент под названием «Ключи» на левой вкладке. Оказавшись там, вы можете нажать на белый плюс в синем круге. Вы должны увидеть экран конфигурации, который выглядит примерно так. Обратите внимание, что вы можете создать только два ключа типа APNS, поэтому используйте их с умом.

Нажмите «Зарегистрироваться» и подождите немного. После регистрации обратите особое внимание на идентификатор ключа, который появится на странице. Вам это понадобится позже.

Хорошо, теперь скачайте свою подпись. Он будет содержаться в файле с расширением .p8. Ни одно из приложений в стандартной OS X не понимает, что такое файл .p8, и вы не сможете открыть его в обычном режиме. Но мы закрываем его здесь, и мне нужно, чтобы содержимое .p8 двигалось вперед. Перейдите в раздел «Загрузки», щелкните файл правой кнопкой мыши и откройте его с помощью приложения TextEdit. Нет, это приложение не рекомендуется для открытия файлов .p8. Тебе придется заставить его руку. Конечно, если вы такой же старомодный парень, как я, вы можете использовать что-то вроде редактора vi в приложении терминала, чтобы открыть его.

Как только вы его откроете, вы увидите вот такое содержимое.

-----BEGIN PRIVATE KEY-----
MIGTAgVAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgl8Kij2y6acAgp1FZ
BHqI6T/Bv4bBgndxuVr1IfuYhemgBgYIKoZIzj0DAQehRANCAASweAt5jGR5H1Vf
QmlPyVVa2hn8jPLxdg0wHyP/xpXbJ5kGunlkXomLh8k+d31tWKKQF2QTzPCzckyi
p0aHWAWG
-----END PRIVATE KEY-----

Это секретный закрытый ключ, который вы будете использовать для шифрования сообщений, отправляемых в Apple. Хорошо, вернемся к кодированию. Снова откройте свой проект WotsApp и создайте еще один класс с именем RemoteNotifications.swift. Добавьте к нему два фрагмента данных, которые мы только что извлекли:

Да, это три цитаты. Тебе понадобится весь шебанг. А теперь о том, что, как мне кажется, некоторые читатели могут найти наиболее пугающим. Для этого нам понадобится сторонняя библиотека. Библиотека, которую мы ищем, была написана IBM. Google библиотека swift jwt. Вам нужно вернуться по этой ссылке. Щелкните ссылку, и вы окажетесь в GitHub и увидите этот репозиторий:

Скопируйте URL-адрес и вернитесь в проект Xcode. Щелкните синий значок ПРОЕКТА, а затем вкладку «Пакеты Swift».

Щелкните + и вставьте имя пакета IBM-Swift / Swift-JWT в появившееся диалоговое окно.

Нажмите «Далее», подождите и посмотрите, как он все проверит. Наконец, нажмите кнопку «Готово».

Если предположить, что все работает как часы, теперь в ваш проект должна быть включена библиотека SwiftJWT. Вернитесь к классу RemoteNotifications и импортируйте новую библиотеку. Скомпилируйте его, чтобы убедиться, что все работает. Вы не должны получить никаких ошибок. Не волнуйтесь, это была самая нервная часть. Теперь все должно быть гладко.

Следующим шагом является создание полезной нагрузки, которую мы можем отправить на сервер уведомлений Apple. Полезная нагрузка JSON. Вот один для вашего проекта:

Yes, it is another magic number of sorts we’re adding. Don’t worry, I am just doing this to get things going. Now for good measure, to make sure you didn’t mistype anything here, add this code to your RemoteNotification class:
private var jsonObject: [String: Any] = ["aps":["badge":2,"category":"mycategory","alert":["title":"What, where, who, when, how","body":"You must be kidding"]]]

Создайте экземпляр вашего RemoteNotification класса в ContentView.swift - как вы это делали с классом LocalNotification - и запустите его, чтобы убедиться, что все в порядке. Вы также можете создать для него вторую кнопку. Вы должны получить сообщение в консоли, подтверждающее, что ваш слепок JSON действителен:

Теперь вы готовы использовать библиотеку IBM. Определите две из трех частей, составляющих веб-токен JSON, добавив этот код в свой RemoteNotification.swift postNotification метод:

Здесь есть два поля, для которых требуются разные значения для показанного кода. kid: - это Key ID вашего закрытого ключа, который мы описали ранее. А атрибут iss: - это идентификатор вашей группы, который вы сможете найти на странице членства в учетной записи Apple.

Определив первые две части, теперь вам нужно использовать свой закрытый ключ для создания третьей части. Это ваш веб-токен JSON.

Последний шаг в этой головоломке - позвонить в службу APNS в Apple. Несколько дополнительных примечаний:

  • URL-адрес, показанный в коде, предназначен для песочницы. Для производства вам нужно использовать немного другой.
  • Упомянутый здесь токен - это 64-символьная строка, которую мы получили при регистрации нашего устройства в Apple в главе 1.
  • apns-topic - это идентификатор пакета вашего проекта, а jwtString - это только что созданный нами веб-токен JSON.

Скомпилируйте его и исправьте ошибки для домашнего задания. Ладно, шучу. Ошибка должна быть только одна - необходимость сделать RemoteNotifications класс URLSessionDelegate. Последний фрагмент этого кода:

class PostController: NSObject,URLSessionDelegate {

Все, что вам нужно сделать сейчас, это вызвать новый класс RemoteNotification из интерфейса SwiftUI. Код, показанный ниже, предназначен для полноты:

Запустите приложение на реальном устройстве и нажмите кнопку на пульте дистанционного управления. Вы должны получить уведомление, которое выглядит следующим образом:

Очевидно, уведомление будет не от Noob. Это будет из WotsApp. На случай, если что-то пошло не так, и вы не вернули этот волшебный код ошибки 200 при публикации, вот таблица, которая поможет вам отладить то, что у вас получилось:

  • 200 - Успех.
  • ошибка 400, неверный запрос.
  • 403 - Произошла ошибка сертификата или токена аутентификации поставщика.
  • 405 - Запрос использовал неверное значение :method. Поддерживаются только запросы POST.
  • 410 - токен устройства больше не активен для темы.
  • 413 - Полезная нагрузка уведомления была слишком большой.
  • 429 - сервер получил слишком много запросов на один и тот же токен устройства.
  • внутренняя ошибка сервера 500.
  • 503 - Сервер выключается и недоступен.

Заключение

Я собираюсь опубликовать главу 3 в ближайшие дни. Нам предстоит многое сделать, чтобы запустить этот WotsApp в рабочее состояние. Читать дальше.