Отправка Push-уведомлений через сервис Firebase Cloud Messaging по протоколу FCM HTTP v1 API

24.03.21

Интеграция - WEB-интеграция

При разработке нативного приложения Android для ТСД, в котором присутствует функционал отображения задач кладовщикам, созданных в 1С, возникла необходимость отправлять push-уведомления о появлении новых задач. Для отправки таких уведомлений было решено использовать сервис Firebase Cloud Messaging (FCM). Так как для 1С, в отличии от других языков программирования, не существует готовых библиотек, что вполне логично, то очевидным способом отправки является использование протокола HTTP. Однако, существующая информация в интернете в части 1С содержит только сведений об отправке push-уведомлений через этот сервис с использованием устаревшего протокола HTTP Firebase Cloud Messaging. Сам Google не рекомендует использовать данный протокол и настоятельно склоняет к переходу на новый протокол FCM HTTP v1 API. Что ж, пришлось разбираться самостоятельно.

Скачать файлы

Наименование Файл Версия Размер
Библиотека отправки Push уведомлений FCM (расширение)
.cfe 21,64Kb
33
.cfe 1.0.1.2 21,64Kb 33 Скачать

Авторизация для выполнения запросов к сервисам Google.

Основным отличием, помимо формата самого отправляемого сообщения, является способ авторизации. В отличии от постоянного ключа (Web API Key, который, нужно заметить, для новых проектов вообще не доступен), который передаётся в заголовке при использовании старого протокола, теперь необходимо отправлять ключ доступа (access token), срок действия которого максимально может составлять один час. По истечению срока действия необходимо получать новый ключ доступа для доступа к сервисам Google. Сделано это для увеличения безопасности. Если такой ключ доступа попадёт в посторонние руки, то максимум через час он уже будет недействителен.

Так же в качестве плюсов нового протокола приводится более эффективная настройка сообщений для разных платформ. Можно указать общие параметры уведомления и настроить дополнительные определения для конкретных платформ (Android, APNS, Web push protocol).

И если отправка самого push-уведомления через сервис FCM не вызывает сложностей (достаточно сформировать JSON объект согласно описанию https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?hl=ru и отправить его в POST запросе по адресу https://fcm.googleapis.com/v1/projects/{идентификатор-проекта}/messages:send, указав в заголовке ключ доступа, речь о котором идёт выше), то вот как получать этот ключ пришлось разбираться более детально.

Можно, конечно, получать ключ с использованием авторизации пользователя через OAuth2. Это когда открывается форма c веб-страницей, в которой выполняется переход на сайт Google для авторизации, а после входа в свою учётную запись возвращается ключ доступа. Потом периодически по истечению срока действия ключа выполняется HTTP запрос для обновления этого ключа уже без участия пользователя. Такой метод использовался мной для обращения к сервисам Google Карты и Календарь. Но в данной ситуации захотелось выполнять авторизацию (получать ключ доступа) от имени сервисного аккаунта, т. е. вообще без участия пользователя.

Для выполнения такой авторизации используется JSON Web Token, который подписывается приватным ключом и отправляется на сервер авторизации. В ответ приходит ключ доступа. Когда срок действия этого ключа истекает, необходимо повторить процесс авторизация для получения нового ключа.

Подробно можно ознакомиться здесь: https://developers.google.com/identity/protocols/oauth2/service-account#httprest

Далее мы рассмотрим вкратце, как это сделать на 1С и по-русски)).

Получение приватного ключа для выполнения авторизации.

В первую очередь, нам понадобится приватный ключ, который можно скачать в настройках проекта Firebase. Как создавать такой проект мы рассматривать не будем, информации на эту тему достаточно в интернете, в том числе и на этом сайте. А если вы ранее использовали сервисы Firebase (например, для отправки push-уведомлений по устаревшему протоколу), то такой проект у вас уже есть.

Переходим к настройкам своего проекта Firebase на закладку Service Accounts и нажимаем кнопку Generate new private key. Браузером будет скачан JSON файл с данными приватного ключа. Внимание! Храните этот файл в надёжном хранилище и не допускайте его утечки.

Далее необходимо сгенерировать JSON Web Token (JWT) и подписать его приватным ключом для отправки на сервер авторизации.

Чтение приватного ключа в 1С.

Приватный ключ является объектом JSON. Ниже приведён пример содержимого ключа.

{
  "type": "service_account",
  "project_id": "fir-push-for-1c",
  "private_key_id": "355...b06",
  "private_key": "-----BEGIN PRIVATE KEY-----\n[СОДЕРЖИМОЕ ПРИВАТНОГО КЛЮЧА]\n-----END PRIVATE KEY-----\n",
  "client_email": "firebase-...@fir-push-for-1c.iam.gserviceaccount.com",
  "client_id": "106...782",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-hmjr4%40fir-push-for-1c.iam.gserviceaccount.com"
}

