Хабр, привет!
Firebase Cloud Messaging (FCM) — это бесплатный (или почти) облачный сервис от Google, который позволяет отправлять push-уведомления и сообщения напрямую на устройства Android, iOS и веб-приложения. FCM широко используется для реализации мгновенных уведомлений, оповещений о событиях, маркетинговых рассылок и других сценариев, где требуется быстрая доставка сообщений пользователям.
В этой статье мы рассмотрим, как интегрировать FCM в Android-приложение на Kotlin и как настроить отправку push-уведомлений с небольшого, похожего backend, сервера, написанного на Kotlin. Вы узнаете, как подключить Firebase к вашему проекту, реализовать обработку входящих сообщений на устройстве, а такж�� научитесь отправлять push-уведомления на выбранные устройства.
Итак, начнём. Заходим на Firebase console и создаем новый проект

На следующем шаге оставляем рекомендуемые параметры для Gemini и аналитики, выбираем аккаунт и завершаем создание проекта. Как только появилась надпись, что проект готов, приступаем к его настройке.
Для начала нужно добавить Android приложение к этому проекту:

На следующем этапе понадобятся данные приложения и подпись.
Я заранее создал пустой проект и добавил туда 3 модуля по чистой архитектуре (presentation, domain, data), чтобы создать видимость реального проекта, т.к. это могут быть как глобальные модули, так и модули внутри фичи. Сделал это не из соображений соблюдения архитектуры, а для того, чтобы показать, куда подключать зависимости и плагины, потому что в одномодульном проекте все понятно и слишком просто.

Теперь у нас есть package name приложения. С никнеймом приложения проблем не возникнет, а вот сертификат подписи сейчас сгенерируем. Следующий параграф можно пропустить тем, у кого уже есть свой keystore.
Создание keystore
Android Studio -> Build -> Generate Signed App Bundle or APK -> здесь APK или Android App Bundle, без разницы -> create new
Далее вводим все необходимые данные, указываем путь к файлу хранилища ключей для сохранения и сохраняем.
Keystore готов, далее можно самостоятельно в студии генерировать подписанный исполняемый файл.
Получение сертификата
Переходим в папку с keystore. Вместе с установкой JDK поставляется утилита keytool для генерации и работы с keystore. Через неё, кстати, можно было и keystore создать.
Команда: keytool.exe --list -v --alias ваш_алиас --keystore хранилище.jks
После нажатия enter нужно ввести пароль хранилища, а потом выведутся SHA-1 и SHA-256 сертификаты.
Возвращаемся в firebase console, вставляем SHA-1, нажимаем "register app", и теперь доступен файл google-services.json, который нужно поместить в папку модуля app.

Далее показывается инструкция по добавлению базовых зависимостей.

Плагин: id("com.google.gms.google-services") version "4.4.2" apply false
Зависимости:
//fcm api(platform("com.google.firebase:firebase-bom:33.14.0")) api("com.google.firebase:firebase-messaging")
Плагин разместим в app модуле, а зависимости в data, т.к. это не относится ни к интерфейсу, ни к бизнес-логике. Теперь заканчиваем с регистрацией приложения.
Создание firebase в android приложении
В классе Application модуля app нужно добавить инициализацию firebase:
import android.app.Application import com.google.firebase.FirebaseApp internal class App : Application() { override fun onCreate() { super.onCreate() FirebaseApp.initializeApp(this@App) } }
За получение данных об уведомлении отвечает FirebaseMessagingService, который будет находиться в data модуле. Вместо отправки пуш-уведомления я буду логировать его, иначе статья затянется еще и на добавление сервисов для уведомлений, а также запроса разрешения.
import android.util.Log import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(message: RemoteMessage) { Log.e( "fcm", "title=${message.notification?.title}" + "\ntext=${message.notification?.body}" ) } override fun onNewToken(token: String) { super.onNewToken(token) Log.e("fcm", "token=$token") } }
В манифест app модуля добавляю декларацию этого сервиса так, чтобы google сервисы могли вызвать его через intent-фильтр:
<service android:name="ru.vafeen.data.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
Итак, после запуска приложения в logcat необходимо найти токен устройства и скопировать.
Тестирование
Протестируем работу fcm без бэкенда. На главной странице проекта в firebase console в категории run есть раздел messaging, где можно отправить тестовое сообщение.

Далеепо нажатию на кнопку «create your first compaign» выберем «Firebase Notification messages», которое приходит вне зависимости от нахождения в приложении.
На этом шаге задаем заголовок и текст уведомления.

Далее «Send test message», вставляем туда скопированный токен и нажимам «Test».
Результат:

Работа с Android-частью закончена, переходим к «бэкенду».
Backend
В этом же проекте, для простоты и удобства, я создам обычный Java or Kotlin Library модуль.
Здесь нужно настроить Firebase Admin SDK, чтобы отправлять сообщения.
Зависимость: implementation("com.google.firebase:firebase-admin:9.2.0")
Теперь сгенерируем Service Account key, по которому происходит отправка сообщений. Firebase Console -> Project settings -> Service Accounts -> generate new private key -> generate key -> сохраняем в удобное место
Также здесь сразу даётся сниппет для инициализации SDK: копируем его.
Далее инициализируем SDK, получаем инстанс FCM, создаем сообщение и отправляем его. Токен — харкдод, т. к. это не полноценный бэкенд, и его отправка выходит за рамки статьи.
import com.google.auth.oauth2.GoogleCredentials import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.Message import com.google.firebase.messaging.Notification import java.io.FileInputStream const val token = "токен девайса" fun main() { initialFirebase() val fcm = FirebaseMessaging.getInstance() val message = Message.builder().setNotification( Notification.builder().setTitle("test sdk title").setBody("test sdk text").build() ).setToken(token).build() println(fcm.send(message)) } fun initialFirebase() { val serviceAccount = FileInputStream("path/to/serviceAccountKey.json") val options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.fromStream(serviceAccount)) .build() FirebaseApp.initializeApp(options) }
А также при запуске бэкенд потребует логирование. Здесь просто происходит чек наличия, поэтому на настройке не будем останавливаться.
Добавляем зависимость: implementation("ch.qos.logback:logback-classic:1.5.18")
И снова запуск.

UPD 12.11.25 Репозиторий с кодом из статьи
vafeenHub/Android-FCM-with-Kotlin-Backend-example
На этом путь от пустого проекта до отправки fcm с имитированного бэкенда пройден!
No errors, no warnings, gentlemen and ladies!
