feat: Implement Firebase Cloud Messaging (FCM) integration documentation for push notifications docs: Outline remaining tasks for complete FCM integration in the project fix: Resolve WebSocket connection issues after user registration
307 lines
8.5 KiB
Markdown
307 lines
8.5 KiB
Markdown
# 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](https://console.firebase.google.com/)
|
||
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
|
||
|
||
```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 (рекомендуется)
|
||
|
||
```bash
|
||
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 (проще для начала)
|
||
|
||
```bash
|
||
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)
|
||
|
||
```javascript
|
||
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. Проверка токена
|
||
|
||
```kotlin
|
||
// В логах 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`
|
||
|
||
## Полезные ссылки
|
||
|
||
- [Firebase Console](https://console.firebase.google.com/)
|
||
- [FCM Documentation](https://firebase.google.com/docs/cloud-messaging)
|
||
- [Android Setup Guide](https://firebase.google.com/docs/cloud-messaging/android/client)
|
||
- [FCM HTTP Protocol](https://firebase.google.com/docs/cloud-messaging/http-server-ref)
|