Поясним как выглядит общая схема. Есть три актора - мобильное приложение (устройство) -получатель push-сообщения; приложение-сервер, которое является отправителем сообщений; FCM - сервис-провайдер.
Провайдер содержит список возможных приложений-получателей, он получает от приложения-сервера текст уведомления вместе с идентификатором устройства-получателя и передает его по сети интернет на конкретное мобильное устройство. Какое именно - определяется средствами Google, установленными на этом устройстве. Приложение на мобильном устройстве создает определенный идентификатор этого устройства, передает его приложению-серверу, под ним же устройство зарегистрировано в сервисах Google. Приложение сервер регистрируется в сервисе FCM, после этого оно может аутентифицироваться и передавать в сервис сообщения, которые сервису необходимо отправлять получателям.
Ставилась задача выполнить все средствами платформы 1С, без привлечения сторонних библиотек.
Шаг 1.
Подготовка.
Регистрируемся в сервисе FCM по адресу https://console.firebase.google.com/.
Создаем свои проект и приложение. Важные данные на этом этапе: Project ID и Project number.
Затем надо скачать в разделе App файл google-service.json, он будет нужен нам на этапе сборки мобильного приложения.
Шаг 2.
Получение файла закрытого ключа.
На этом шаге необходимо перейти в раздел Service accounts и сформировать json-файл закрытого ключа. Этот файл нам нужен будет для использования непосредственно в код. Отнеситесь к нему как к конфиденциальной информации, получивший его сможет рассылать сообщения от вашего имени.
Шаг 3.
Получение access-токена.
Перед отсылкой сообщения для рассылки в FCM, нам надо авторизоваться в сервисах Google, чтобы получить access-token. Этот токен будет использоваться при отсылке сообщений в сервис.
Авторизация происходит по OAuth2, для нее мы формируем JWT-токен, подписываем его ранее полученным закрытым ключом и отсылаем на адрес авторизации Google.
Есть некоторые особенности, которые надо проговорить отдельно.
Шаг 3.1.
Подпись JWT-токена.
После создания токен подписывается приватным ключом по RS256 (RSASSA-PKCS1-v1_5 с SHA256). Тут есть нюанс: как понятно по наименованию алгоритма, взятому из документации платформы, метод Подписать() объекта ТокенДоступа просит на вход ключ в формате PKCS#1 v1.5., а FCM выдает закрытый ключ в более продвинутом стандарте PKCS#8. Если подавать его в метод в исходном виде, то получим сообщение "Ошибка создания подписи". Пришлось написать функцию-конвертер. Очень неудобно, собственно, именно на разбор схем кодирования и работу с бинарными данными ушло большое количество времени, надеюсь, этот пробел разработчики платформы устранят и метод подписи будет принимать ключ любого стандарта, "разбираясь" с ним внутри своей реализации. В самом методе шифрования, к счастью, разбираться не пришлось.
В стандарте на PKCS#8 (он сам не очень большой) в разделе 5 Private-Key Information Syntax написано, что нужный нам приватный ключ есть один из реквизитов некоторой структуры.
Соответственно, нам надо прочитать этот реквизит, пропустив последовательно все байты, что встретятся до него - пропускаем заголовок SEQUENCE, реквизиты version и privateKeyAlgorithm. Здесь мы смотрим, как кодируются поля структуры и соответственно выполняем побайтовое чтение.
Проще всего проверить полученный на выходе функции преобразования новый ключ при помощи утилиты openssl. Сохраните ключ в текстовый файл, и выполните команду в консоли:
openssl rsa --in text.key -check -noout
Если все в порядке, утилита так и напишет. Ключ check - проверка, noout - не показывать проверяемые ключ на экране. Если нет - косяк при реализации функции (да, было, получилось не сразу)).
Шаг 3.2.
Токен готов и подписан. Обращаю внимание на параметры scope и aud. В scope надо указать правильную область действия, в aud - адрес сервера, для которого предназначен формируемый токен. При ошибке в этих полях токен не будет принят.
Что может пойти не так на этом этапе, если все сделали вроде бы корректно?
- Ответ сервера без реквизита access_token.
Если вы получаете структуру только с одним реквизитом id_token, то это некорректный ответ. Сервер просто выдал вам токен идентификации. Надо проверить поле запроса уровней доступа JWT-токена, в нем должно быть указано конкретное значение https://www.googleapis.com/auth/firebase.messaging вместо обобщенного https://googleapis.com. - Ошибка 400.
Ваша авторизация, генерация JWT и подпись закрытым ключом работают нормально. Подвела генерация токена (идентификатора) получателя, этого мы еще коснемся.
- Ошибка 404.
Эта ошибка означает, что токен устройства, на который вы отправляете пуш-уведомление, больше недействителен на серверах Google. Сервис FCM считает это устройство отписанным от уведомлений. Надо получить новый идентификатор устройства.
Шаг 4.
Получение идентификатора мобильного устройства.
В мобильном приложении нам надо получить идентификатор устройства, по которому устройство будет определяться провайдером как получатель уведомлений. Как написано в документации, идентификатор может периодически меняться, поэтому его надо получать регулярно и пересылать приложению-серверу.
Этот фрагмент кода исполняется каждый раз при старте приложения на мобильном устройстве. Он получает все идентификаторы и отправляет их на http-сервис. Также выполняется подключение обработчика push-уведомлений.
Идентификатор устройства меняется не только при смене устройства, но и при переустановке приложения даже той же самой версии, поэтому логично связывать идентификаторы с учетной записью пользователя, это позволит оперировать не обезличенными идентификаторами.
Странно отрабатывает метод ПолучитьИдентификаторПодписчикаУведомлений, для телефона марки Huawei, подключенного через кабель возвращает тип подписчика HPK, а после развертывания собранного приложения возвращает тип FCM.
Шаг 5.
Отправка уведомления в сервис FCM.
Само уведомление - это простая структура, отправляемая в теле запроса на адрес fcm.googleapis.com. Адрес ресурса формируется с использованием имени проекта /v1/projects/project_id/messages:send.
При отправке как раз и используется ранее полученный токен, он указывается в заголовке Authorization.
Если вам надо тестировать отправку уведомлений без реальной доставки пользователями, то формируйте сообщение с дополнительным тегом "validate_only": true, описано тут https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send.
Шаг 6.
Реализация процедуры-обработчика уведомлений.
Решение определяется исключительно логикой работы приложения, как минимум необходимо наличие в коде объявления процедуры.
Шаг 7.
Сборка приложения.
При сборке надо включить в дистрибутив полученный файл google-services.json. Необходимо, чтобы полный идентификатор приложения google в сборщике полностью совпадал с Package name в консоли сервиса FCM, в противном случае сборщик будет выдавать ошибку.
Используемые версии ПО
Разработка велась на Windows 11 26H2, платформе 8.5.4.1306, мобильной платформе 8.5.4.28, Apache 2.4. Тестировалось на устройстве Huawei c OC Android и надстройкой EMUI и установленными сервисами microG 0.3.16.252432-hw и GBox 1.8.3.61. Для них в настройках приложений необходимо разрешить уведомления, процесс не описываю, т.к., судя по информации из интернета, последовательность действий зависит от установленных версий. По итогу, отправленные с ПК уведомления успешно приходят на устройство, даже если мобильная платформа закрыта, если выгружена из памяти.
Прилагаются файлы приложений, на которых отлаживался обмен между компонентами системы, архив с файлами dt и cf приложения-сервера и мобильного приложения, apk-архивы собранного мобильного приложения для разных платформ, краткая инструкция по настройке взаимодействия компонентов. Приложение сервер содержит обработку для рассылки уведомлений на мобильное устройство, есть тестовое наполнение информационной базы. Это прототипы для понимания как все работает, не более. Без доработки нельзя применять в реальных проектах. Например, необходим обмен между мобильным приложением и приложением-сервером по https, иной подход к хранению закрытого ключа и некоторые другие детали.
Возможна отсылка сообщений не только для мобильных приложений, созданных на базе платформы 1С, но и для приложений, написанных на любом языке, при условии, что приложение сможет выдать идентификатор устройства во внешний сервис.
В планах теперь познакомиться с Huawei Push Kit.
Какими ресурсами надо пользоваться:
- https://its.1c.ru/db/v854doc#bookmark:dev:TI000001540 Глава 29. Разработка для мобильных устройств. Раздел 28.3.6.12. Работа с уведомлениями. Читается тяжело, есть нюансы.
- https://habr.com/ru/articles/842056/. Хорошая статья про устройство JWT-токена.
- https://firebase.google.com/docs/cloud-messaging?hl=ru. Документация сервиса FCM.
- https://developers.google.com/identity/protocols/oauth2?hl=ru. Документация по авторизации OAuth2 для доступа к API Google.
- //infostart.ru/1c/tools/1518089/?ID=1518089#. Статья на Infostart, но приведенное там решение уже не работает.
- https://datatracker.ietf.org/doc/html/rfc5208. Описание алгоритма RSA256 PKCS#8.
- https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der. Исключительно полезный мануал по структурам данных, используемых в криптографии.
Остались вопросы?
Для получения дополнительной информации и помощи в настройке модуля под нужды вашего бизнеса — оставьте заявку