Этот ключ понадобится для создания подписанного JWT, поэтому необходимо его прочитать из файла и преобразовать в Структуру.

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл("{путь_к_файлу_секретного_ключа}");

СекретныйКлюч = ПрочитатьJSON(ЧтениеJSON);

ЧтениеJSON.Закрыть();

Создание JWT.

JWT является строкой и состоит из трёх частей, разделённых точкой: заголовок, данные авторизации (тело), цифровая подпись. Каждая часть представляет собой строку Base64.

{Заголовок Base64}.{Тело Base64}.{Подпись Base64}

Для получения подписи необходимо подписать приватным ключом первые две части JWT.

{Заголовок Base64}.{Тело Base64}

И добавить полученное значение подписи в конец JWT через точку.

Формат заголовка JWT.

Формат заголовка представляет собой JSON объект, содержащий два параметра:

  • alg – тип алгоритма, по которому формируется подпись. Всегда используется алгоритм RSA SHA-256, поэтому значение этого параметра RS256.
  • typ – тип формата. Всегда JWT token, поэтому значение этого параметра JWT.

Таким образом заголовок будет всегда одним и тем же:

{"alg": "RS256", "typ": "JWT"}

В 1С можно просто устанавливать эту строку. Для преобразования простой строки в Base64 можно создать соответствующую процедуру.

Функция СтрокаВСтрокуBase64(ИсходнаяСтрока)
	
	Поток = Новый ПотокВПамяти;
	
	ЗаписьТекста = Новый ЗаписьТекста(Поток, КодировкаТекста.UTF8);
	ЗаписьТекста.Записать(ИсходнаяСтрока);
	ЗаписьТекста.Закрыть();
	
	ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
	Результат = Base64Строка(ДвоичныеДанные);
	
	// Необходимо так же удалить разделители ВК + ПС
	Результат = СтрЗаменить(Результат, Символы.ВК + Символы.ПС, "");
	
	Возврат Результат;
	
КонецФункции

В результате код получения заголовка JWT будет выглядеть следующим образом.

ЗаголовокJWT = СтрокаВСтрокуBase64("{""alg"":""RS256"", ""typ"":""JWT""}");

Формат данных авторизации (тело JWT).

Тело JWT так же является объектов JSON и содержит следующие параметры:

  • iss – адрес электронной почты сервисного аккаунта проекта Firebase.
  • scope – разрешения, которые необходимы. Для возможности отправлять push-уведомление необходимо разрешение https://www.googleapis.com/auth/firebase.messaging. Со всем значениями можно ознакомиться по адресу https://developers.google.com/identity/protocols/oauth2/scopes.
  • aud – всегда имеет значение https://oauth2.googleapis.com/token.
  • iat – дата, начиная с которой будет действовать полученный ключ доступа. Значение содержит количество секунд, прошедших с 1 января 1970 года.
  • exp – дата окончания действия ключа доступа. Значение содержит количество секунд, прошедших с 1 января 1970 года. Значение не может быть больше даты начала срока действия ключа чем на час (3600 секунд).

Сформировать тело JWT в 1С можно следующим образом.

// Вычисляем количество секунд с 01.01.1970 00:00:00
ДатаВыдачи = ТекущаяУниверсальнаяДата() - '19700101';
// Максимальный срок действия - 1 час (3600 секунд).
ДатаОкончания = ДатаВыдачи + 3600;

// Простой объект JSON сформируем сразу как строку.
ШаблонТела =
"{
|	""iss"": ""%1"",
|	""scope"": ""%2"",
|	""aud"": ""%3"",
|	""exp"": %4,
|	""iat"": %5
|}";
// Необходимые данные подставим из считанного ранее из файла приватного ключа.
Тело = СтрШаблон(ШаблонТела,
	СекретныйКлюч.client_email,
	"https://www.googleapis.com/auth/firebase.messaging",
	СекретныйКлюч.token_uri,
	Формат(ДатаОкончания, "ЧГ="),
	Формат(ДатаВыдачи, "ЧГ="));
	
ТелоJWT = СтрокаВСтрокуBase64(Тело); // Конечный результат должен быть строкой Base64.

Формирование подписи JWT.

После получения строк Base64 заголовка и тела их необходимо соединить через точку и вычислить цифровую подпись полученной строки с использование приватного ключа, содержащемся в скачанном выше файле. К сожалению, встроенные средства криптографии 1С не позволяет это сделать, поэтому для формирования подписи используется внешняя программа OpenSSL.
Для формирования подписи этой программой необходимо выполнить следующую команду системы:

openssl.exe dgst -sha256 -sign <имя_приватного_ключа> -out <имя_файла_подписи> <имя_подписанного_файла>

Таким образом для получения подписи нам необходимо сохранить в файлы на диске полученную строку для подписи и приватный ключ, выполнить указанную выше команду, подставив нужные имена файлов, после чего считать подпись из созданного файла <имя_файла_подписи>.

Создадим вспомогательную процедуру для записи строки в файл на диске. Это должны быть текстовые файлы в формате UTF-8.

