@suro4ek/appmetrica-push-sdk 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "AppMetricaPushSDK"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => "11.0" }
14
+ s.source = { :git => "https://github.com/suro4ek/appmetrica-push-sdk.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
17
+ s.requires_arc = true
18
+
19
+ s.dependency "React-Core"
20
+ s.dependency "AppMetricaPush", "~> 3.2.0"
21
+ s.dependency "AppMetricaPushLazy", "~> 3.2.0"
22
+
23
+ # Swift/Objective-C compatibility
24
+ s.pod_target_xcconfig = {
25
+ "DEFINES_MODULE" => "YES",
26
+ "SWIFT_COMPILATION_MODE" => "wholemodule"
27
+ }
28
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Moyka Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # @suro4ek/appmetrica-push-sdk
2
+
3
+ React Native библиотека для интеграции с Yandex AppMetrica Push SDK.
4
+
5
+ ## Документация
6
+
7
+ - 📖 [Полное руководство по интеграции](docs/INTEGRATION_GUIDE.md)
8
+ - 📊 [Руководство по аналитике](docs/ANALYTICS_GUIDE.md)
9
+ - 🍎 [Настройка APNS для iOS](docs/IOS_APNS_SETUP.md)
10
+
11
+ ## Установка
12
+
13
+ ```bash
14
+ npm install @suro4ek/appmetrica-push-sdk
15
+ # или
16
+ yarn add @suro4ek/appmetrica-push-sdk
17
+ ```
18
+
19
+ ## Зависимости
20
+
21
+ ```bash
22
+ npm install @react-native-firebase/messaging
23
+ npm install @appmetrica/react-native-analytics
24
+ ```
25
+
26
+ ## Настройка
27
+
28
+ ### Android
29
+
30
+ Добавьте в `android/app/src/main/AndroidManifest.xml`:
31
+
32
+ ```xml
33
+ <application>
34
+ <receiver android:name="com.appmetricapush.SilentPushReceiver"
35
+ android:exported="false">
36
+ <intent-filter>
37
+ <action android:name="com.appmetricapush.action.ymp.SILENT_PUSH_RECEIVE"/>
38
+ </intent-filter>
39
+ </receiver>
40
+
41
+ <service android:name="com.appmetricapush.FirebaseMessagingMainService"
42
+ android:enabled="true"
43
+ android:exported="false">
44
+ <intent-filter android:priority="100">
45
+ <action android:name="com.google.firebase.MESSAGING_EVENT"/>
46
+ </intent-filter>
47
+ </service>
48
+
49
+ <service android:name="io.appmetrica.analytics.push.provider.firebase.AppMetricaMessagingService"
50
+ android:enabled="false"
51
+ tools:node="remove"/>
52
+ </application>
53
+ ```
54
+
55
+ ### iOS
56
+
57
+ ```bash
58
+ cd ios && pod install
59
+ ```
60
+
61
+ ## Использование
62
+
63
+ ```typescript
64
+ import { Platform } from "react-native";
65
+ import { getAPNSToken, getMessaging } from "@react-native-firebase/messaging";
66
+ import { AppMetrica } from "@appmetrica/react-native-analytics";
67
+ import { AppMetricaPush } from "@suro4ek/appmetrica-push-sdk";
68
+
69
+ // 1. Сначала активируем основную AppMetrica
70
+ AppMetrica.activate({
71
+ apiKey: "YOUR_APPMETRICA_API_KEY",
72
+ });
73
+
74
+ // 2. Получение APNS токена для iOS
75
+ let apnsToken = "";
76
+ if (Platform.OS === "ios") {
77
+ const messaging = getMessaging();
78
+ apnsToken = (await getAPNSToken(messaging)) ?? "";
79
+ }
80
+
81
+ // 3. Инициализация Push SDK (ТОЛЬКО после AppMetrica.activate)
82
+ await AppMetricaPush.initialize({
83
+ debugMode: __DEV__,
84
+ apnsToken: Platform.OS === "ios" ? apnsToken : undefined,
85
+ });
86
+
87
+ // Проверка уведомления
88
+ const isFromAppMetrica = await AppMetricaPush.isNotificationFromAppMetrica(
89
+ notification
90
+ );
91
+
92
+ // Получение пользовательских данных
93
+ const userData = await AppMetricaPush.getUserData(notification);
94
+ ```
95
+
96
+ ## API
97
+
98
+ - `initialize(config)` - инициализация SDK
99
+ - `isNotificationFromAppMetrica(notification)` - проверка источника уведомления
100
+ - `getUserData(notification)` - извлечение пользовательских данных
101
+ - `getSDKInfo()` - информация о SDK
102
+
103
+ ## Требования
104
+
105
+ - React Native >= 0.60.0
106
+ - Android API 21+
107
+ - iOS 11.0+
108
+
109
+ ## Лицензия
110
+
111
+ MIT
File without changes
@@ -0,0 +1,2 @@
1
+ #Thu Dec 25 09:38:41 YAKT 2025
2
+ gradle.version=9.0.0
File without changes
@@ -0,0 +1,44 @@
1
+ apply plugin: "com.android.library"
2
+ apply plugin: "kotlin-android"
3
+
4
+ android {
5
+ namespace "com.appmetricapush"
6
+ compileSdkVersion 34
7
+ buildToolsVersion "34.0.0"
8
+
9
+ defaultConfig {
10
+ minSdkVersion 21
11
+ targetSdkVersion 34
12
+ versionCode 1
13
+ versionName "1.0"
14
+ }
15
+
16
+ buildTypes {
17
+ release {
18
+ minifyEnabled false
19
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
20
+ }
21
+ }
22
+
23
+ compileOptions {
24
+ sourceCompatibility JavaVersion.VERSION_1_8
25
+ targetCompatibility JavaVersion.VERSION_1_8
26
+ }
27
+ }
28
+
29
+ dependencies {
30
+ implementation "com.facebook.react:react-native:+"
31
+
32
+ // Kotlin
33
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.20"
34
+
35
+ // AppMetrica Push SDK (только основные зависимости)
36
+ implementation("io.appmetrica.analytics:push:4.2.1")
37
+ implementation("androidx.legacy:legacy-support-v4:1.0.0")
38
+
39
+ // Firebase dependencies (будут переопределены основным проектом)
40
+ implementation platform('com.google.firebase:firebase-bom:33.2.0')
41
+ implementation 'com.google.firebase:firebase-messaging'
42
+ implementation 'com.google.firebase:firebase-messaging-ktx'
43
+ implementation("io.appmetrica.analytics:push-provider-firebase:4.2.1")
44
+ }
@@ -0,0 +1 @@
1
+ rootProject.name = 'AppMetricaPushSDK'
@@ -0,0 +1,176 @@
1
+ package com.appmetricapush
2
+
3
+ import android.util.Log
4
+ import androidx.annotation.NonNull
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
8
+ import com.facebook.react.bridge.ReactMethod
9
+ import com.facebook.react.bridge.ReadableMap
10
+ import com.facebook.react.bridge.WritableMap
11
+ import com.facebook.react.bridge.Arguments
12
+ import io.appmetrica.analytics.push.AppMetricaPush
13
+
14
+ /**
15
+ * React Native модуль для AppMetrica Push SDK
16
+ * Написан на Kotlin для лучшей интеграции с современным Android разработкой
17
+ */
18
+ class AppMetricaPushModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
19
+
20
+ companion object {
21
+ private const val MODULE_NAME = "AppMetricaPushModule"
22
+ private const val TAG = "AppMetricaPush"
23
+ }
24
+
25
+ @NonNull
26
+ override fun getName(): String {
27
+ return MODULE_NAME
28
+ }
29
+
30
+ @ReactMethod
31
+ fun initialize(config: ReadableMap, promise: Promise) {
32
+ try {
33
+ val debugMode = if (config.hasKey("debugMode")) config.getBoolean("debugMode") else false
34
+
35
+ // Инициализация AppMetrica Push
36
+ AppMetricaPush.activate(reactApplicationContext)
37
+
38
+ // Настройка дефолтного канала AppMetrica Push SDK
39
+ setupAppMetricaDefaultChannel()
40
+
41
+ if (debugMode) {
42
+ Log.d(TAG, "AppMetrica Push initialized successfully")
43
+ }
44
+
45
+ promise.resolve(true)
46
+ } catch (e: Exception) {
47
+ Log.e(TAG, "Failed to initialize AppMetrica Push", e)
48
+ promise.reject("INIT_ERROR", e.message)
49
+ }
50
+ }
51
+
52
+
53
+ /**
54
+ * Настройка дефолтного канала AppMetrica Push SDK
55
+ */
56
+ private fun setupAppMetricaDefaultChannel() {
57
+ try {
58
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
59
+ // Получаем дефолтный канал AppMetrica и настраиваем его
60
+ // appmetrica_push_channel
61
+ AppMetricaPush.getDefaultNotificationChannel()?.apply {
62
+ description = "Push notifications from AppMetrica"
63
+ importance = android.app.NotificationManager.IMPORTANCE_HIGH
64
+ enableLights(true)
65
+ enableVibration(true)
66
+ setShowBadge(true)
67
+ // Включаем звук
68
+ setSound(android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION), null)
69
+ }
70
+ Log.d(TAG, "AppMetrica default notification channel configured with sound")
71
+ }
72
+ } catch (e: Exception) {
73
+ Log.e(TAG, "Failed to setup AppMetrica default channel", e)
74
+ }
75
+ }
76
+
77
+
78
+ @ReactMethod
79
+ fun isNotificationFromAppMetrica(notification: ReadableMap, promise: Promise) {
80
+ try {
81
+ // Проверяем, что push уведомление не от AppMetrica
82
+ // Это нужно для собственных сервисов обработки push уведомлений
83
+ var isFromAppMetrica = false
84
+
85
+ if (notification.hasKey("data")) {
86
+ // Проверяем наличие специфических полей AppMetrica в данных
87
+ val data = notification.getString("data")
88
+ if (data != null && data.contains("appmetrica")) {
89
+ isFromAppMetrica = true
90
+ }
91
+ }
92
+
93
+ promise.resolve(isFromAppMetrica)
94
+ } catch (e: Exception) {
95
+ Log.e(TAG, "Failed to check if notification is from AppMetrica", e)
96
+ promise.reject("NOTIFICATION_CHECK_ERROR", e.message)
97
+ }
98
+ }
99
+
100
+ @ReactMethod
101
+ fun getSDKInfo(promise: Promise) {
102
+ try {
103
+ val info = Arguments.createMap().apply {
104
+ // Получаем актуальную версию AppMetrica Push SDK
105
+ putString("version", getAppMetricaPushVersion())
106
+ putString("platform", "android")
107
+ putString("sdkName", "AppMetrica Push SDK")
108
+ putString("libraryVersion", "1.0.0") // Версия нашей библиотеки
109
+ }
110
+ promise.resolve(info)
111
+ } catch (e: Exception) {
112
+ Log.e(TAG, "Failed to get SDK info", e)
113
+ promise.reject("SDK_INFO_ERROR", e.message)
114
+ }
115
+ }
116
+
117
+ @ReactMethod
118
+ fun getUserData(notification: ReadableMap, promise: Promise) {
119
+ try {
120
+ // Получаем дополнительную информацию из push-уведомления согласно документации
121
+ // AppMetrica Push SDK автоматически извлекает userData из уведомления
122
+ val userData = Arguments.createMap()
123
+
124
+ // Проверяем наличие данных в уведомлении
125
+ if (notification.hasKey("data")) {
126
+ val data = notification.getMap("data")
127
+ if (data != null) {
128
+ // Копируем все данные из notification.data в userData
129
+ val keySetIterator = data.keySetIterator()
130
+ while (keySetIterator.hasNextKey()) {
131
+ val key = keySetIterator.nextKey()
132
+ val value = data.getDynamic(key)
133
+ userData.putString(key, value.toString())
134
+ }
135
+ }
136
+ }
137
+
138
+ promise.resolve(userData)
139
+ } catch (e: Exception) {
140
+ Log.e(TAG, "Failed to get user data from notification", e)
141
+ promise.reject("USER_DATA_ERROR", e.message)
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Регистрация device token (заглушка для iOS совместимости)
147
+ * В Android device token регистрируется автоматически через Firebase
148
+ */
149
+ @ReactMethod
150
+ fun registerDeviceToken(deviceToken: String, promise: Promise) {
151
+ try {
152
+ // В Android device token регистрируется автоматически через Firebase
153
+ // Этот метод добавлен для совместимости с iOS API
154
+ Log.d(TAG, "Device token registration not needed on Android (handled by Firebase)")
155
+ promise.resolve(true)
156
+ } catch (e: Exception) {
157
+ Log.e(TAG, "Failed to register device token", e)
158
+ promise.reject("REGISTRATION_ERROR", e.message)
159
+ }
160
+ }
161
+
162
+
163
+ /**
164
+ * Получение версии AppMetrica Push SDK
165
+ */
166
+ private fun getAppMetricaPushVersion(): String {
167
+ return try {
168
+ // Пытаемся получить версию из AppMetrica Push SDK
169
+ val version = io.appmetrica.analytics.push.BuildConfig.VERSION_NAME
170
+ version ?: "4.2.1" // Fallback версия
171
+ } catch (e: Exception) {
172
+ Log.w(TAG, "Could not get AppMetrica Push version, using fallback", e)
173
+ "4.2.1" // Fallback версия
174
+ }
175
+ }
176
+ }
@@ -0,0 +1,21 @@
1
+ package com.appmetricapush
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ /**
9
+ * React Native Package для AppMetrica Push SDK
10
+ * Написан на Kotlin для консистентности с остальным кодом
11
+ */
12
+ class AppMetricaPushPackage : ReactPackage {
13
+
14
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
15
+ return listOf(AppMetricaPushModule(reactContext))
16
+ }
17
+
18
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
19
+ return emptyList()
20
+ }
21
+ }
@@ -0,0 +1,79 @@
1
+ package com.appmetricapush
2
+
3
+ import android.util.Log
4
+ import com.google.firebase.messaging.FirebaseMessagingService
5
+ import com.google.firebase.messaging.RemoteMessage
6
+ import io.appmetrica.analytics.push.provider.firebase.AppMetricaMessagingService
7
+
8
+ /**
9
+ * Основной сервис для обработки Firebase Cloud Messaging
10
+ * Интегрирован с AppMetrica Push SDK
11
+ * Входит в состав библиотеки @moyka/appmetrica-push-sdk
12
+ */
13
+ class FirebaseMessagingMainService : FirebaseMessagingService() {
14
+ companion object {
15
+ private const val TAG = "AppMetricaFirebaseService"
16
+ }
17
+
18
+ override fun onMessageReceived(message: RemoteMessage) {
19
+ super.onMessageReceived(message)
20
+
21
+ Log.d(TAG, "Firebase message received: ${message.messageId}")
22
+
23
+ // Проверяем, что push уведомление от AppMetrica
24
+ if (AppMetricaMessagingService.isNotificationRelatedToSDK(message)) {
25
+ Log.d(TAG, "Processing AppMetrica push notification")
26
+ // AppMetrica Push SDK сам покажет уведомление пользователю
27
+ AppMetricaMessagingService().processPush(this, message)
28
+ return
29
+ }
30
+
31
+ // Обрабатываем собственные push уведомления
32
+ Log.d(TAG, "Processing custom push notification")
33
+ handleCustomPushMessage(message)
34
+ }
35
+
36
+ override fun onNewToken(token: String) {
37
+ super.onNewToken(token)
38
+
39
+ Log.d(TAG, "New FCM token received: $token")
40
+
41
+ // Отправляем токен в AppMetrica Push SDK
42
+ AppMetricaMessagingService().processToken(this, token)
43
+
44
+ // Отправляем токен в другие SDK или обрабатываем самостоятельно
45
+ handleCustomToken(token)
46
+ }
47
+
48
+ /**
49
+ * Обработка собственных push уведомлений
50
+ */
51
+ private fun handleCustomPushMessage(message: RemoteMessage) {
52
+ try {
53
+ Log.d(TAG, "Custom push data: ${message.data}")
54
+ Log.d(TAG, "Custom push notification: ${message.notification}")
55
+
56
+ // Здесь можно добавить логику обработки собственных push уведомлений
57
+ // Например, отправить событие в React Native через EventEmitter
58
+
59
+ } catch (e: Exception) {
60
+ Log.e(TAG, "Error handling custom push message", e)
61
+ }
62
+ }
63
+
64
+
65
+ /**
66
+ * Обработка собственного токена
67
+ */
68
+ private fun handleCustomToken(token: String) {
69
+ try {
70
+ Log.d(TAG, "Handling custom token: $token")
71
+
72
+ // Здесь можно отправить токен в другие SDK или на ваш сервер
73
+ // Например, отправить событие в React Native через EventEmitter
74
+
75
+ } catch (e: Exception) {
76
+ Log.e(TAG, "Error handling custom token", e)
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,53 @@
1
+ package com.appmetricapush
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.util.Log
7
+ import io.appmetrica.analytics.push.AppMetricaPush
8
+
9
+ /**
10
+ * Receiver для обработки silent push уведомлений от AppMetrica
11
+ * Настроен согласно документации AppMetrica Push SDK
12
+ * Входит в состав библиотеки @suro4ek/appmetrica-push-sdk
13
+ */
14
+ class SilentPushReceiver : BroadcastReceiver() {
15
+ companion object {
16
+ private const val TAG = "AppMetricaSilentPushReceiver"
17
+ }
18
+
19
+ override fun onReceive(context: Context, intent: Intent) {
20
+ try {
21
+ // Extract push message payload from your push message.
22
+ val payload = intent.getStringExtra(AppMetricaPush.EXTRA_PAYLOAD)
23
+
24
+ if (payload != null) {
25
+ Log.d(TAG, "Silent push received with payload: $payload")
26
+
27
+ // AppMetrica Push SDK автоматически обрабатывает silent push
28
+ // Здесь можно добавить дополнительную логику обработки
29
+ handleSilentPushPayload(context, payload)
30
+ } else {
31
+ Log.w(TAG, "Silent push received but payload is null")
32
+ }
33
+ } catch (e: Exception) {
34
+ Log.e(TAG, "Error handling silent push", e)
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Обработка payload от silent push
40
+ */
41
+ private fun handleSilentPushPayload(context: Context, payload: String) {
42
+ try {
43
+ // Логируем получение silent push
44
+ Log.d(TAG, "Processing silent push payload: $payload")
45
+
46
+ // AppMetrica Push SDK автоматически обрабатывает silent push
47
+ // Здесь можно добавить дополнительную логику обработки
48
+
49
+ } catch (e: Exception) {
50
+ Log.e(TAG, "Error processing silent push payload", e)
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,68 @@
1
+ # Руководство для аналитиков
2
+
3
+ ## Настройка push кампаний в AppMetrica
4
+
5
+ При создании push кампаний в веб-интерфейсе AppMetrica **обязательно укажите канал уведомлений**:
6
+
7
+ ```
8
+ appmetrica_push_channel
9
+ ```
10
+
11
+ ## Почему это важно:
12
+
13
+ - ✅ **Звук уведомлений** - канал настроен с включенным звуком
14
+ - ✅ **Высокий приоритет** - уведомления будут показаны пользователю
15
+ - ✅ **Вибрация** - включена для лучшего UX
16
+ - ✅ **Светодиод** - для визуального уведомления
17
+
18
+ ## Где указать канал:
19
+
20
+ 1. Перейдите в **AppMetrica → Push-уведомления**
21
+ 2. Создайте новую кампанию
22
+ 3. В разделе **"Настройки уведомления"** найдите поле **"Канал уведомлений"**
23
+ 4. Укажите: `appmetrica_push_channel`
24
+
25
+ ## Без указания канала:
26
+
27
+ - ❌ Уведомления могут приходить без звука
28
+ - ❌ Низкий приоритет уведомлений
29
+ - ❌ Плохой пользовательский опыт
30
+
31
+ ## Дополнительные настройки
32
+
33
+ ### Silent Push уведомления
34
+
35
+ Для актуализации push-токенов включите в настройках AppMetrica:
36
+
37
+ 1. Перейдите в **Настройки приложения → Push-уведомления**
38
+ 2. Включите **"Актуализировать токены с помощью Silent Push-уведомлений"**
39
+
40
+ ### Тестирование уведомлений
41
+
42
+ 1. **Тестовая отправка** - используйте функцию "Отправить тест"
43
+ 2. **Проверка канала** - убедитесь, что указан `appmetrica_push_channel`
44
+ 3. **Проверка звука** - уведомление должно приходить со звуком
45
+
46
+ ## Troubleshooting
47
+
48
+ ### Уведомления без звука
49
+
50
+ 1. ✅ Проверьте, что указан канал `appmetrica_push_channel`
51
+ 2. ✅ Убедитесь, что приложение не в режиме "Не беспокоить"
52
+ 3. ✅ Проверьте настройки звука в Android
53
+
54
+ ### Уведомления не доходят
55
+
56
+ 1. ✅ Проверьте, что SDK инициализирован
57
+ 2. ✅ Убедитесь, что пользователь дал разрешения на уведомления
58
+ 3. ✅ Проверьте, что токен получен и отправлен в AppMetrica
59
+
60
+ ### Низкая доставляемость
61
+
62
+ 1. ✅ Используйте Silent Push для актуализации токенов
63
+ 2. ✅ Проверьте, что Firebase настроен правильно
64
+ 3. ✅ Убедитесь, что все зависимости добавлены
65
+
66
+ ## Контакты
67
+
68
+ При возникновении проблем с push уведомлениями обращайтесь к команде разработки.