Firebase, аналитика, реклама и пуши
Шпаргалка: что и зачем настраивать в новом Expo-приложении, чтобы события уходили в Google Analytics, реклама в Google Ads видела установки, а пуш-уведомления доходили. Значения в примерах взяты из AiAstrology, в новом приложении подставь свои (таблица в самом конце).
Как всё связано
Это две независимые цепочки. Первая — аналитика и реклама: приложение рассказывает Google, кто установил приложение и что делал. Вторая — пуши: сервер отправляет уведомления через Expo. Общее у них одно: оба работают через один Firebase-проект, а на Android пушам тоже нужен google-services.json.
Кто есть кто
Чек-лист для нового приложения
Шаги по порядку. Галочки сохраняются только в этом браузере.
- Создать Firebase-проектодин раз на приложение
- Отметить ключевые события в Google Analyticsчерез сутки после первых событий
- Выпустить версию в сторыдо этого реальных пользователей в отчётах не будет
| Android | iOS | |
|---|---|---|
| Установки | Google Play сам передаёт их в Google Ads. SDK не нужен, достаточно связать аккаунты (шаг 7). | Apple ничего не передаёт в Google. Нужен Firebase SDK: он шлёт событие first_open, Google Ads считает его установкой. |
| Действия в приложении | Только через Firebase → Google Analytics → импорт в Google Ads. | |
1Создать Firebase-проект
- console.firebase.google.com → Create a project.
- На шаге про Google Analytics оставить его включённым и выбрать или создать GA-аккаунт. Без этого события некуда будет складывать. Если забыл: Project settings → Integrations → Google Analytics.
В AiAstrology проект называется aiastrology-3a616.
2Добавить приложения и скачать конфиги
⚙️ Project settings → General, ниже блок Your apps.
Android
Add app → Android, package name как expo.android.package в app.json. SHA-1 не обязателен (нужен для Google Sign-In, берётся из eas credentials). Скачать google-services.json.
iOS
Add app → значок iOS+.
Заполнить и нажать Register app:
- Apple bundle ID — как
expo.ios.bundleIdentifierвapp.json. Если не совпадёт, SDK не примет конфиг. - App nickname — любое, только для консоли.
- App Store ID — число из ссылки на приложение в App Store (
apps.apple.com/.../id6756072533). По нему Google Ads связывает события с приложением в сторе. Если приложения в сторе ещё нет, можно добавить позже.
Скачать GoogleService-Info.plist. Следующие шаги мастера, «Add Firebase SDK» и «Add initialization code», пропустить (Next → Continue to console). Они для нативного Swift-проекта, а у нас SDK ставится через npm, и инициализацию плагин добавляет сам (шаг 3).
Куда положить
| Файл | Куда | В git |
|---|---|---|
GoogleService-Info.plist | корень проекта | да |
google-services.json | в AiAstrology: android/app/лучше: корень проекта | в AiAstrology нет, /android в .gitignore |
google-services.json в корень и указывай "googleServicesFile": "./google-services.json". Если он лежит в /android, то npx expo prebuild --clean его удалит, а EAS Build его не увидит, потому что папка в gitignore.Если в консоли что-то поменяли у приложения (SHA, OAuth client), конфиг нужно скачать заново. В plist может стоять IS_ANALYTICS_ENABLED = false: это устаревшее поле, SDK его не читает.
3Поставить SDK и плагин
npx expo prebuild сам вписывает Firebase в нативные проекты.yarn add @react-native-firebase/app @react-native-firebase/analytics
В AiAstrology стоит версия 26.4.0: версия 27 требует Node ≥ 24, а в проекте Node 20. Проверь node -v и, если нужно, укажи версию явно: @26.4.0.
app.json:
"ios": { "googleServicesFile": "./GoogleService-Info.plist" },
"android": { "googleServicesFile": "./google-services.json" },
"plugins": [
["@react-native-firebase/app", { "ios": { "disableSPM": true } }],
["expo-build-properties", { "ios": { "extraPods": [
{ "name": "FirebaseCore", "modular_headers": true },
{ "name": "FirebaseCoreInternal", "modular_headers": true },
{ "name": "FirebaseCoreExtension", "modular_headers": true },
{ "name": "FirebaseInstallations", "modular_headers": true },
{ "name": "GoogleDataTransport", "modular_headers": true },
{ "name": "GoogleUtilities", "modular_headers": true },
{ "name": "nanopb", "modular_headers": true }
] } }]
]
disableSPM: true: без негоpod installпадает с «SPM + static linkage is not supported».modular_headersдля Firebase-подов: позволяет обойтись безuseFrameworks: "static", который ломает другие библиотеки.
Что плагин добавит при prebuild:
| iOS | FirebaseApp.configure() в AppDelegate, plist в Xcode-проект, поды Firebase |
|---|---|
| Android | Gradle-плагин com.google.gms.google-services, который читает google-services.json |
Потом пересобрать: npx expo prebuild и обычная сборка. В Expo Go Firebase не работает, нужен dev build.
4Отправлять события в Firebase
Не нужно трогать экраны: достаточно в общей функции track() (src/services/analytics/index.ts) отправлять событие ещё и в Firebase.
reportEvent(name, attributes); // AppMetrica
reportFirebaseEvent(name, attributes); // Firebase
src/services/analytics/firebase.ts — можно копировать в новое приложение как есть:
import { getAnalytics, logEvent, logScreenView } from "@react-native-firebase/analytics";
/** Names Firebase reserves for its own automatic events (it collects those itself). */
const SKIPPED = new Set(["session_start", "app_background", "ad_impression"]);
export const reportFirebaseEvent = (name: string, params: Record<string, string | number | boolean>) => {
if (SKIPPED.has(name)) return;
try {
const analytics = getAnalytics();
const promise =
name === "screen_view"
? logScreenView(analytics, { screen_name: String(params.screen), screen_class: String(params.screen) })
: logEvent(analytics, name, params);
void Promise.resolve(promise).catch((e: unknown) => {
if (__DEV__) console.warn("Firebase logEvent failed", name, e);
});
} catch (e) {
if (__DEV__) console.warn("Firebase logEvent failed", name, e);
}
};
| Событие | В Firebase | Почему |
|---|---|---|
| Обычные события | как есть | Те же имя и параметры, что в AppMetrica |
screen_view | просмотр экрана | Через logScreenView попадает в стандартный отчёт «Экраны» |
session_start, app_background | пропускаются | Имена зарезервированы, Firebase пишет такие события сам |
ad_impression | пропускается | Иначе показы рекламы задвоятся в отчётах о доходе |
first_open | SDK шлёт сам | Это и есть установка для Google Ads на iOS |
track(). Имена, даты рождения, места и тексты чатов не отправляются (правила в CLAUDE.md и ANALYTICS.md).5Проверить в DebugView
iOS, запуск из Xcode
Product → Scheme → Edit Scheme → Run → Arguments → Arguments Passed On Launch → «+» → -FIRDebugEnabled.
iOS, запуск через npm run ios
expo run:ios аргументы из схемы не передаёт, поэтому перезапусти приложение с флагом (Metro продолжает работать):
xcrun simctl terminate booted com.kapernikrs.aiastrology
xcrun simctl launch booted com.kapernikrs.aiastrology -FIRDebugEnabled
Android
adb shell setprop debug.firebase.analytics.app com.kapernikrs.aiastrology
Выключить: adb shell setprop debug.firebase.analytics.app .none., на iOS — запустить с -FIRDebugDisabled.
Как должно выглядеть: через 10–60 секунд идёт поток событий (screen_view, onboarding_step_completed…), зелёный флажок у first_open. Надпись «Debug Device 0» не страшна, если события идут.
Если пусто: проверь, что в Firebase подключён Google Analytics (Project settings → Integrations), и поищи FirebaseAnalytics в консоли Xcode. Без режима отладки события уходят пачкой примерно раз в час.
6Отметить ключевые события в Google Analytics
Это делается в Google Analytics, не в Firebase: analytics.google.com или кнопка View more in Google Analytics в DebugView. Дальше Admin → Data display → Events.
Вкладка Key events показывает только уже отмеченные. Отмечать нужно на вкладке Recent events звёздочкой ☆ слева от имени.
У нового ресурса Recent events первые сутки пустой. Это нормально, просто вернись завтра.
Что отмечать
first_open— установка (обычно уже отмечено по умолчанию).onboarding_completed— главное событие для старта.- Покупка: не
purchase_result, оно приходит при любом исходе. Сделать Create event: имяpurchase_success, условияevent_name=purchase_resultиresult=purchased. Отметить его ключевым. Прошлые события GA не пересчитывает.
7Подключить Google Ads
- Android-установки: Google Ads → Инструменты → Связанные аккаунты → Google Play → запрос. Подтвердить в Play Console: Настройки → Связанные сервисы → Google Ads. Затем Цели → Конверсии → Новое действие → Приложение → Google Play → Установки.
- Firebase ↔ Google Ads: Firebase → Project settings → Integrations → Google Ads → Link. Нужны Owner/Editor в Firebase и Admin в Google Ads.
- Импорт конверсий: Google Ads → Цели → Конверсии → «+ Новое действие-конверсия» → Импорт → Google Analytics 4 → Приложение. Отметить
first_openи ключевые события из шага 6.
Совет: сначала оптимизировать кампанию на first_open или onboarding_completed. На покупки переключаться, когда их хотя бы 10–20 в день, иначе алгоритму не хватает данных.
ExponentPushToken[…]) и отправляет его на сервер. Сервер шлёт пуш через expo-server-sdk в Expo, а Expo передаёт его в FCM (Android) или APNs (iOS). Поэтому Expo нужны ключи от FCM и от APNs. Без них Expo принимает пуш, но до телефона он не доходит.Что уже есть в коде AiAstrology (переносится в новое приложение)
| Где | Что делает |
|---|---|
src/helpers/hooks/usePushNotifications.ts | Спрашивает разрешение, создаёт Android-канал, получает токен по projectId из app.json → extra.eas.projectId |
AuthService.sendPushToken | POST /push/mobile после логина |
server/…/push/mobile | Хранит токены: один на пользователя и устройство |
server/…/cron/daily-horoscope-push.cron.ts | Ежедневный пуш в DAILY_PUSH_HOUR (по умолчанию 8:00) по местному времени |
src/helpers/hooks/usePushNavigator.ts | По тапу открывает экран из data.screen: horoscope / chats / people |
8Android: ключ FCM V1 в Expo
google-services.jsonдолжен быть в сборке (шаг 2). Без него на устройствеgetExpoPushTokenAsyncпадает с ошибкой про FirebaseApp.- Firebase → Project settings → Service accounts → Generate new private key. Скачается JSON. Ссылка для AiAstrology.
- Загрузить JSON в Expo:
eas credentials→ Android → production → Google Service Account → Push Notifications (FCM V1). Или на expo.dev → проект → Credentials → Android.
9iOS: APNs-ключ в Expo
- Проще всего:
eas credentials→ iOS → production → Push Notifications → Set up a new key. EAS сам создаст ключ в Apple и привяжет его к проекту. Capability Push Notifications EAS тоже включает сам. - Вручную: developer.apple.com → Certificates, IDs & Profiles → Keys → «+» → Apple Push Notifications service → скачать
.p8(скачивается только один раз), записать Key ID и Team ID → загрузить вeas credentials. Один APNs-ключ подходит для всех приложений аккаунта.
10Отправить тестовый пуш
- Взять токен с реального устройства (симулятор iOS токен не даёт), например из коллекции
MobilePushTokenпосле логина. - Отправить через expo.dev/notifications или так:
curl -H "Content-Type: application/json" -X POST https://exp.host/--/api/v2/push/send \ -d '{"to":"ExponentPushToken[...]","title":"Test","body":"Hello","data":{"screen":"horoscope"}}' - В ответе будет
id. Через минуту проверить, что Google/Apple приняли пуш:curl -H "Content-Type: application/json" -X POST https://exp.host/--/api/v2/push/getReceipts \ -d '{"ids":["<id>"]}'
| Ответ | Что значит |
|---|---|
| status: ok | Всё работает |
| InvalidCredentials | Не загружен ключ FCM V1 (шаг 8) или APNs (шаг 9) |
| DeviceNotRegistered | Приложение удалено или токен устарел |
На сервере используется new Expo() без токена. Если на expo.dev включить Enhanced Security for Push Notifications, нужен access token (expo.dev → Account settings → Access tokens) в server/.env и new Expo({ accessToken }).
11Выпустить версию
Реальные пользователи появятся в Firebase и Google Ads только после выхода версии с Firebase в App Store и Google Play. Рекламу на установки запускать после этого.
Значения AiAstrology
В новом приложении замени их на свои.
| Что | Значение | Где взять |
|---|---|---|
| Bundle ID / package | com.kapernikrs.aiastrology | app.json |
| Firebase-проект | aiastrology-3a616 | console.firebase.google.com |
| App Store ID | 6756072533 | ссылка на приложение в App Store |
| EAS projectId | d1def0ec-9920-48b9-9084-f37fabbd67e1 | app.json → extra.eas.projectId |
| EAS slug | expoAiAstrology | app.json → slug |
Грабли, на которые уже наступали
| Симптом | Решение |
|---|---|
expo install @react-native-firebase/… ставит v27 и падает: @firebase/ai требует Node ≥ 24.12 | yarn add …@26.4.0 или обновить Node |
pod install: «SPM + static linkage is not supported» | disableSPM: true в опциях плагина |
pod install: Unicode Normalization not appropriate for ASCII-8BIT | Запускать с LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 |
После prebuild --clean Android не собирается, нет google-services.json | Файл был в /android и удалился. Держать его в корне |
| Поменял конфиг, ничего не изменилось | Нужна пересборка нативного приложения, Metro reload не поможет |
Debug-сборка из xcodebuild падает на facebook::react::Sealable | С Firebase не связано. Собирать Debug из Xcode, Release собирается |
| Пуш «отправлен», но не пришёл | Проверить receipt (шаг 10): почти всегда не загружен ключ FCM/APNs |