Процедура ЗаписатьСтрокуВФайл(Строка, ИмяФайла)
	
	// Используется поток, чтобы записать текст в формате UTF-8 без BOM.
	Поток = Новый ПотокВПамяти;
	
	ЗаписьТекста = Новый ЗаписьТекста(Поток, КодировкаТекста.UTF8, , , Ложь);
	ЗаписьТекста.Записать(Строка);
	ЗаписьТекста.Закрыть();
	
	ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
	ДвоичныеДанные.Записать(ИмяФайла);
	
КонецПроцедуры

Далее реализуем алгоритм по формированию подписи с использованием OpenSSL.

// Создадим временный каталог для хранения файлов.
КаталогФайлов = ПолучитьИмяВременногоФайла();
СоздатьКаталог(КаталогФайлов);

// Зададим имена файлов.
ИмяФайлаКлюча = КаталогФайлов + "\private.key";
ИмяФайлаJWT = КаталогФайлов + "\jwt.txt";
ИмяФайлаПодписи = КаталогФайлов + "\jwt.sgn";

// Запишем подписываемые данные и приватный ключ в файлы.
ДанныеДляПодписи = ЗаголовокJWT + "." + ТелоJWT;
ЗаписатьСтрокуВФайл(ДанныеДляПодписи, ИмяФайлаJWT);
ЗаписатьСтрокуВФайл(СекретныйКлюч.private_key, ИмяФайлаКлюча);

// Сфомируем команду для формирования подписи.
OpenSsl = "<Путь_к_OpenSLL>\bin\openssl.exe";
СтрокаКоманды = OpenSsl + " dgst -sha256 -sign " + ИмяФайлаКлюча + " -out " + ИмяФайлаПодписи + " " + ИмяФайлаJWT;
КодВозврата = Неопределено;

// Выполним команду для формирования подписи.
ЗапуститьПриложение(СтрокаКоманды, , Истина, КодВозврата);

Если КодВозврата <> 0 Тогда
	// Что-то пошло не так.
	УдалитьФайлы(КаталогФайлов);
	ВызватьИсключение СтрШаблон(
		НСтр("ru='Произошла ошибка при подписании JSON Web Token. Код возврата: %1'"),
		КодВозврата);
КонецЕсли; 

// Прочитаем полученную подпись из файла, как двоичные данные.
ДанныеПодписи = Новый ДвоичныеДанные(ИмяФайлаПодписи);

// Преобразуем подпись в строку Base64...
ПодписьJWT = Base64Строка(ДанныеПодписи);
// ... и удалим разделители ВК + ПС
ПодписьJWT = СтрЗаменить(ПодписьJWT, Символы.ВК + Символы.ПС, "");

// Удалим временный каталог с файлами.
УдалитьФайлы(КаталогФайлов);

После того, как получена подпись, можем сформировать итоговый JSON Web Token.

JWT = ЗаголовокJWT + "." + ТелоJWT + "." + ПодписьJWT;

Авторизация и получение ключа доступа с использованием сформированного JWT.

Теперь мы можем выполнить авторизацию и получить ключ доступа для обращения к сервисам Google.

Для этого необходимо выполнить HTTP POST запрос по адресу https://oauth2.googleapis.com/token.

В теле запроса необходимо передать объект JSON, содержащий два параметра:

  • grant_type – всегда содержит значение urn:ietf:params:oauth:grant-type:jwt-bearer.
  • assertion – сформированный выше подписанный JSON Web Token.

Такой запрос будет выглядеть следующим образом.

// В заголовках установим тип содержимого тела - JSON.
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json");

// Простой объект JSON сформируем сразу как строку.
ШаблонЗапроса = 
"{
|	""grant_type"": ""%1"",
|	""assertion"": ""%2""
|}";
ПараметрыЗапроса = СтрШаблон(ШаблонЗапроса,
	"urn:ietf:params:oauth:grant-type:jwt-bearer",
	JWT
);

// Создадим HTTP запрос с нужными параметрами.
Запрос = Новый HTTPЗапрос("token", Заголовки);
Запрос.УстановитьТелоИзСтроки(ПараметрыЗапроса);

// Создадим защищенное HTTPS соединение.
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение("oauth2.googleapis.com", , , , , , ЗащищенноеСоединение);

// И отправим запрос с методом POST на сервер.
Ответ = Соединение.ОтправитьДляОбработки(Запрос);

В ответе придёт JSON объект, содержащий ключ доступа (access_token) и срок действия (дата, после которой ключ станет недействительным).

Произведём чтение этих данных из ответа.

ТелоОтвета = Ответ.ПолучитьТелоКакСтроку();

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоОтвета);

СтруктураОтвета = ПрочитатьJSON(ЧтениеJSON);
	
ЧтениеJSON.Закрыть();

Если Ответ.КодСостояния <> 200 Тогда
	ВызватьИсключение СтруктураОтвета.error_description;
