feat: Integrate Firebase Cloud Messaging for push notifications; add service to handle token and message reception
This commit is contained in:
306
FCM_SETUP.md
Normal file
306
FCM_SETUP.md
Normal file
@@ -0,0 +1,306 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user