Files
mobile-android/FCM_SETUP.md

8.5 KiB
Raw Blame History

Firebase Cloud Messaging (FCM) Integration

Обзор

Android приложение использует Firebase Cloud Messaging (FCM) для push-уведомлений о новых сообщениях.

Архитектура

Клиент (Android)

  1. При старте приложения (MainActivity.kt):

    • Инициализируется Firebase
    • Получается FCM токен
    • Токен отправляется на сервер через протокол
  2. При получении нового токена (RosettaFirebaseMessagingService.kt):

    • Вызывается onNewToken()
    • Новый токен отправляется на сервер
  3. При получении push-уведомления (RosettaFirebaseMessagingService.kt):

    • Вызывается onMessageReceived()
    • Показывается системное уведомление
    • При клике открывается соответствующий чат

Протокол

Packet ID: 0x0A - PacketPushToken

Формат пакета:

[PacketID: 0x0A (2 bytes)]
[privateKey: String]
[publicKey: String]
[pushToken: String]
[platform: String] // "android" или "ios"

Сервер

Сервер должен:

  1. Получить PacketPushToken от клиента
  2. Сохранить в БД связку: publicKey -> fcmToken
  3. При получении нового сообщения для пользователя:
    • Найти FCM токен по publicKey получателя
    • Отправить push через FCM HTTP API

Настройка Firebase

1. Создать Firebase проект

  1. Перейти на Firebase Console
  2. Создать новый проект или выбрать существующий
  3. Добавить Android приложение

2. Настройка Android app

Package name: com.rosetta.messenger

  1. В Firebase Console → Project Settings → General
  2. Скачать google-services.json
  3. Поместить файл в rosetta-android/app/google-services.json

3. Структура google-services.json

{
  "project_info": {
    "project_number": "YOUR_PROJECT_NUMBER",
    "project_id": "your-project-id",
    "storage_bucket": "your-project-id.appspot.com"
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:YOUR_PROJECT_NUMBER:android:xxxxx",
        "android_client_info": {
          "package_name": "com.rosetta.messenger"
        }
      },
      "oauth_client": [],
      "api_key": [
        {
          "current_key": "YOUR_API_KEY"
        }
      ],
      "services": {
        "appinvite_service": {
          "other_platform_oauth_client": []
        }
      }
    }
  ],
  "configuration_version": "1"
}

4. Получить Server Key

  1. Firebase Console → Project Settings → Cloud Messaging
  2. Скопировать Server Key (Legacy)
  3. Использовать на сервере для отправки уведомлений

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

FCM HTTP v1 API (рекомендуется)

POST https://fcm.googleapis.com/v1/projects/YOUR_PROJECT_ID/messages:send
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "message": {
    "token": "FCM_DEVICE_TOKEN_FROM_CLIENT",
    "notification": {
      "title": "Имя отправителя",
      "body": "Текст сообщения"
    },
    "data": {
      "type": "new_message",
      "sender_public_key": "SENDER_PUBLIC_KEY",
      "sender_name": "Имя отправителя",
      "message_preview": "Текст сообщения"
    },
    "android": {
      "priority": "HIGH",
      "notification": {
        "channel_id": "messages",
        "sound": "default",
        "notification_priority": "PRIORITY_HIGH"
      }
    }
  }
}

Legacy FCM API (проще для начала)

POST https://fcm.googleapis.com/fcm/send
Authorization: key=YOUR_SERVER_KEY
Content-Type: application/json

{
  "to": "FCM_DEVICE_TOKEN_FROM_CLIENT",
  "notification": {
    "title": "Имя отправителя",
    "body": "Текст сообщения",
    "sound": "default"
  },
  "data": {
    "type": "new_message",
    "sender_public_key": "SENDER_PUBLIC_KEY",
    "sender_name": "Имя отправителя",
    "message_preview": "Текст сообщения"
  },
  "priority": "high",
  "android": {
    "priority": "HIGH",
    "notification": {
      "channel_id": "messages"
    }
  }
}

Пример серверной логики (Node.js)

const admin = require("firebase-admin");

// Инициализация Firebase Admin SDK
const serviceAccount = require("./path/to/serviceAccountKey.json");
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
});

// База данных с токенами (пример)
const userTokens = new Map(); // publicKey -> fcmToken

// Обработка PacketPushToken (0x0A)
function handlePushToken(packet) {
  const { publicKey, pushToken, platform } = packet;

  console.log(`📱 Saving FCM token for user ${publicKey.slice(0, 10)}...`);
  userTokens.set(publicKey, pushToken);
}

// Отправка push-уведомления
async function sendPushNotification(
  recipientPublicKey,
  senderPublicKey,
  senderName,
  messageText
) {
  const fcmToken = userTokens.get(recipientPublicKey);

  if (!fcmToken) {
    console.log("⚠️ No FCM token for user");
    return;
  }

  const message = {
    token: fcmToken,
    notification: {
      title: senderName,
      body: messageText,
    },
    data: {
      type: "new_message",
      sender_public_key: senderPublicKey,
      sender_name: senderName,
      message_preview: messageText,
    },
    android: {
      priority: "HIGH",
      notification: {
        channelId: "messages",
        sound: "default",
        priority: "PRIORITY_HIGH",
      },
    },
  };

  try {
    const response = await admin.messaging().send(message);
    console.log("✅ Push notification sent:", response);
  } catch (error) {
    console.error("❌ Error sending push:", error);

    // Если токен невалиден - удаляем из БД
    if (
      error.code === "messaging/invalid-registration-token" ||
      error.code === "messaging/registration-token-not-registered"
    ) {
      userTokens.delete(recipientPublicKey);
    }
  }
}

// Когда приходит PacketMessage
function handleNewMessage(packet) {
  const { fromPublicKey, toPublicKey, content } = packet;

  // Отправляем push получателю (если он не онлайн)
  sendPushNotification(toPublicKey, fromPublicKey, "User", "New message");
}

Тестирование

1. Проверка токена

// В логах Android Studio должно быть:
🔔 FCM token: XXXXXXXXXXXX...

2. Тест через Firebase Console

  1. Firebase Console → Cloud Messaging
  2. Send test message
  3. Вставить FCM токен из логов
  4. Отправить

3. Проверка формата пакета

Packet 0x0A должен содержать:
- PacketID: 0x0A (10 в decimal)
- privateKey: хеш приватного ключа
- publicKey: публичный ключ пользователя
- pushToken: FCM токен устройства
- platform: "android"

Troubleshooting

Токен не получается

  1. Проверить google-services.json в app/google-services.json
  2. Проверить package name совпадает: com.rosetta.messenger
  3. Rebuild проект
  4. Проверить Google Play Services на устройстве

Уведомления не приходят

  1. Проверить разрешение на уведомления (Android Settings)
  2. Проверить Server Key на сервере
  3. Проверить FCM токен актуален
  4. Проверить формат JSON в FCM API запросе

Уведомления приходят, но не открывают чат

Проверить data payload содержит sender_public_key

Полезные ссылки