КонецЕсли; 

КлючДоступа = СтруктураОтвета.access_token;
// Определим срок действия ключа, после которого он устареет и необходимо будет
// вновь выполнить авторизацию.
СрокДействия = ТекущаяУниверсальнаяДата() + СтруктураОтвета.expires_in;

// Можно сохранить ключ доступа чтобы не производить авторизацию при каждой отправке сообщения.
// Если в вашей конфигурации используется БСП, то это можно сделать, например, так.
ДанныеКлючаДоступа = Новый Структура("КлючДоступа, СрокДействия", КлючДоступа, СрокДействия);
УстановитьПривилегированныйРежим(Истина);
ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище("GoogleAPI", ДанныеКлючаДоступа);
УстановитьПривилегированныйРежим(Ложь);

Теперь, имея действующий ключ доступа мы может выполнять запросы к сервисам Google, в том числе и для отправки push-уведомлений.

Отправка push-уведомлений.

Как было сказано вначале, для отправки push-уведомлений необходимо сформировать JSON-объект, заполненный необходимыми данными и отправить его по адресу https://fcm.googleapis.com/v1/projects/{идентификатор-проекта}/messages:send, указав в заголовке ключ доступа.

Для этой статьи мной был создан проект Firebase с идентификатором «fir-push-for-1c» (Project ID на закладке General настроек проекта). Поэтому адрес, по которому необходимо отправить push-уведомление будет выглядеть следующим образом: https://fcm.googleapis.com/v1/projects/fir-push-for-1c/messages:send.

Объект JSON называется message и содержит следующий поля:

  • data – произвольные передаваемые данные, которые будут обработаны приложением, получившим push-уведомление. В терминах 1С – это Соответствие, где ключ и значение имеют тип «Строка».
  • notification – объект (в терминах 1С – Структура), описывающий само уведомление (заголовок, текст сообщения и изображение).
  • android – объект, содержащий специфичные параметры для Android устройств (приоритет, цвет сообщение, звук, видимость и прочие параметры).
  • webpush – объект, содержащий параметры протокола Webpush.
  • apns – объект, содержащий специальные параметры службы push-уведомлений Apple.
  • token – идентификатор (токен) получателя. Данный идентификатор должен быть получен от устройства, на которое требуется отправлять уведомления. Получение идентификатора можно реализовать через http-сервис 1С. Например, при запуске мобильного приложения на устройстве Android, разработчик должен реализовать получение этого идентификатора и отправку его в базу 1С через http-сервис. Разработчик 1С должен сохранять этот идентификатор в БД и использовать его при отправке уведомлений на это устройство. Если вы реализовывали отправку уведомлений для приложений на мобильной платформе 1С, то вам должен быть знаком данный механизм (token в таком случае – ИдентификаторПодписчикаДоставляемыхУведомлений.ИдентификаторУстройства).

С подробным описанием этого объекта уведомлений можно ознакомиться по адресу https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?hl=ru.

Напишем код, который отправит простое push-уведомление, содержащее заголовок, текст сообщения и данные о вымышленной задаче (тип задачи и её идентификатор). Заголовок и текст сообщения используются для отображения оповещения на экране устройства, а данные (data) используются непосредственно самим приложением, чтобы «знать» что, собственно говоря, пришло.

// Сформируем объект push-уведомления для отправки.
Уведомление = Новый Структура;
Уведомление.Вставить("token", "<Идентификатор_получателя>");

// Установим необходимые данные.
Уведомление.Вставить("data", Новый Соответствие);
Уведомление.data["task_id"] = "092309280";
Уведомление.data["task_type"] = "check_order";

// Зададим оповещение, отображаемое на экране.
Оповещение = Новый Структура;
Оповещение.Вставить("title", НСтр("ru='Создана новая задача'"));
Оповещение.Вставить("body", НСтр("ru='Проверить сборку ордера на отгрузку 123'"));

Уведомление.Вставить("notification", Оповещение);

// Для Android устройства можем указать дополнительные параметры оповещения,
// например, видимость уведомления.
КонфигурацияAndroid = Новый Структура;
КонфигурацияAndroid.Вставить("notification", Новый Структура("visibility", "PRIVATE"));

Уведомление.Вставить("android", КонфигурацияAndroid);

// Создадим итоговый объект уведомления.
PushСообщение = Новый Структура("message", Уведомление);

// И преобразуем его в JSON строку.
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();

ЗаписатьJSON(ЗаписьJSON, PushСообщение);

ТелоЗапроса = ЗаписьJSON.Закрыть();

// Отправим уведомление через FCM.

КлючДоступа = "<полученный_ранее_ключ_доступа>";

// Если ключ доступа был сохранён в безопасном хранилище, как было показано в коде выше,
// то можно воспользоваться следующим кодом.
УстановитьПривилегированныйРежим(Истина);
ДанныеКлючаДоступа = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища("GoogleAPI");
УстановитьПривилегированныйРежим(Ложь);

