Android SDK — интеграция для разработчика и ИИ-агента
Документ выверен для SDK 2.8.0. Актуальную версию смотрите в
Release Notes Android и подставляйте её вместо
<SDK_VERSION>.
Документ самодостаточен: по нему интеграцию можно выполнить
полностью автономно, без вопросов к команде. Подходит и человеку, и ИИ-агенту
(Claude Code, Cursor). Читается сверху вниз как playbook.
Оглавление
Краткое содержание
Документ выверен для SDK 2.8.0. Актуальную версию смотрите в Release Notes Android и подставляйте её вместо <SDK_VERSION>. Документ самодостаточен: по нему интеграцию можно выполнить полностью автономно, без вопросов к команде. Подходит и человеку, и ИИ-агенту (Claude Code, Cursor). Читается сверху вниз как playbook.
TL;DR — золотой путь
Минимум, чтобы события пошли (флейвор allserv, замените плейсхолдеры вида `<FLOW_ID>` (см. таблицу плейсхолдеров ниже)):
-
В
settings.gradle.ktsдобавьте репозитории артефактов (SDK + Huawei для флейворовallserv/huawei):dependencyResolutionManagement {repositories {maven("https://packages.a.mts.ru/repository/maven-releases/") {name = "mts_analytics_sdk"content { includeGroupAndSubgroups("ru.mts.analytics") }}// транзитивные зависимости HMS для флейворов allserv/huawei —// артефактов com.huawei.* нет в google()/mavenCentral()maven("https://developer.huawei.com/repo/") {name = "huawei_repo"content { includeGroupAndSubgroups("com.huawei") }}}} -
В
<module>/build.gradle.kts(где<module>— имя вашего Android-модуля, напримерapp) добавьте зависимость:dependencies {implementation("ru.mts.analytics:android-sdk-allserv-v2:<SDK_VERSION>")} -
В
AndroidManifest.xmlдобавьте разрешение:<uses-permission android:name="android.permission.INTERNET" /> -
В
Applicationвыполните инициализацию и отправьте одно событие:import ru.mts.analytics.sdk2.publicapi.MTSAnalyticsimport ru.mts.analytics.sdk2.publicapi.config.MtsAnalyticsConfigimport ru.mts.analytics.sdk2.publicapi.event.Eventclass App : android.app.Application() {override fun onCreate() {super.onCreate()val analytics = MTSAnalytics.getInstance(context = this,config = MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>").build(),)analytics.track(Event.AppEvent(eventName = "app_open"))}}
Проверка: adb logcat -s 'MA_ANALYTICS:*' — видны строки MA_CONFIG ->, MA_SESSION ->, MA_EMITTER ->.
Единственный Android-тег логов SDK — MA_ANALYTICS; подсистема (MA_CONFIG, MA_SESSION, MA_EMITTER, MA_NETWORK) указывается префиксом внутри текста сообщения (MA_CONFIG -> ...), а не отдельным тегом.
Дальше — полные шаги с проверками и опциями.
Предусловия и плейсхолдеры
Требования: Android (Kotlin), minSdk 23, targetSdk 36, compileSdk 36, JDK 17.
flowId — идентификатор потока аналитики. Если его нет — запросить на analytics.support@mts.ru (тема «Получение Flow ID»). Для интеграции подставляйте <FLOW_ID>.
В таблице плейсхолдеров указаны значения для подстановки:
<FLOW_ID>— UUID потока аналитики (пример:aabb1111-2c2d-3e3f-4444-555566667777).<SDK_VERSION>— версия SDK (актуальная в Release Notes Android, пример:2.8.0).<APP_PACKAGE>— package приложения (пример:ru.example.app).<UPTIME_PROVIDER_AUTHORITY>— уникальный authority провайдера (см. рецепт 8 app-start, пример:ru.example.app.MTSAUptimeProvider).
Шаг 1. Репозиторий артефактов
Добавьте адрес артефактов SDK в settings.gradle.kts:
dependencyResolutionManagement {
repositories {
maven("https://packages.a.mts.ru/repository/maven-releases/") {
name = "mts_analytics_sdk"
content { includeGroupAndSubgroups("ru.mts.analytics") }
}
}
}
Блок content { includeGroupAndSubgroups(...) } ограничивает репозиторий только артефактами SDK — Gradle не будет обращаться к нему за другими зависимостями.
Для флейворов allserv и huawei дополнительно нужен репозиторий Huawei. Эти флейворы тянут транзитивные зависимости HMS (com.huawei.hms:location, ads-identifier, ads-installreferrer), которых нет ни в google(), ни в mavenCentral() — без этого репозитория сборка пад ает с Could not find com.huawei.hms:...:
dependencyResolutionManagement {
repositories {
// транзитивные зависимости HMS (только для флейворов allserv/huawei)
maven("https://developer.huawei.com/repo/") {
name = "huawei_repo"
content { includeGroupAndSubgroups("com.huawei") }
}
}
}
Для флейворов google и noserv репозиторий Huawei не нужен.
Если резолюция не работает после изменения settings.gradle.kts, добавьте аналогичный блок repositories в корневой build.gradle.kts:
// корневой build.gradle.kts — резервный вариа нт при проблемах резолюции
allprojects {
repositories {
maven("https://packages.a.mts.ru/repository/maven-releases/") {
name = "mts_analytics_sdk"
content { includeGroupAndSubgroups("ru.mts.analytics") }
}
}
}
Резервный блок allprojects { repositories { ... } } не сработает, если в settings.gradle.kts задан repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) — тогда добавляйте репозиторий только в dependencyResolutionManagement (первый вариант).
DoD Шага 1: ./gradlew --refresh-dependencies help завершается успешно; репозиторий резолвится (нет Could not resolve ru.mts.analytics).
Шаг 2. Флейвор и зависимость
Выберите флейвор в зависимости от поддерживаемых сервисов:
| Условие проекта | Флейвор | Артефакт |
|---|---|---|
| Только Google Play Services | google | ru.mts.analytics:android-sdk-google-v2 |
| Только Huawei HMS | huawei | ru.mts.analytics:android-sdk-huawei-v2 |
| И Google, и Huawei | allserv | ru.mts.analytics:android-sdk-allserv-v2 |
| Без сервисов (крайний случай) | noserv | ru.mts.analytics:android-sdk-noserv-v2 |
noserv не собирает основные идентификаторы, что снижает точность аналитики.
Для allserv/huawei обязателен репозиторий Huawei из Шага 1.
В <module>/build.gradle.kts (выберите один вариант):
allserv
dependencies {
implementation("ru.mts.analytics:android-sdk-allserv-v2:<SDK_VERSION>")
}
dependencies {
implementation("ru.mts.analytics:android-sdk-google-v2:<SDK_VERSION>")
}
huawei
dependencies {
implementation("ru.mts.analytics:android-sdk-huawei-v2:<SDK_VERSION>")
}
noserv
dependencies {
implementation("ru.mts.analytics:android-sdk-noserv-v2:<SDK_VERSION>")
}
Если в проекте есть свои build-варианты, привязывайте по конфигурации:
dependencies {
"googleImplementation"("ru.mts.analytics:android-sdk-google-v2:<SDK_VERSION>")
"huaweiImplementation"("ru.mts.analytics:android-sdk-huawei-v2:<SDK_VERSION>")
}
DoD Шага 2: ./gradlew :<module>:dependencies --configuration debugRuntimeClasspath | grep ru.mts.analytics показывает выбранный артефакт версии <SDK_VERSION>; сборка ./gradlew :<module>:assembleDebug проходит.
Шаг 3. Разрешения манифеста
SDK автоматически мержит ряд разрешений через манифест-мерджер; потребителю нужно добавить только то, чего в манифесте SDK нет.
| Разрешение | Зачем | Кто объявляет / когда добавлять |
|---|---|---|
android.permission.INTERNET | отправка событий | потребитель — в манифесте SDK отсутствует, автоматически не мержится; добавить обязат ельно |
android.permission.ACCESS_NETWORK_STATE | определение типа сети | SDK — мержится автоматически; добавлять не нужно |
android.permission.READ_EXTERNAL_STORAGE | fingerprint (хранилище) | SDK — объявлено с maxSdkVersion="32"; на API 33+ автоматически заменено READ_MEDIA_*; мержится автоматически |
com.google.android.gms.permission.AD_ID | AdvertisingId | SDK объявляет с tools:node="remove" (удаляет запись из манифеста); для google-флейвора на API 33+ добавляет потребитель или Google Play Services |
com.google.android.providers.gsf.permission.READ_GSERVICES | fingerprint (GSF) | SDK — мержится автоматически; добавлять не нужно |
Минимум для AndroidManifest.xml — всегда:
<!-- обязательно: SDK не объявляет INTERNET, мерджер не добавит автоматически -->
<uses-permission android:name="android.permission.INTERNET" />
Для google-флейвора на API 33+ SDK удаляет запись AD_ID из своего манифеста (tools:node="remove"); Google Play Services восстанавливает её автоматически. Добавляйте её явно только если GPS не поставляет её в вашем проекте:
<!-- google-флейвор + API 33+: SDK удаляет эту запись, добавляем явно -->
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
Библиотеки Huawei (транзитивный com.huawei.hms:location → LocationLiteSdk) добавляют в merged-манифест приложения свои разрешения: ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, com.huawei.permission.ACCESS_HW_KEYSTORE. Манифест самого SDK их не объявляет. Учитывайте это при privacy-ревью и публикации в сторах: приложение начнёт декларировать доступ к геолокации.
Если приложение не использует геолокацию, разрешения можно исключить в своём AndroidManifest.xml (SDK активных запросов геолокации не делает — местоположение передаётся только вручную через analytics.setLocation(...)):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" tools:node="remove" />
</manifest>
DoD Шага 3: ./gradlew :<module>:processDebugManifest (или assembleDebug) проходит; в merged-манифесте присутствует INTERNET.
Шаг 4. Инициализация
import ru.mts.analytics.sdk2.publicapi.MTSAnalytics
import ru.mts.analytics.sdk2.publicapi.api.MtsAnalyticsApi
import ru.mts.analytics.sdk2.publicapi.config.MtsAnalyticsConfig
import ru.mts.analytics.sdk2.logger.LogLevel
class App : android.app.Application() {
lateinit var analytics: MtsAnalyticsApi
private set
override fun onCreate() {
super.onCreate()
analytics = MTSAnalytics.getInstance(
context = this,
config = MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setLogLevel(LogLevel.ERROR) // релиз: ERROR/OFF; отладка: VERBOSE
.setCrashReportingEnabled(true)
.build(),
)
}
}
getInstance(...) возвращает один и тот же экземпляр для одного flowId.
Обработка ошибок. Пустой, невалидный или нулевой UUID (00000000-0000-0000-0000-000000000000) в flowId → getInstance(...) бросает IllegalArgumentException("FlowId must be in UUID format, but was: ..."). Проверьте <FLOW_ID> до сборки.
DoD Шага 4: приложение стартует без падения; adb logcat -s 'MA_ANALYTICS:*' показывает строки MA_CONFIG -> и создание сессии MA_SESSION ->.
Шаг 5. Конфигурация
Все параметры задаются через MtsAnalyticsConfig.Builder при инициализации; изменить конфигурацию в runtime можно через analytics.updateConfig(...).
| Сеттер | Смысл | Дефолт | Границы |
|---|---|---|---|
setLogLevel(LogLevel) | уровень логирования в logcat | OFF | VERBOSE, DEBUG, WARNING, ERROR, OFF |
setLoggerDelegate(LoggerDelegate?) | внешний обработчик логов | null | — |
setNetworkTrafficEnabled(Boolean) | включить отправку событий по сети | true | — |
setCrashReportingEnabled(Boolean) | перехватывать JVM-краши | false | — |
setNativeCrashReportingEnabled(Boolean) | перехватывать native-краши | false | — |
setAnrMonitoringEnabled(Boolean) | мониторинг ANR | false | — |
setAnrMonitoringTimeout(Int) | таймаут обнаружения ANR, секунды | 5 | мин 5 |
setCollectAppStartMetricsEnabled(Boolean) | собирать метрики старта приложения | false | — |
setCollectUIMetricsEnabled(Boolean) | собирать метрики UI | false | — |
setActiveTimeout(Int) | таймаут активной сессии, секунды | 1800 | мин 900, макс 86400 |
setBackgroundTimeout(Int) | таймаут фоновой сессии, секунды | 1800 | мин 900, макс 86400 |
setEventStorageLimit(Int) | лимит событий в локальном хранилище | 6000 | мин 3000, макс 20000 |
setAllowFallbackMode(Boolean) | резервный режим работы в памяти при недоступности локального хранилища | false | — |
subscribeForInstallReferrer { } | подписка на получение install_referrer (Map<String,String>) один раз при инициализации | не задан | подробнее — рецепт install referrer ниже |
НЕ ДЕЛАЙ: не менять flowId в runtime — локальное хранилище событий создаётся заново, накопленные неотправленные события не переносятся.
Пример обновления конфигурации в runtime (без изменения flowId):
analytics.updateConfig(
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setLogLevel(LogLevel.VERBOSE)
.setActiveTimeout(3600)
.build(),
)
DoD Шага 5: конфигурация применяется без перезапуска; adb logcat -s 'MA_ANALYTICS:*' отражает новые значения ч ерез MA_CONFIG ->.
Шаг 6. Отправка событий
Event.AppEvent — универсальный шаблон. Обязателен eventName; остальные поля опциональны (зарезервированные ключи из ru.mts.analytics.sdk2.publicapi.MtsDimensions подставляются автоматически).
import ru.mts.analytics.sdk2.publicapi.event.Event
analytics.track(
Event.AppEvent(
eventName = "purchase_tap",
screenName = "cart",
customDimensions = mapOf("item_id" to "42", "price" to 199),
),
)
// Открытие экрана — спец-значение eventName:
analytics.track(Event.AppEvent(eventName = "scrn", screenName = "main"))
Короткие перегрузки:
analytics.track("app_open")
analytics.track("app_open", "source", "push")
analytics.track("app_open", "source" to "push", "step" to 1)
analytics.track("app_open", mapOf("source" to "push"))
Ошибки — Event.ErrorEvent с полем throwable (стектрейс обрезается ~5000 символов):
runCatching { risky() }.onFailure { analytics.track(Event.ErrorEvent(throwable = it, errMsg = "risky failed")) }
DoD Шага 6: после track(...) в adb logcat -s 'MA_ANALYTICS:*' виден MA_EMITTER ->.
Отправка в сеть (MA_NETWORK ->) идёт батчами: события (кроме ErrorEvent) уходят при накоплении батча (по умолчанию 10 событий) либо по таймауту простоя — поэтому для проверки отправьте ~10 track(...) (не считая системных событий и resolve*). ErrorEvent отправляется сразу, вне батча. Подтверждение доставки в консоли МТС Аналитики — ручной шаг (у ИИ-агента нет доступа к консоли; не считать это провалом).
Шаг 7. Приёмка (Definition of Done)
Локально проверяемо (агент может подтвердить сам):
./gradlew :<module>:assembleDebug— успех.- Зависимость резолвится:
./gradlew :<module>:dependencies | grep ru.mts.analytics→<SDK_VERSION>. - Приложение запускается без падения.
adb logcat -s 'MA_ANALYTICS:*'при старте показываетMA_CONFIG ->,MA_SESSION ->.- После ~10
track(...)видныMA_EMITTER ->иMA_NETWORK ->(события батчатся по ~10 либо уходят по таймауту простоя;ErrorEvent— сразу).
Ручной шаг (человек): подтвердить приход событий в консоли МТС Аналитики.
Если события не идут → Приложение: troubleshooting.
Рецепты по подсистемам
1. Краши JVM/Kotlin + native + ANR
Когда: нужно автоматически перехватывать фатальные JVM-ошибки, native-краши (C++/NDK) и ANR.
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setCrashReportingEnabled(true) // JVM/Kotlin-краши
.setNativeCrashReportingEnabled(true) // native-краши (NDK)
.setAnrMonitoringEnabled(true) // ANR watchdog
.setAnrMonitoringTimeout(5) // мин 5 сек
.build()
Подробнее: Краши и ANR.
2. Performance — трассировка и метрики UI
Когда: нужно замерять время операций, перехватывать HTTP-запросы или собирать метрики старта/UI.
// Включить в конфиге:
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setCollectAppStartMetricsEnabled(true) // метрики старта: нужны MTSAUptimeProvider + AppCompatActivity — см. рецепт 8
.setCollectUIMetricsEnabled(true)
.build()
// Ручная трассировка:
val trace: MTTrace = analytics.performance.newTrace("my_operation")
trace.start()
// ... операция ...
trace.stop()
HTTP-перехватчик для OkHttp
Позволяет автоматически собирать сетевые метрики производительности. Для этого необходимо добавить перехватчик MTInterceptor в билдер OkHttpClient.
Remote Config / эксперименты
Помогает получать конфигурацию с сервера и участвовать в A/B-тестах. SDK предоставляет интерфейс MARemoteConfig для установки дефолтных значений и запроса актуальных данных с сервера.
E-commerce
Позволяет отправлять события электронной коммерции (просмотры, корзина, покупки) в форматах GA4 и Universal Analytics. Используются специализированные классы событий EcommerceGA4Event и EcommerceUAEvent.
Deep link — передача URI в аналитику
Позволяет фиксировать переходы по внешним ссылкам (deep link). Необходимо вызывать метод трекинга URI в методах onCreate и onNewIntent активности.
Link Manager — короткие ссылки и deep link В тексте вы найдете руководство по решению задачи обработки брендированных коротких ссылок МТС. Инструкция охватывает две задачи: внешние переходы через Android App Links и внутренние переходы внутри приложения.
- Для внешних переходов требуется регистрация поддомена и SHA-256 ключа для публикации
assetlinks.json. - В манифесте настраивается
intent-filterсautoVerify="true"для точного хоста. - Для внутренних ссылок (из чатов, баннеров) используется метод
resolveLink, который раскрывает короткую ссылку в реальный URL для навигации внутри приложения, избегая открытия браузера. - На устройствах Huawei рекомендуется использовать
resolveLinkкак устойчивый способ маршрутизации.
Install Referrer — источник установки Помогает определить источник установки приложения (Google, Huawei, RuStore и др.). SDK поддерживает получение реферрала через колбэк при инициализации или через Flow после инициализации.
App-start metrics — провайдер времени запуска
Позволяет собирать точные метрики холодного старта приложения. Для этого необходимо добавить провайдер MTSAUptimeProvider в манифест и включить сбор метрик в конфиге. Метрики собираются корректно только при использовании AppCompatActivity.
MTS ID cross-auth — воронка аутентификации Позволяет отслеживать шаги воронки авторизации через MTS ID. События трекаются с указанием уникального токена сессии и названия шага воронки.
Web-session query — связь сессий app ↔ web Помогает передать идентификатор мобильной сессии в WebView или браузер для сквозной аналитики. SDK предоставляет асинхронный метод для получения строки запроса с идентификатором сессии.
Профиль пользователя — userId, userAgent, location Позволяет глобально устанавливать идентификатор пользователя, User-Agent и геолокацию. Идентификатор пользователя сохраняется между перезапусками, геолокацию можно задать через координаты или объект Location.
SDK-in-SDK — схема AnalyticsHostDelegate Предназначена для экосистемных модулей (Eco SDK), встраиваемых в хост-приложение. Модуль не должен создавать собственный экземпляр SDK, а должен делегировать вызовы хосту. В модуле запрещено включать отчетность о крашах, добавлять провайдер времени запуска и зависимости install-referrer.
Fallback mode — работа без базы данных Позволяет SDK продолжать работу в памяти, если SQLite недоступен. Режим следует отключать в продакшене, так как события не сохраняются при перезапуске приложения.
Приложение: таблицы В статье приведены таблицы флейворов, флагов конфигурации и разрешений, а также раздел Troubleshooting с описанием частых ошибок (невалидный FlowId, отсутствие интернета, конфликты версий) и способов их решения.
Глоссарий В разделе описаны основные классы SDK, их назначение и публичные интерфейсы, включая работу с событиями, конфигурацией, производительностью и логированием.
Актуальность инструкции Рекомендуется проверять актуальную версию SDK и изменения в Release Notes при обновлении библиотеки.
- TL;DR — золотой путь
- Предусловия и плейсхолдеры
- Шаг 1. Репозиторий артефактов
- Шаг 2. Флейвор и зависимость
- Шаг 3. Разрешения манифеста
- Шаг 4. Инициализация
- Шаг 5. Конфигурация
- Шаг 6. Отправка событий
- Шаг 7. Приёмка (Definition of Done)
- Рецепты по подсистемам
- Приложение: таблицы
- Глоссарий
- Актуальность инструкции
TL;DR — золотой путь
Минимум, чтобы события пошли (флейвор allserv, замените плейсхолдеры вида `<FLOW_ID>` (см. таблицу плейсхолдеров ниже)):
1. settings.gradle.kts — репозитории артефактов (SDK + Huawei для флейворов allserv/huawei):
dependencyResolutionManagement {
repositories {
maven("https://packages.a.mts.ru/repository/maven-releases/") {
name = "mts_analytics_sdk"
content { includeGroupAndSubgroups("ru.mts.analytics") }
}
// транзитивные зависимости HMS для флейворов allserv/huawei —
// артефактов com.huawei.* нет в google()/mavenCentral()
maven("https://developer.huawei.com/repo/") {
name = "huawei_repo"
content { includeGroupAndSubgroups("com.huawei") }
}
}
}
2. <module>/build.gradle.kts (где <module> — имя вашего Android-модуля, например app) — зависимость:
dependencies {
implementation("ru.mts.analytics:android-sdk-allserv-v2:<SDK_VERSION>")
}
3. AndroidManifest.xml — разрешение:
<uses-permission android:name="android.permission.INTERNET" />
4. Application — инициализация и одно событие:
import ru.mts.analytics.sdk2.publicapi.MTSAnalytics
import ru.mts.analytics.sdk2.publicapi.config.MtsAnalyticsConfig
import ru.mts.analytics.sdk2.publicapi.event.Event
class App : android.app.Application() {
override fun onCreate() {
super.onCreate()
val analytics = MTSAnalytics.getInstance(
context = this,
config = MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>").build(),
)
analytics.track(Event.AppEvent(eventName = "app_open"))
}
}
Проверка: adb logcat -s 'MA_ANALYTICS:*' — видны строки MA_CONFIG ->, MA_SESSION ->, MA_EMITTER ->.
Единственный Android-тег логов SDK — MA_ANALYTICS; подсистема (MA_CONFIG, MA_SESSION, MA_EMITTER, MA_NETWORK) указывается префиксом внутри текста сообщения (MA_CONFIG -> ...), а не отдельным тегом.
Дальше — полные шаги с проверками и опциями.
Предусловия и плейсхолдеры
Требования: Android (Kotlin), minSdk 23, targetSdk 36, compileSdk 36, JDK 17.
flowId — идентификатор потока аналитики. Если его нет — запросить на
analytics.support@mts.ru (тема «Получение Flow ID»). Для интеграции подставляйте <FLOW_ID>.
| Плейсхолдер | Что подставить | Пример |
|---|---|---|
<FLOW_ID> | UUID потока аналитики | aabb1111-2c2d-3e3f-4444-555566667777 |
<SDK_VERSION> | версия SDK — актуальная в Release Notes Android | 2.8.0 |
<APP_PACKAGE> | package приложения | ru.example.app |
<UPTIME_PROVIDER_AUTHORITY> | уникальный authority провайдера — см. рецепт 8 (app-start) | ru.example.app.MTSAUptimeProvider |
Шаг 1. Репозиторий артефактов
Добавьте адрес артефактов SDK в settings.gradle.kts:
dependencyResolutionManagement {
repositories {
maven("https://packages.a.mts.ru/repository/maven-releases/") {
name = "mts_analytics_sdk"
content { includeGroupAndSubgroups("ru.mts.analytics") }
}
}
}
Блок content { includeGroupAndSubgroups(...) } ограничивает репозиторий только артефактами SDK — Gradle не будет обращаться к нему за другими зависимостями.
Для флейворов allserv и huawei дополнительно нужен репозиторий Huawei. Эти флейворы
тянут транзитивные зависимости HMS (com.huawei.hms:location, ads-identifier,
ads-installreferrer), которых нет ни в google(), ни в mavenCentral() — без этого
репозитория сборка падает с Could not find com.huawei.hms:...:
dependencyResolutionManagement {
repositories {
// транзитивные зависимости HMS (только для флейворов allserv/huawei)
maven("https://developer.huawei.com/repo/") {
name = "huawei_repo"
content { includeGroupAndSubgroups("com.huawei") }
}
}
}
Для флейворов google и noserv репозиторий Huawei не нужен.
Если резолюция не работает после изменения settings.gradle.kts, добавьте аналогичный блок repositories в корневой build.gradle.kts:
// корневой build.gradle.kts — резервный вариант при проблемах резолюции
allprojects {
repositories {
maven("https://packages.a.mts.ru/repository/maven-releases/") {
name = "mts_analytics_sdk"
content { includeGroupAndSubgroups("ru.mts.analytics") }
}
}
}
Резервный блок allprojects { repositories { ... } } не сработает, если в settings.gradle.kts задан repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) — тогда добавляйте репозиторий только в dependencyResolutionManagement (первый вариант).
DoD Шага 1: ./gradlew --refresh-dependencies help завершается успешно; репозиторий
резолвится (нет Could not resolve ru.mts.analytics).
Шаг 2. Флейвор и зависимость
Выберите флейвор в зависимости от поддерживаемых сервисов:
| Условие проекта | Флейвор | Артефакт |
|---|---|---|
| Только Google Play Services | google | ru.mts.analytics:android-sdk-google-v2 |
| Только Huawei HMS | huawei | ru.mts.analytics:android-sdk-huawei-v2 |
| И Google, и Huawei | allserv | ru.mts.analytics:android-sdk-allserv-v2 |
| Без сервисов (крайний случай) | noserv | ru.mts.analytics:android-sdk-noserv-v2 |
noserv не собирает основные идентификаторы, что снижает точность аналитики.
Для allserv/huawei обязателен репозиторий Huawei из Шага 1.
<module>/build.gradle.kts (выберите один вариант):
- Google и Huawei (allserv)
- Только Google
- Только Huawei
- Без сервисов (noserv)
dependencies {
implementation("ru.mts.analytics:android-sdk-allserv-v2:<SDK_VERSION>")
}
dependencies {
implementation("ru.mts.analytics:android-sdk-google-v2:<SDK_VERSION>")
}
dependencies {
implementation("ru.mts.analytics:android-sdk-huawei-v2:<SDK_VERSION>")
}
dependencies {
implementation("ru.mts.analytics:android-sdk-noserv-v2:<SDK_VERSION>")
}
Если в проекте есть свои build-варианты, привязывайте по конфи гурации:
dependencies {
"googleImplementation"("ru.mts.analytics:android-sdk-google-v2:<SDK_VERSION>")
"huaweiImplementation"("ru.mts.analytics:android-sdk-huawei-v2:<SDK_VERSION>")
}
DoD Шага 2: ./gradlew :<module>:dependencies --configuration debugRuntimeClasspath | grep ru.mts.analytics
показывает выбранный артефакт версии <SDK_VERSION>; сборка ./gradlew :<module>:assembleDebug проходит.
Шаг 3. Разрешения манифеста
SDK автоматически мержит ряд разрешений через манифест-мерджер; потребителю нужно добавить только то, чего в манифесте SDK нет.
| Разрешение | Зачем | Кто объявляет / когда добавлять |
|---|---|---|
android.permission.INTERNET | отправка событий | потребитель — в манифесте SDK отсутствует, автоматически не мержится; добавить обязательно |
android.permission.ACCESS_NETWORK_STATE | определение типа сети | SDK — мержится автоматически; добавлять не нужно |
android.permission.READ_EXTERNAL_STORAGE | fingerprint (хранилище) | SDK — объявлено с maxSdkVersion="32"; на API 33+ автоматически заменено READ_MEDIA_*; мержится автоматически |
com.google.android.gms.permission.AD_ID | AdvertisingId | SDK объявляет с tools:node="remove" (удаляет запись из манифеста); для google-флейвора на API 33+ добавляет потребитель или Google Play Services |
com.google.android.providers.gsf.permission.READ_GSERVICES | fingerprint (GSF) | SDK — мержится автоматически; добавлять не нужно |
Минимум для AndroidManifest.xml — всегда:
<!-- обязательно: SDK не объявляет INTERNET, мерджер не добавит автоматически -->
<uses-permission android:name="android.permission.INTERNET" />
Для google-флейвора на API 33+ SDK удаляет запись AD_ID из своего манифеста (tools:node="remove"); Google Play Services восстанавли вает её автоматически. Добавляйте её явно только если GPS не поставляет её в вашем проекте:
<!-- google-флейвор + API 33+: SDK удаляет эту запись, добавляем явно -->
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
Библиотеки Huawei (транзитивный com.huawei.hms:location → LocationLiteSdk) добавляют
в merged-манифест приложения свои разрешения: ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION,
ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, com.huawei.permission.ACCESS_HW_KEYSTORE.
Манифест самого SDK их не объявляет. Учитывайте это при privacy-ревью и публикации в сторах:
приложение начнёт декларировать доступ к геолокации.
Если приложение не использует геолокацию, разрешения можно исключить в своём
AndroidManifest.xml (SDK активных запросов геолокации не делает — местоположение
передаётся только вручную через analytics.setLocation(...)):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" tools:node="remove" />
</manifest>
DoD Шага 3: ./gradlew :<module>:processDebugManifest (или assembleDebug) проходит;
в merged-манифесте присутствует INTERNET.
Шаг 4. Инициализация
import ru.mts.analytics.sdk2.publicapi.MTSAnalytics
import ru.mts.analytics.sdk2.publicapi.api.MtsAnalyticsApi
import ru.mts.analytics.sdk2.publicapi.config.MtsAnalyticsConfig
import ru.mts.analytics.sdk2.logger.LogLevel
class App : android.app.Application() {
lateinit var analytics: MtsAnalyticsApi
private set
override fun onCreate() {
super.onCreate()
analytics = MTSAnalytics.getInstance(
context = this,
config = MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setLogLevel(LogLevel.ERROR) // релиз: ERROR/OFF; отладка: VERBOSE
.setCrashReportingEnabled(true)
.build(),
)
}
}
getInstance(...) возвращает один и тот же экземпляр для одного flowId.
Обработка ошибок. Пустой, невалидный или нулевой UUID
(00000000-0000-0000-0000-000000000000) в flowId → getInstance(...) бросает
IllegalArgumentException("FlowId must be in UUID format, but was: ..."). Проверьте <FLOW_ID> до сборки.
DoD Шага 4: приложение стартует без падения; adb logcat -s 'MA_ANALYTICS:*' показывает
строки MA_CONFIG -> и создание сессии MA_SESSION ->.
Шаг 5. Конфигурация
Все параметры задаются через MtsAnalyticsConfig.Builder при инициализации; изменить конфигурацию в runtime можно через analytics.updateConfig(...).
| Сеттер | Смысл | Дефолт | Границы |
|---|---|---|---|
setLogLevel(LogLevel) | уровень логирования в logcat | OFF | VERBOSE, DEBUG, WARNING, ERROR, OFF |
setLoggerDelegate(LoggerDelegate?) | внешний обработчик логов | null | — |
setNetworkTrafficEnabled(Boolean) | включить отправку событий по сети | true | — |
setCrashReportingEnabled(Boolean) | перехватывать JVM-краши | false | — |
setNativeCrashReportingEnabled(Boolean) | перехватывать native-краши | false | — |
setAnrMonitoringEnabled(Boolean) | мониторинг ANR | false | — |
setAnrMonitoringTimeout(Int) | таймаут обнаружения ANR, секунды | 5 | мин 5 |
setCollectAppStartMetricsEnabled(Boolean) | собирать метрики старта приложения | false | — |
setCollectUIMetricsEnabled(Boolean) | собирать метрики UI | false | — |
setActiveTimeout(Int) | таймаут активной сессии, секунды | 1800 | мин 900, макс 86400 |
setBackgroundTimeout(Int) | таймаут фоновой сессии, секунды | 1800 | мин 900, макс 86400 |
setEventStorageLimit(Int) | лимит событий в локальном хранилище | 6000 | мин 3000, макс 20000 |
setAllowFallbackMode(Boolean) | резервный режим работы в памяти при недоступности локального хранилища | false | — |
subscribeForInstallReferrer { } | подписка на получение install_referrer (Map<String,String>) один раз при инициализации | не задан | подробнее — рецепт install referrer ниже |
НЕ ДЕЛАЙ: не менять flowId в runtime — локальное хранилище событий создаётся заново, накопленные неотправленные события не переносятся.
Пример обновления конфигурации в runtime (без изменения flowId):
analytics.updateConfig(
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setLogLevel(LogLevel.VERBOSE)
.setActiveTimeout(3600)
.build(),
)
DoD Шага 5: конфигурация применяется без перезапуска; adb logcat -s 'MA_ANALYTICS:*' отражает
новые значения через MA_CONFIG ->.
Шаг 6. Отправка событий
Event.AppEvent — универсальный шаблон. Обязателен eventName; остальные поля опциональны
(зарезервированные ключи из ru.mts.analytics.sdk2.publicapi.MtsDimensions подставляются
автоматически).
import ru.mts.analytics.sdk2.publicapi.event.Event
analytics.track(
Event.AppEvent(
eventName = "purchase_tap",
screenName = "cart",
customDimensions = mapOf("item_id" to "42", "price" to 199),
),
)
// Открытие экрана — спец-значение eventName:
analytics.track(Event.AppEvent(eventName = "scrn", screenName = "main"))
Короткие перегрузки:
analytics.track("app_open")
analytics.track("app_open", "source", "push")
analytics.track("app_open", "source" to "push", "step" to 1)
analytics.track("app_open", mapOf("source" to "push"))
Ошибки — Event.ErrorEvent с полем throwable (стектрейс обрезается ~5000 символов):
runCatching { risky() }.onFailure { analytics.track(Event.ErrorEvent(throwable = it, errMsg = "risky failed")) }
DoD Шага 6: после track(...) в adb logcat -s 'MA_ANALYTICS:*' виден MA_EMITTER ->.
Отправка в сеть (MA_NETWORK ->) идёт батчами: события (кроме ErrorEvent) уходят
при накоплении батча (по умолчанию 10 событий) либо по таймауту простоя — поэтому для
проверки отправьте ~10 track(...) (не считая системных событий и resolve*).
ErrorEvent отправляется сразу, вне батча. Подтверждение доставки в консоли МТС
Аналитики — ручной шаг (у ИИ-агента нет доступа к консоли; не считать это провалом).
Шаг 7. Приёмка (Definition of Done)
Локально проверяемо (агент может подтвердить сам):
-
./gradlew :<module>:assembleDebug— успех. - Зависимость резолвится:
./gradlew :<module>:dependencies | grep ru.mts.analytics→<SDK_VERSION>. - Приложение запускается без падения.
-
adb logcat -s 'MA_ANALYTICS:*'при старте показываетMA_CONFIG ->,MA_SESSION ->. - После ~10
track(...)видныMA_EMITTER ->иMA_NETWORK ->(события батчатся по ~10 либо уходят по таймауту простоя;ErrorEvent— сразу).
Ручной шаг (человек): подтвердить приход событий в консоли МТС Аналитик и.
Если события не идут → Приложение: troubleshooting.
Рецепты по подсистемам
1. Краши JVM/Kotlin + native + ANR
Когда: нужно автоматически перехватывать фатальные JVM-ошибки, native-краши (C++/NDK) и ANR.
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setCrashReportingEnabled(true) // JVM/Kotlin-краши
.setNativeCrashReportingEnabled(true) // native-краши (NDK)
.setAnrMonitoringEnabled(true) // ANR watchdog
.setAnrMonitoringTimeout(5) // мин 5 сек
.build()
Подробнее: Краши и ANR.
2. Performance — трассировка и метрики UI
Когда: нужно замерять время операций, перехватывать HTTP-запросы или собирать метрики старта/UI.
// Включить в конфиге:
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setCollectAppStartMetricsEnabled(true) // метрики старта: нужны MTSAUptimeProvider + AppCompatActivity — см. рецепт 8
.setCollectUIMetricsEnabled(true)
.build()
// Ручная трассировка:
val trace: MTTrace = analytics.performance.newTrace("my_operation")
trace.start()
// ... операция ...
trace.stop()
// HTTP-перехватчик для OkHttp:
val interceptor: MTInterceptor = analytics.performance.httpTracker.interceptor
val okHttpClient = OkHttpClient.Builder().addInterceptor(interceptor).build()
3. Remote Config / эксперименты
Когда: нужно получать конфигурацию с сервера и участвовать в A/B-экспериментах.
val remoteConfig: MARemoteConfig = analytics.remoteConfig
// Установить дефолты и запросить актуальные значения:
remoteConfig.fetchRemoteConfigValuesAndActivate { result ->
val value = remoteConfig.activeConfig.value?.stringValue("feature_flag") ?: "default"
}
Подробнее: Remote Config.
4. E-commerce
Когда: нужно отправлять события e-commerce (просмотры, добавление в корзину, покупки).
// GA4-контракт (имена событий — классы, не enum-константы):
analytics.track(
Event.EcommerceGA4Event(
eventName = EcommerceGA4Name.ViewItem(),
ecommerceGA4 = EcommerceGA4(items = listOf(/* EcommerceGA4Item(...) */)),
)
)
// UA-контракт:
analytics.track(
Event.EcommerceUAEvent(
eventName = EcommerceUAName.Detail(),
ecommerceUA = EcommerceUA(detail = Detail(products = listOf(/* Product(...) */))),
)
)
Подробнее: E-Commerce Android.
5. Deep link — передача URI в аналитику
Когда: нужно зафиксировать переход по deep link (из внешнего источника).
// В Activity.onCreate и onNewIntent:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.data?.let { uri -> analytics.track(uri = uri) }
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.data?.let { uri -> analytics.track(uri = uri) }
}
Подробнее: Deep Link Android.
6. Link Manager — короткие ссылки и deep link
Когда: брендированные короткие ссылки МТС (https://<поддомен>.url.mts.ru/...) должны открывать нужный экран приложения (а если приложение не установлено — вести на сайт). Здесь две разные задачи, которые часто путают:
- A. Внешний переход — пользователь нажал на ссылку в браузере / другом приложении / SMS → нужно открыть ваше приложение на целевом экране (Android App Links).
- B. Ссылка внутри приложения — короткая ссылка встроена в UI, пришла из чата поддержки, баннера, push-уведомления → нужно открыть контент в приложении, а не в браузере. Решается через
resolveLink(шаг 6.3). На App Links здесь полагаться нельзя: если ссылку открывает сам код приложения (через WebView / Custom Tab / чат-SDK или как веб-URL), переход обычно идёт мимо App Links — в браузер.
Регистрация (один раз). Письмо на analytics.support@mts.ru, тема «Регистрация в Link Manager»: поддомен (<продукт>.url.mts.ru), SHA-256 ключа подписи приложения, имя пакета. По ним Link Manager публикует на домене Digital Asset Links (assetlinks.json) — это и включает автопроверку App Links.
Шаг 6.1. Манифест — App Links (внешние переходы, задача A).
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"> <!-- singleTask или singleTop — чтобы срабатывал onNewIntent -->
<!-- Автопроверка App Links: ТОЛЬКО https и ТОЛЬКО точный хост (wildcard *.url.mts.ru не верифицируется) -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="<продукт>.url.mts.ru" />
</intent-filter>
</activity>
Условия, без которых App Links не сработает (и ссылка уйдёт в браузер):
autoVerifyработает только поhttps.http-ссылки не верифицируются; если нужно ловить и их — вынеситеhttpв отдельныйintent-filterбезautoVerifyи обрабатывайте такой переход черезresolveLink(шаг 6.3).- Только точный хост. Wildcard
android:host="*.url.mts.ru"вautoVerify-фильтре проверку Digital Asset Links не проходит — указывайте зарегистрированный поддомен<продукт>.url.mts.ruявно (по одному<data>на каждый поддомен). assetlinks.jsonна домене. Автопроверка тянетhttps://<продукт>.url.mts.ru/.well-known/assetlinks.jsonс вашим пакетом и SHA-256 — его публикует Link Manager по данным регистрации. Без него статус не будетverified.android:exported="true"(обязательно с API 31) и категорииDEFAULT+BROWSABLE.launchMode—singleTaskилиsingleTop(чтобы повторные переходы приходили вonNewIntent, а не открывали новый экземпляр экрана).
Проверить верификацию на устройстве: adb shell pm get-app-links <APP_PACKAGE> — для домена ожидается verified. Если none / legacy_failure — проверьте доступность assetlinks.json и точное совпадение SHA-256 и имени пакета.
Шаг 6.2. Обработать открытие приложения по ссылке — в Activity#onCreate и Activity#onNewIntent:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent) // важно для singleTask
handleLink(intent)
}
private fun handleLink(intent: Intent?) {
val uri = intent?.data ?: return
analytics.track(uri) // 1) зафиксировать факт перехода
// 2) короткая ссылка Link Manager? — раскрыть через resolveLink и маршрутизировать по location;
// обычный deep link — маршрутизировать напрямую.
if (uri.authority?.contains("url.mts.ru") == true) {
lifecycleScope.launch {
when (val result = analytics.resolveLink(url = uri)) {
is DeepLinkResult.Success -> routeInApp(result.location, result.params)
is DeepLinkResult.Error -> routeInApp(uri.toString(), emptyMap()) // фолбэк
}
}
} else {
routeInApp(uri.toString(), emptyMap())
}
}
Шаг 6.3. Ссылка ВНУТРИ приложения — раскрыть и маршрутизировать, НЕ отдавать в браузер (задача B).
Это решение проблемы «ссылка из чата или встроенная ссылка открывается в браузере». Не вызывайте startActivity(ACTION_VIEW, url) для короткой ссылки — сначала раскройте её:
lifecycleScope.launch {
when (val result = analytics.resolveLink(url = uri)) {
is DeepLinkResult.Success -> routeInApp(result.location, result.params) // открыть экран в приложении
is DeepLinkResult.Error -> openInBrowser(uri) // фолбэк, если раскрыть не удалось
}
}
resolveLink делает сетевой запрос к бэкенду Link Manager (принудительно использует https, добавляет maAppInstalled / maOsName=android) и возвращает:
DeepLinkResult.Success(location: String, params: Map<String, Any?>)—location= целевой URL редиректа,params= параметры ссылки (вложенность ≤ 3 уровней); по ним стройте in-app навигацию.DeepLinkResult.Error(error: Throwable)— невалидный URL или сетевая ошибка.
Доступен и колбэк-вариант: analytics.resolveLink(url) { result -> }.
- Ссылка из чата поддержки / баннера / захардкоженная не откроется сама через App Links — App Links работает только для переходов ИЗВНЕ приложения. Внутри приложения перехватывайте URL и вызывайте
resolveLink(шаг 6.3). Это тот же случай, что и с короткими ссылками AppsFlyer. - Не открывайте короткую
*.url.mts.ruссылку напрямую в браузере / Custom Tab — сначалаresolveLink, иначе пользователь уйдёт в браузер вместо экрана приложения. - Без регистрации (SHA-256 + пакет →
assetlinks.json) внешняя автопро верка App Links не пройдёт, и система предложит открыть браузер.
Huawei / AppGallery. Отдельной Huawei-специфики в SDK нет и не требуется: resolveLink (шаг 6.3) — обычный сетевой вызов и работает на любом флейворе/сторе (google/huawei/allserv/noserv). Именно resolveLink + ручной роутинг — устойчивый способ маршрутизации на Huawei-устройствах, не зависящий от Google-верификации. OS-level App Links (шаг 6.1) — механизм Android (AOSP), не привязан к Google Play Services.
Подробнее: Link Manager для Android и отслеживание Deeplink.
7. Install Referrer — источник установки
Когда: нужно знать, откуда пользователь установил приложение (Google, Huawei, RuStore, Galaxy, GetApps).
// Вариант 1 — колбэк при инициализации (срабатывает один раз):
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.subscribeForInstallReferrer { referrers ->
val google = referrers["Google"]
}
.build()
// Вариант 2 — Flow (подписка после инициализации):
analytics.installReferrerFlow.collect { referrers ->
val rustore = referrers["Rustore"]
}
Дополнительные зависимости для конкретных магазинов (RuStore, Galaxy, GetApps) подключайте по документации соответствующего магазина.
Подробнее: Install Referrer Android.
8. App-start metrics — провайдер времени запуска
Когда: нужно собирать точные метрики времени холодного старта приложения.
В AndroidManifest.xml (authority должен быть уникальным для каждого приложения):
<provider
android:name="ru.mts.analytics.sdk2.publicapi.providers.MTSAUptimeProvider"
android:authorities="<UPTIME_PROVIDER_AUTHORITY>"
android:exported="false" />
В конфиге:
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setCollectAppStartMetricsEnabled(true)
.build()
Метрики старта собираются полностью только при обоих условиях: (1) провайдер MTSAUptimeProvider добавлен в манифест (выше), и (2) стартовая Activity наследует androidx.appcompat.app.AppCompatActivity. В Compose-шаблоне Android Studio по умолчанию ComponentActivity, в которой нет части lifecycle-методов — тогда TTID/TTFD и метрики видимости первого экрана не соберутся.
9. MTS ID cross-auth — воронка аутентификации
Когда: нужно отслеживать шаги воронки авторизации через MTS ID с привязкой к сессии аутентификации.
// Начало авторизации:
analytics.track(
Event.AppEvent(
eventName = "vntLogin",
mtsIdAuthState = authState, // уникальный токен сеанса аутентификации
funnelName = "fnl_auth",
funnelStep = "fnl_auth_st1",
)
)
10. Web-session query — связь сессий app ↔ web
Когда: нужно передать идентификатор мобильной сессии в WebView/браузер для сквозной аналитики.
// Асинхронный вариант (предпочтителен):
lifecycleScope.launch {
val queryItem = analytics.getWebSessionQueryItemAsync(url = "https://example.mts.ru")
// queryItem вернёт строку вида "_ma=1008798411687163870.1687163881292"
val webUrl = "$baseUrl?$queryItem"
openWebView(webUrl)
}
11. Профиль пользователя — userId, userAgent, location
Когда: нужно глобально установить идентификатор пользователя, User-Agent WebView или геолокацию.
// userId — сохраняется между перезапусками; null — сброс:
analytics.setUserId(userId = "user-guid-123")
// userAgent — в памяти, не переживает рестарт:
analytics.setUserAgent(userAgent = Helpers.getUserAgentOrNull(context))
// Геолокация:
analytics.setLocation(latitude = 55.751244, longitude = 37.618423)
// или через android.location.Location:
analytics.setLocation(location = myLocation)
12. SDK-in-SDK — схема AnalyticsHostDelegate
Когда: ваш продукт — это экосистемный модуль (Eco SDK), который встраивается в хост-приложение МТС, уже содержащее MTSA. Eco SDK не встраивает собственный экземпляр MTSA — он делегирует все вызовы экземпляру хоста через AnalyticsHostDelegate.
Подробная схема интеграции: SDK-in-SDK Android.
НЕ ДЕЛАЙ в релизном Eco SDK:
- не включать
setCrashReportingEnabled(true)/setNativeCrashReportingEnabled(true)/setAnrMonitoringEnabled(true)— перехват крашей и ANR в модуле конфликтует с хост-приложением; - не добавлять
MTSAUptimeProviderв манифест модуля — authority должен быть уникален на приложение, в хост-приложении он уже объявлен; - не подключать зависимости install-referrer (RuStore, Galaxy, GetApps) в модульном артефакте — это зона ответственности хоста.
13. Fallback mode — работа без базы данных
Когда: устройство не поддерживает SQLite или база данных недоступна; нужно, чтобы SDK не падал, а продолжал работу в памяти.
MtsAnalyticsConfig.Builder(flowId = "<FLOW_ID>")
.setAllowFallbackMode(true) // режим работы в памяти при недоступности локального хранилища
.build()
НЕ ДЕЛАЙ: не включать fallback mode по умолчанию в продакшн — события не переживают перезапуск приложения.
Приложение: таблицы
Каноничные таблицы флейворов, флагов конфигурации и разрешений — см. разделы Шаг 1, Шаг 2 и Шаг 3 выше.
Troubleshooting
| Симптом / ошибка | Причина | Фикс |
|---|---|---|
IllegalArgumentException: FlowId must be in UUID format | пустой/невалидный/нулевой UUID | подставить корректный <FLOW_ID> |
| События не приходят в консоль | нет INTERNET / отключён трафик | добавить INTERNET; проверить setNetworkTrafficEnabled(true) |
В logcat нет MA_* логов | logLevel = OFF | setLogLevel(LogLevel.VERBOSE) на время отладки |
Could not resolve ru.mts.analytics:... | не добавлен или неверно указан репозиторий | проверить URL из Шага 1 |
Could not find com.huawei.hms:... (флейвор allserv/huawei) | нет репозитория Huawei — артефактов com.huawei.* нет в google()/mavenCentral() | добавить https://developer.huawei.com/repo/ (Шаг 1) |
| Конфликт версий (например, netty и guava) | транзитивные зависимости | resolutionStrategy { force(...) } в модуле |
| App-start метрики пустые на Compose | ComponentActivity вместо AppCompatActivity | известное ограничение; см. рецепт 8 (app-start) |
| Сборка требует minSdk 23 | RuStore install-referrer требует 23 | поднять minSdk до 23 |
| R8/ProGuard ломает SDK | — | обычно не требуется: SDK поставляет consumer-rules.pro автоматически |
Глоссарий
| Класс (FQN) | Назначение |
|---|---|
ru.mts.analytics.sdk2.publicapi.MTSAnalytics | точка входа SDK; getInstance(context, config) возвращает MtsAnalyticsApi |
ru.mts.analytics.sdk2.publicapi.api.MtsAnalyticsApi | основной публичный интерфейс: track, updateConfig, setUserId, resolveLink и др. |
ru.mts.analytics.sdk2.publicapi.config.MtsAnalyticsConfig | конфигурация SDK; строится через вложенный Builder(flowId) |
ru.mts.analytics.sdk2.publicapi.event.Event.AppEvent | универсальное событие МТС-разметки (eventName, screenName, customDimensions и др.) |
ru.mts.analytics.sdk2.publicapi.event.Event.ErrorEvent | событие с прикреплённым Throwable; стектрейс обрезается до ~5000 символов |
ru.mts.analytics.sdk2.publicapi.event.Event.EcommerceUAEvent | событие электронной торговли в формате Universal Analytics |
ru.mts.analytics.sdk2.publicapi.event.Event.EcommerceGA4Event | событие электронной торговли в формате GA4 |
ru.mts.analytics.sdk2.publicapi.MtsDimensions | объект с константами стандартных dimension-ключей МТС |
ru.mts.analytics.sdk2.publicapi.Helpers | утилиты: getUserAgentOrNull, getDeviceId и др. |
ru.mts.analytics.sdk2.publicapi.api.apicontract.DeepLinkResult | результат resolveLink: содержит URI и параметры deep link |
ru.mts.analytics.sdk2.logger.LogLevel | enum уровней логирования: VERBOSE, DEBUG, WARNING, ERROR, OFF |
ru.mts.analytics.sdk2.publicapi.remoteconfig.MARemoteConfig | интерфейс доступа к удалённой конфигурации и A/B-экспериментам |
ru.mts.analytics.sdk2.publicapi.performance.MTPerformance | интерфейс для ручного измерения производительности (трейсы) |
ru.mts.analytics.sdk2.publicapi.performance.MTTrace | отдельный трейс; start(), stop() |
ru.mts.analytics.sdk2.publicapi.performance.MTInterceptor | OkHttp-перехватчик для автоматического сбора сетевых метрик |
ru.mts.analytics.sdk2.publicapi.providers.MTSAUptimeProvider | ContentProvider для сбора метрик app-start; authority уникален на приложение |
Актуальность инструкции
Актуальную версию SDK и изменения между версиями проверяйте в Release Notes Android. При обновлении SDK перепроверьте инструкцию и синхронизируйте документ.