// Проверка сохраненного ключа доступа
КлючДоступаАктален = Тип(ДанныеКлючаДоступа) = Тип("Структура")
	И ТекущаяУниверсальнаяДата() < ДанныеКлючаДоступа.СрокДействия;
Если Не КлючДоступаАктален Тогда
	// Необходимо выполнить повторную авторизацию.
	// Как вариант, можно обновлять ключ доступа регламентным заданием по рассписанию.
	//....
КонецЕсли; 

КлючДоступа = ДанныеКлючаДоступа.КлючДоступа;

АдресРесурса = СтрШаблон("/v1/projects/%1/messages:send", "<Идентификатор_вашего_проекта_Firebase>");

Заголовки = Новый Соответствие;
// Заголовок авторизации с полученным ранее ключом доступа.
Заголовки.Вставить("Authorization", "Bearer " + КлючДоступа);
// Заголовок, указывающий тип содержимого тела запроса.
Заголовки.Вставить("Content-Type", "application/json");
	
Запрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса);

Соединение = Новый HTTPСоединение("fcm.googleapis.com", , , , , , Новый ЗащищенноеСоединениеOpenSSL);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Таким образом мы выполнили авторизацию, получили ключ доступа и отправили push-уведомление.

Библиотека отправки Push уведомления через Firebase Cloud Messaging.

"Для облегчения жизни" описанный выше код был собран в отдельные процедуры и функции для авторизации и отправки push-уведомлений в отдельную библиотеку, выполненную в виде расширения. Её можно подключить к своей конфигурации как расширение, либо добавить общие модули из этой библиотеки непосредственно в конфигурацию своего прикладного решения. Дополнительно необходимо будет реализовать получение идентификаторов получателей от мобильных устройств и загрузку приватного ключа из файла JSON.

Описание процедур и функций библиотеки.

Выполнение авторизации.

Для выполнения авторизации предназначен общий модуль fcm_АутентификацияGoogleAPIКлиентСервер, который содержит одну экспортную функцию ПолучитьКлючДоступаGoogleAPI.

Синтаксис:

ПолучитьКлючДоступаGoogleAPI(<СекретныйКлюч>, <Разрешения>, <ПутьКOpenSsl>, <СрокДействия>)

Параметры:

<СекретныйКлюч> (обязательный) - Строка - строка в формате JSON, содержащая данные секретного ключа. Как получать эту строку должен определять разработчик прикладного решения. Она может быть прочитана из файла на диске (например, можно поместить этот файл в папку, недоступной для чтение обычным пользователям, но доступной серверу 1С), получена из макета конфигурации (не самое удачное решение хранить таким образом конфиденциальные данные) или получена каким-либо другим образом.

Разрешения (обязательный) - Строка - требуемые разрешения от сервисов Google. Для отправки push-уведомлений необходимо указать значение https://www.googleapis.com/auth/firebase.messaging. Данное значение можно получить вызвав функцию библиотеки fcm_УведомленияКлиентСервер.РазрешениеFCMОтправкаУведомлений().

ПутьКOpenSSL (обязательный) - Строка - путь к программе OpenSSL для вычисления подписи JSON Web Token.

СрокДействия (необязательный) - Число - срок действия ключа доступа в секундах. Если не указан, то по умолчанию используется максимально возможное значение: 3600 секунд (1 час).

Возвращаемое значение:

Строка - ключ доступа (access token) к сервисам Google, полученный в результате авторизации.

Описание:

Выполняет авторизация на сервере Google и возвращает ключ доступа. В случае возникновения ошибки при авторизации будет вызвано Исключение.

Отправка push-уведомлений.

Для отправки push-уведомлений предназначен общий модуль fcm_УведомленияКлиентСервер. Данный модуль содержит функцию ОтправитьУведомление для отправки уведомлений и ряд служебный функций для формирования объектов уведомления.

ОтправитьУведомление

Синтаксис:

ОтправитьУведомление(<Уведомление>, <ПроектFirebase>, <КлючДоступа>)

Параметры:

Уведомление (обязательный) - Структура - структура, описывающая push-уведомление. Для формирование данной структуры можно использовать вспомогательные функции модуля fcm_УведомленияКлиентСервер (см. ниже).

ПроектFirebase (обязательный) - Строка - идентификатор проекта сервиса  Firebase.

КлючДоступа (обязательный) - Строка - ключ доступа к сервису Firebase Cloud Messaging.

Возвращаемое значение:

Строка - идентификатор Firebase Cloud Messaging отправленного уведомления.

Описание:

Выполняет отправку push-уведомления через Firebase Cloud Messaging. В случае возникновения ошибки при отправке уведомления будет вызвано Исключение.

Вспомогательные функции для создания структуры, описывающей push-уведомление.

СоздатьУведомление - возвращает структуру, описывающую push-уведомление и инициализированную пустыми значениями.

СоздатьОповещение - возвращает структуру, описывающую оповещение (Notification) и инициализированную пустыми значениями.

СоздатьКонфигурациюAndroid - возвращает структуру, описывающую конфигурацию push-уведомление для Android и инициализированную пустыми значениями.

СоздатьОповещениеAndroid - возвращает структуру, описывающую оповещение для Android (AndroidNotification) и инициализированную пустыми значениями.

СоздатьКонфигурациюWebPush - возвращает структуру, описывающую конфигурацию push-уведомление для Webpush protocol и инициализированную пустыми значениями.

СоздатьКонфигурациюAPNS - возвращает структуру, описывающую конфигурацию push-уведомление для Apple Push Notification Service и инициализированную пустыми значениями.

НастройкиСветовогоОповещения - возвращает структуру, описывающую настройки светового оповещения (LightSettings) и инициализированную пустыми значениями.

ЦветRGBA(R, G, B, A) - возвращает структуру, описывающую цвет RGBA:

  • R - Число - красный (red), дробное число от 0 до 1;
  • G - Число - зеленый (green), дробное число от 0 до 1;
  • B - Число - синий (blue), дробное число от 0 до 1;
  • A - Число - значение альфа-канала, определяющее прозрачность (alpha), дробное число от 0 до 1.

Ниже приведён пример отправки такого же push-уведомления, которое было приведено выше с использованием библиотеки.

// Сформируем объект push-уведомления для отправки.
Уведомление = fcm_УведомленияКлиентСервер.СоздатьУведомление();
Уведомление.token = "<Идентификатор_получателя>";

// Установим необходимые данные.
Уведомление.data["task_id"] = "092309280";
Уведомление.data["task_type"] = "check_order";

// Зададим оповещение, отображаемое на экране.
Оповещение = fcm_УведомленияКлиентСервер.СоздатьОповещение();
Оповещение.title = НСтр("ru='Создана новая задача'");
Оповещение.body = НСтр("ru='Проверить сборку ордера на отгрузку 123'");

Уведомление.notification = Оповещение;

// Для Android устройства можем указать дополнительные параметры оповещения,
// например, видимость уведомления.
ОповещениеAndroid = fcm_УведомленияКлиентСервер.СоздатьОповещениеAndroid();
ОповещениеAndroid.notification_priority = fcm_УведомленияКлиентСервер.ПриоритетОповещенияВысокий();
ОповещениеAndroid.visibility = fcm_УведомленияКлиентСервер.ВидимостьУведомленияПриватное();

КонфигурацияAndroid = fcm_УведомленияКлиентСервер.СоздатьКонфигурациюAndroid();
КонфигурацияAndroid.priority = fcm_УведомленияКлиентСервер.ПриоритетAndroidВысокий();
КонфигурацияAndroid.notification = ОповещениеAndroid;

Уведомление.android = КонфигурацияAndroid;

УстановитьПривилегированныйРежим(Истина);
ДанныеКлючаДоступа = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища("GoogleAPI");
УстановитьПривилегированныйРежим(Ложь);

// Проверка сохраненного ключа доступа
КлючДоступаАктален = Тип(ДанныеКлючаДоступа) = Тип("Структура")
	И ТекущаяУниверсальнаяДата() < ДанныеКлючаДоступа.СрокДействия;

Если Не КлючДоступаАктален Тогда
	// Ключ доступа не актуален. Необходимо выполнить авторизацию и сохранить новый ключ доступа.
		
	СрокДействия = 600; // 10 минут
	КлючДоступа = fcm_АутентификацияGoogleAPIКлиентСервер.ПолучитьКлючДоступаGoogleAPI(
		"<Передайте_загруженный_ключ_доступа>",
		fcm_УведомленияКлиентСервер.РазрешениеFCMОтправкаУведомлений(),
		СрокДействия
	);
	
	ДанныеКлючаДоступа = Новый Структура;
	ДанныеКлючаДоступа.Вставить("КлючДоступа", КлючДоступа);
	ДанныеКлючаДоступа.Вставить("СрокДействия", ТекущаяУниверсальнаяДата() + СрокДействия);
	
	УстановитьПривилегированныйРежим(Истина);
	ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище("GoogleAPI", ДанныеКлючаДоступа);
	УстановитьПривилегированныйРежим(Ложь);
	
Иначе
	
	КлючДоступа = ДанныеКлючаДоступа.КлючДоступа;
	
КонецЕсли; 

ИдентификаторУведомления = fcm_УведомленияКлиентСервер.ОтправитьУведомление(
	Уведомление, "<идентификатор_проекта_firebase>", КлючДоступа);

Сообщить(СтрШаблон(НСтр("ru='Уведомление отправлено. Идентификатор: %1'"), ИдентификаторУведомления));

Так же в состав библиотеки входит обработка, демонстрирующая отправку push-уведомлений.

Условия использования библиотеки отправки Push уведомления через Firebase Cloud Messaging.

Исходный код библиотеки отправки Push уведомления через Firebase Cloud Messaging распространяется под лицензий Apache 2.0. Вы можете свободно использовать, изменять и распространять его, в том числе и в коммерческих целях с обязательным указанием авторства. Подробнее см. текст лицензии http://www.apache.org/licenses/LICENSE-2.0

Исходный код также доступен на github: https://github.com/ltfriend/FCMPushFor1C

Работа была протестирована на версии 1С:Предприятия 8.3.18.1363.

push push-уведомления firebase fcm fcm-push firebase-push

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

Сайты и интернет-магазины WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    15747    10    17    

11

Интеграция 1С — Битрикс24. Обмен задачами

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс24. Разработка имеет двухстороннюю синхронизацию 1С и Битрикс24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (8.3.18.1289). При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

5040 руб.

04.05.2021    17549    6    15    

13

Интеграция с сервисом vetmanager

WEB-интеграция Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    16360    42    49    

23

[Расширение] БОР-Навигатор.Культура

Зарплата Бюджетный учет WEB-интеграция Обмен с ГосИС Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бюджетный учет Платные (руб)

Расширение конфигурации, включающее в себя объекты, необходимые для подготовки и сдачи отчета "Штатная численность" системы "БОР-Навигатор.Культура" в программе "1С:Зарплата и кадры государственного учреждения", редакция 3.1.

8400 руб.

01.02.2019    25741    9    0    

7

Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС

Обмен с ГосИС WEB-интеграция Платформа 1С v8.3 Управляемые формы 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия государственного учреждения 1С:Документооборот 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Платные (руб)

Обработка является альтернативой механизму, разработанному фирмой 1С и заполняющему реквизиты контрагента по ИНН или наименованию. Не требуется действующей подписки ИТС. Вызывается как внешняя дополнительная обработка, т.е. используется, непосредственно, из карточки контрагента. Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС (egrul.nalog.ru) для БП 2.0, БП 3.0, БГУ 1.0, БГУ 2.0, УТ 10.3, УТ 11.x, КА 1.1, КА 2.x, УПП 1.x, ERP 2.x, УНФ 1.5, УНФ 1.6, УНФ 3.0, ДО 2.1

2400 руб.

28.04.2016    88580    160    215    

318
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Steelvan 302 24.03.21 12:14 Сейчас в теме
Как вариант, вместо родного мобильного приложения можно было обойтись родной 1С компонентой для вебгнезд и веб-мордой на html для мобильного обозревателя.
А вообще вариантов и технологий для решения подобных задач достаточно много, да.
2. rozer 306 30.03.21 17:03 Сейчас в теме
интересно а это Push и локальные уведомления еще актуально ? И 1С не переделала свой 1С:Центр уведомлений c GCM на FCM ?
3. Rootking2010 31.03.21 17:34 Сейчас в теме
Спасибо, очень своевременно сделали статью. Никак не получалось с авторизацией на FCM, пришлось переделать через pusher.com, а вот с Вашим расширением всё получилось и убрали не нужное звено.
4. user1098176 08.06.21 14:37 Сейчас в теме
выпадает в ошибку:
"error": {
"code": 403,
"message": "SenderId mismatch",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode": "SENDER_ID_MISMATCH"
6. viki_glebova 19.09.21 11:56 Сейчас в теме
(4)Добрый день. У меня тоже такая же ошибка

Ошибка при отправке push-уведомления: SenderId mismatch


Вы разобрались?
7. dimasts 22 11.10.21 20:06 Сейчас в теме
13. dimasts 22 30.06.22 20:56 Сейчас в теме
(4) Получилось разобраться?
5. user642047_ziborov.roman 29.07.21 14:47 Сейчас в теме
Спасибо вам за подробную статью. Нигде не видел столь подробного примера работы с новым протоколом firebase.

С помощью вашего расширения действительно удалось отправить сообщение мобильному приложению 1с. К самому расширению вопросов нет. Всё просто супер.

Но у меня есть трудности. Возможно вы сталкивались с подобными в своей практике. Сейчас буксую на двух вопросах:

1.
Есть ли возможность использовать для ловли push в мобильном приложении 1с метод ДоставляемыеУведомления.ПодключитьОбработчикУведомлений ?

В вашей статье есть упоминание о передаче данных:
"data – произвольные передаваемые данные, которые будут обработаны приложением, получившим push-уведомление"

В расширении вашей статьи не было такого поля (data). Поэтому хотел бы у вас уточнить. На 8.3.18.1208 мне не удалось обработать push внутри мобильного приложения 1с с помощью ДоставляемыеУведомления.ПодключитьОбработчикУведомлений.
https://forum.infostart.ru/forum92/topic229197/

2.
Вторая проблема. Доставляемые уведомления хотя и приходят на устройство, но почему-то не отображаются в консоли Fire Cloud Messaging на вкладке Reports (https://console.firebase.google.com/project/<имя проекта firebase>/notification). Есть предположения, что на этой вкладке отображаются только отправка маркетинговых push, созданных на вкладке Notifications.
Приходилось ли вам видеть сообщения из 1с в этом журнале?
8. dimasts 22 11.10.21 21:34 Сейчас в теме
До конца сентября уведомления приходили, теперь получаю ошибку. КлючДоступа получает без ошибки, но при отправке уведомления приходит ответ:
{
  "error": {
    "code": 403,
    "message": "SenderId mismatch",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError",
        "errorCode": "SENDER_ID_MISMATCH"
      }
    ]
  }
}
Показать

Куда копать не понимаю
9. dimasts 22 14.10.21 12:43 Сейчас в теме
(8) Попытался перевести описание ошибки. Стало ещё непонятней :)
SENDER_ID_MISMATCH – (Код ошибки HTTP = 403) Идентификатор аутентифицированного отправителя отличается от идентификатора отправителя для токена регистрации.

Жетон регистрации привязан к определенной группе отправителей. Когда клиентское приложение регистрируется в FCM, оно должно указать, каким отправителям разрешено отправлять сообщения. Вы должны использовать один из этих идентификаторов отправителя при отправке сообщений в клиентское приложение. Если вы переключитесь на другого отправителя, существующие регистрационные токены не будут работать.
10. dimasts 22 14.10.21 17:06 Сейчас в теме
(6)
(9) Нашел более адекватное разъяснение: Идентификатор отправителя, прошедшего проверку подлинности, отличается от идентификатора отправителя для токена регистрации. Обычно это означает, что отправитель и целевой регистрационный токен не находятся в одном проекте Firebase.
11. dimasts 22 14.10.21 19:35 Сейчас в теме
Этот метод больше не будет работать в Мобильной платформе 1С, так она генерирует неадекватные токены с помощью ИдентификаторПодписчикаДоставляемыхУведомлений.ИдентификаторУстройства.

Проверил несколько разных токенов, С помощью Try this API в справке метода send в котором все авторизационные данные заполняются автоматически и надо ввести только token и data
Ответ прежний:
{
  "error": {
    "code": 403,
    "message": "SenderId mismatch",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError",
        "errorCode": "SENDER_ID_MISMATCH"
      }
    ]
  }
}
Показать
12. dimasts 22 19.10.21 23:20 Сейчас в теме
(11)Может я чего-то не знаю и этот SENDER_ID надо где-то регистрировать???
14. dimasts 22 30.06.22 21:00 Сейчас в теме
16. onec.developer 181 07.10.22 11:35 Сейчас в теме
(14)Получилось разобраться?
15. pitnn 08.07.22 13:08 Сейчас в теме
Спасибо за статью, код работает, push отправляется (тестировал на 8.3.20.1674).
Но отправляется только если приложение "сидит" в памяти. Если приложение выгружено, то push не приходит, хотя сервер возвращает, что операция выполнена.
В чем может быть дело и как отправлять push, есть приложение не загружено в память?
17. Sanfany 11.08.23 14:47 Сейчас в теме
Огромное спасибо автору !!! Если бы не эта статья, я даже не знаю, что бы делал. Все отправляется. Сначала были тоже ошибки (SENDER_ID ), указанные выше. Но проблема просто в том, что push будут отправляться только когда на устройстве будет установлено собранное приложение. А в сборку будет добавлен файл google-services.json, который можно скачать из консоли FCM. Так же еще важно, чтобы название проекта (Полный идентификатор приложения для Android) в сборщике совпадало с названием ( App nickname ) в FCM.
18. Daynestro07 09.02.24 10:53 Сейчас в теме
Здравствуйте! Сорри за некропостинг, в посте все достаточно понятно расписано. Пытаемся сделать также, отправляется нормально, без ошибок. А вот на стороне, принимающей пуш, проблема - событие которое отлавливает пуши, как будто бы не отрабатывает.

Вот код, который отлавливает пуши:

ОбработчикУведомленийОписаниеОповещения = Новый ОписаниеОповещения("ОбработчикУведомлений", УведомленияКлиент);
ДоставляемыеУведомления.ПодключитьОбработчикУведомлений(ОбработчикУведомленийОписаниеОповещения);


В событии "ОбработчикУведомлений" мы наше уведомление записываем в регистр, но ощущение что это событие не выполняется.
При этом, если приложение свернуто или закрыто, т.е. на экране его нет - то уведомление появляется и при нажатии на это уведомление приложение либо разворачивается либо запускается (если оно не было запущено).
Если же приложение открыто на экране, не появляется вообще ничего.

Все разрешения у приложения есть - пуши приходят и отрабатывают, если использовать старый вариант API для отправки пушей (на скриншоте), используя только серверный ключ в качестве авторизации. Но я так понимаю, гугл в скором времени отключит старое API. Не было у кого-нибудь такой проблемы?
Мобильная платформа 8.3.24.1201
Прикрепленные файлы:
Оставьте свое сообщение