Android SDK
Kixo Android SDK підтримує Kotlin 2.0+ і Java, потребує minSdk 24 (Android 7.0) і зібраний під compileSdk 35. Ваш застосунок і далі сам відповідає за свій targetSdk. Один виклик Kixo.configure у вашому Application.onCreate автоматично відстежує екрани, натискання, сесії, збої та події життєвого циклу. Для відстеження push потрібен міст FCM, описаний нижче. Автовідстеження мережевих запитів у поточному релізі Android не підтримується. SDK також підтримує відтворення сесій, ідентифікацію та цілі.
Швидкий старт
Три файли. Додайте Maven-репозиторій, додайте залежність, а потім вставте два рядки у свій підклас Application.
Вимоги до збірки: compileSdk 35, minSdk 24, Kotlin 2.0+ або Java, а також байткод Java 17.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo")
}
}
}Примітка
На цьому інтеграцію аналітики завершено. Стандартні автотрекери ввімкнені за замовчуванням; для push, як і раніше, потрібен міст FCM нижче. Перевизначайте окремі прапорці через KixoConfiguration.Builder(...) лише за потреби.
Додайте у застосунок
Maven-репозиторій Kixo розміщено на GitHub Pages. Додайте його поруч із google() і mavenCentral() у settings.gradle.kts:
// settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo")
}
}
}Потім оголосіть залежність у модулі застосунку:
// app/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20")
}Порада
android.permission.INTERNET і android.permission.ACCESS_NETWORK_STATE уже входять до маніфесту SDK. Дозволами на сповіщення, як і раніше, керує ваш застосунок, і оголошуються вони лише тоді, коли ви вмикаєте push-функції.
Багатомодульні проєкти
Конфігурація Gradle implementation має поведінку не транзитивна: якщо оголосити implementation("io.kixo:kixo-android-sdk:0.1.20") у бібліотечному модулі, наприклад :core_domain, то Kixo НЕ стане доступним у :app чи в будь-якому іншому модулі-споживачі. Є два робочі варіанти — оберіть один.
Шаблон A — кожен модуль, що викликає Kixo, сам оголошує цю залежність (рекомендовано). Так classpath кожного модуля залишається мінімальним і не спричиняє каскадних перебудов. Використовуйте version catalog (libs.kixo.sdk), щоб змінювати версію в одному місці.
// :core_domain/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20") // local use only
}
// :app/build.gradle.kts
dependencies {
implementation(project(":core_domain"))
implementation("io.kixo:kixo-android-sdk:0.1.20") // declared again — fine
}Шаблон B — реекспорт через api(...). Оголошення одне, але публічний ABI бібліотечного модуля тепер містить типи Kixo — будь-яка зміна версії змусить перебудувати всі залежні модулі. Використовуйте це лише тоді, коли бібліотека застосовує типи Kixo у власних публічних сигнатурах, наприклад повертає KixoDiagnostics з функції.
// :core_domain/build.gradle.kts
dependencies {
api("io.kixo:kixo-android-sdk:0.1.20") // re-exposed
}
// :app/build.gradle.kts
dependencies {
implementation(project(":core_domain")) // gets Kixo for free
}Увага
Якщо під час компіляції модуля з’являється Unresolved reference: Kixo, цьому модулю бракує власної залежності від SDK — додайте рядок implementation вище або скористайтеся шаблоном B.
Ініціалізація
Налаштуйте Kixo у своєму підкласі Application: onCreate виконується раніше за будь-яку activity, тож усі перегляди екранів, натискання й події життєвого циклу фіксуються з першого кадру. Зареєструйте Application у manifest через android:name=".MyApp".
import android.app.Application
import io.kixo.sdk.Kixo
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Kixo.configure(
context = this,
projectId = "kx_proj_YOUR_PROJECT_ID",
apiKey = "kx_key_YOUR_API_KEY",
)
}
}Щоб точно налаштувати параметри — прапорці автовідстеження, частоту flush, вибірку відтворення сесій, власний API host — явно створіть KixoConfiguration:
import io.kixo.sdk.Kixo
import io.kixo.sdk.KixoConfiguration
val config = KixoConfiguration.Builder(
projectId = "kx_proj_YOUR_PROJECT_ID",
apiKey = "kx_key_YOUR_API_KEY",
)
.autoTrackScreens(true)
.autoTrackTaps(true)
.autoTrackNetwork(false) // reserved; no-op in the current Android release
.autoTrackCrashes(true)
.autoTrackSessions(true)
.autoTrackPush(true)
.flushIntervalMillis(30_000)
.flushAt(20)
.maxBufferSize(200)
.build(applicationContext)
Kixo.configure(this, config)Примітка
Ідемпотентно. Повторний виклик configure в межах того самого процесу нічого не змінює й лише пише WARN у лог — SDK зберігає першу конфігурацію. Події, які ваш auth singleton ставить у чергу до того, як configure відпрацює в до, буферизуються (до 50) і відтворюються після підключення SDK, тож Kixo.identify(...) можна викликати з глобального синглтона ще до завершення Application.onCreate.
Відстеження подій
Основну частину інструментування покривають три примітиви: track для подій, markGoal для сигналів конверсії та addBreadcrumb для контексту поза подіями.
import io.kixo.sdk.Kixo
Kixo.track("video_played", mapOf(
"video_id" to "vid_42",
"duration_ms" to 18_500,
"autoplay" to false,
))
// markGoal(name, value?, currency?, properties?) — pass extra context
// through the named 'properties' argument (a Map can't be the 2nd
// positional arg; that slot is the Double 'value').
Kixo.markGoal("activated", properties = mapOf(
"step" to "onboarding_completed",
))
// Revenue goals use the typed value + currency parameters:
Kixo.markGoal("purchase_completed", value = 49.99, currency = "USD")
Kixo.addBreadcrumb(
message = "user toggled dark mode",
category = "ui",
level = "info",
)Порада
Цілі мають рівні важливості. Позначені цілі використовуються у воронках активації Kixo та в щоденному cron-процесі виявлення змін: якщо обсяг цілі тиждень до тижня падає на 70%, у дашборді вона з’являється з позначкою Потребує перевірки. Використовуйте markGoal для кількох справді важливих моментів, а track — для всього іншого.
Стандартні події
Зручна обгортка над Kixo.track для подій, які Kixo розпізнає за назвою: точні рядкові ключі, які зіставляє детектор стандартних подій на бекенді. Дає перевірку форми властивостей під час компіляції й одне джерело істини для назв.
import io.kixo.sdk.Kixo
import io.kixo.sdk.SubscriptionInterval
Kixo.trackPurchase(
amount = 49.99,
currency = "USD",
productId = "pro_yearly",
)
Kixo.trackSubscriptionStart(
plan = "pro",
amount = 9.99,
currency = "USD",
interval = SubscriptionInterval.MONTH,
)
Kixo.trackSignup(method = "google")
Kixo.trackTrialStart(plan = "pro", days = 14)
Kixo.trackCancel(plan = "pro", reason = "too_expensive")
Kixo.trackUpgrade(fromPlan = "free", toPlan = "pro")
Kixo.trackActivation(event = "first_post_published")
Kixo.trackShare(channel = "twitter", contentId = "post_123")
Kixo.trackInvite(channel = "email", recipientCount = 5)Ідентифікувати користувачів
Прив’язує наступні події до стабільного user id і набору traits. Зіставлення анонімного та відомого користувача відбувається в Kixo — події, зафіксовані до identify, заднім числом буде віднесено до того самого користувача.
import io.kixo.sdk.Kixo
// Reserved standard property keys carry a $-prefix (Mixpanel
// convention) so they namespace away from your own custom traits
// and promote to the dashboard's profile columns. See
// io.kixo.sdk.StandardProperty for the typed catalogue, or the
// "Standard property catalog" section below for the full 37-key list.
Kixo.identify("user_123", mapOf(
"$email" to "jane@example.com", // identity
"$name" to "Jane Doe", // identity
"$plan" to "pro", // subscription pack
"$lifetime_orders" to 12, // e-commerce pack
"signup_source" to "twitter_ad", // custom trait
))
// Logout: clear identity, super-properties, and the persisted queue.
Kixo.reset()⚠️ Пастка зі знаком долара в Kotlin. Стандартні ключі ідентифікації мають префікс $ ($email, $name, $first_name), а в рядковому літералі Kotlin знак долара потрібно треба екранувати як "\$email". Якщо написати "$email", Kotlin підставить значення змінної email, тож воно непомітно запишеться як trait власний і ніколи не заповнить стовпці email / name в Audience. Найпростіше рішення — використати типізоване перевантаження (SDK 0.1.13+), у якому помилитися неможливо: Kixo.setUserProperty(StandardProperty.EMAIL, email).
Позначити користувача для сегментації
Використовуйте setUserProperty зі значенням булеве значення, щоб додати користувачеві просту ознаку «так/ні». Вона зберігається між запусками й використовується в сегментах, email-кампаніях і запитах у чаті — без жодних додаткових налаштувань, лише виклик SDK.
// Tag a user as subscribed — segments + campaigns can target this
Kixo.setUserProperty("subscribe", true)
// VIP membership
Kixo.setUserProperty("vip", true)
// String + numeric values work too
Kixo.setUserProperty("plan_tier", "enterprise")
Kixo.setUserProperty("lifetime_orders", 42)
// Bulk-set
Kixo.setUserProperties(mapOf(
"subscribe" to true,
"plan_tier" to "enterprise",
))Властивості зберігаються через SharedPreferences між запусками й автоматично додаються до кожної вихідної події. У чаті можна написати щось на кшталт "надішли вітальний email користувачам, у яких subscribe має значення true" — Kixo сам збере сегмент і підготує чернетку шаблону. Очищуються на Kixo.reset().
Каталог стандартних властивостей
Зарезервовані ключі властивостей мають префікс $, щоб не перетинатися з вашими власними атрибутами. У каталозі Kixo є 37 ключів у 3 універсальних наборах (ідентичність, геодані, життєвий цикл) і 5 галузевих наборах для B2B (підписка, e-commerce, медіа, маркетплейс, лояльність). Заповнюйте лише ті, що підходять вашому продукту, — дашборд сам підлаштується й покаже тільки використані набори.
Ідентифікація
Завжди актуально. Визначає стовпці в заголовку профілю.
| Ключ | Тип | Опис |
|---|---|---|
$email | рядок | Основна електронна адреса; часто використовується як ключ злиття для зшивання ідентичностей. |
$phone | рядок | Номер телефону у форматі E.164. |
$name | рядок | Повне відображуване ім’я. |
$first_name | рядок | Ім’я. |
$last_name | рядок | Прізвище. |
$avatar_url | рядок | Повний URL зображення аватара користувача. |
Геодані
Географічний контекст.
| Ключ | Тип | Опис |
|---|---|---|
$country | рядок | Код країни за ISO 3166. |
$city | рядок | Назва міста. |
$region | рядок | Штат або область. |
$timezone | рядок | Часовий пояс IANA, наприклад America/Los_Angeles. |
$language | рядок | Тег IETF, наприклад en або ru-RU. |
$locale | рядок | Повний ідентифікатор локалі. |
Життєвий цикл
Коли ми бачили їх востаннє.
| Ключ | Тип | Опис |
|---|---|---|
$created | ISO8601 | Час реєстрації або створення облікового запису. |
$last_seen | ISO8601 | Час останньої взаємодії. |
Підписка
Використовуйте, якщо у вашому продукті є тарифні плани.
| Ключ | Тип | Опис |
|---|---|---|
$plan | рядок | Slug рівня — free, pro, enterprise. |
$subscription_status | рядок | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | Коли завершується поточний пробний період. |
$mrr | число | Щомісячний регулярний дохід у валюті акаунта. |
$subscription_started | ISO8601 | Коли почалася поточна підписка. |
Електронна комерція
Використовуйте, якщо ви продаєте товари.
| Ключ | Тип | Опис |
|---|---|---|
$lifetime_orders | число | Кількість завершених замовлень. |
$lifetime_revenue | число | Загальні витрати. |
$aov | число | Середній чек. |
$last_purchase | ISO8601 | Остання успішна покупка. |
$first_purchase | ISO8601 | Перша успішна покупка. |
$cart_abandoned_count | число | Загальна кількість покинутих кошиків. |
Медіа
Використовуйте, якщо ви публікуєте контент.
| Ключ | Тип | Опис |
|---|---|---|
$content_tier | рядок | free / premium / paid. |
$subscribed_categories | CSV-рядок або масив | Категорії, за якими стежить користувач. |
$watch_time_total | число | Загальний час перегляду в секундах. |
$last_played | ISO8601 | Останній запуск відтворення. |
Маркетплейс
Використовуйте, якщо у вас двостороння платформа.
| Ключ | Тип | Опис |
|---|---|---|
$seller_tier | рядок | Slug рівня на боці продавця. |
$buyer_tier | рядок | slug рівня на боці покупця. |
$listings_count | число | Активні оголошення користувача. |
$reviews_count | число | Відгуки, які отримав користувач. |
$verified | булеве значення | Статус KYC. |
Лояльність
Використовуйте для програм залучення та винагород.
| Ключ | Тип | Опис |
|---|---|---|
$loyalty_points | число | Поточний баланс балів, доступних до використання. |
$vip_level | рядок | Slug рівня VIP. |
$referral_count | число | Успішні реферали, зараховані цьому користувачу. |
Порада
Не бачите свого варіанта? Для власних атрибутів використовуйте звичайні ключі без префікса. Вони з’являться в панелі Custom Traits у Dashboard і не засмічуватимуть стовпці профілю. П’ять вертикальних наборів вище — це практичні припущення про найтиповіші B2B-сценарії; специфічна для клієнта термінологія (наприклад, shipping_plan) лишається без префікса.
Супервластивості
Пари ключ/значення на рівні сесії, які автоматично додаються до кожної вихідної події. На відміну від traits identify, що описують ідентичність, super-properties описують контекст сесії: активний варіант A/B, flavor збірки, увімкнені feature flags. Зберігаються між запусками; очищуються на reset(). Якщо ключі збігаються, значення properties у track для конкретної події завжди мають пріоритет.
import io.kixo.sdk.Kixo
Kixo.setSuperProperty("build_flavor", "beta")
Kixo.setSuperProperties(mapOf(
"ab_variant" to "B",
"referrer_campaign" to "autumn-launch",
))
// Sugar for A/B tracking — stored as 'experiment_<id>'.
Kixo.setExperimentVariant("checkout_v2", "variant_a")
Kixo.unsetSuperProperty("build_flavor")
Kixo.clearSuperProperties()Push-сповіщення
Є два шляхи інтеграції. Оберіть A, якщо ви використовуєте FCM і хочете найкоротше робоче налаштування; оберіть B, якщо у вас уже є власний FirebaseMessagingService, який не можна перебудувати, або якщо вам потрібен явний контроль над тим, які доставки FCM бачить Kixo.
Варіант A — успадкувати KixoFirebaseMessagingService (автовідстеження)
Успадкуйте KixoFirebaseMessagingService і викличте super.onMessageReceived(...) у своєму перевизначенні — Kixo автоматично надсилає push_received (видимий payload) або push_silent (лише data). Базовий клас також обробляє реєстрацію onNewToken, якщо ви її не перевизначаєте. Реєстрація AndroidManifest.xml не відрізняється від звичайного сервісу FCM.
import com.google.firebase.messaging.RemoteMessage
import io.kixo.sdk.KixoFirebaseMessagingService
class MyMessagingService : KixoFirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage) // Kixo auto-tracks push_received
// … your own routing / notification display
}
}Примітка
Kixo компілює цей необов’язковий клас із Firebase Messaging, але не підтягує Firebase у ваш застосунок транзитивно. SDK оголошує Firebase як compileOnly; якщо застосунок обирає цей варіант, він уже має залежати від firebase-messaging, як і будь-який FCM receiver.
Варіант B — викликати API вручну зі свого сервісу FCM
Зареєструйте свій токен FCM у Kixo через FirebaseMessagingService.onNewToken, а потім явно логируйте кожну доставку. Обирайте цей шлях, якщо хочете, щоб Kixo бачив лише частину доставок FCM. Наразі на Android підтримуються лише доставки через FCM.
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import io.kixo.sdk.Kixo
import io.kixo.sdk.PushProvider
class MyMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
Kixo.setPushToken(token, PushProvider.FCM)
}
override fun onMessageReceived(message: RemoteMessage) {
// Convert the FCM payload to a Map<String, Any?> and log it —
// Kixo correlates this with the open / dismiss it sees later.
Kixo.logPushReceived(message.data.toMap(), appState = "background")
}
}Android не надає універсального lifecycle hook для відкриття сповіщень, їх закриття чи натискань на кнопки дій. Передавайте ці сигнали з notification intent або receiver, які створює ваш застосунок:
import io.kixo.sdk.Kixo
Kixo.logPushOpened(payload = pushPayload) // open
Kixo.logPushOpened(payload = pushPayload, actionId = "reply") // action-button tap
Kixo.logPushDismissed(payload = pushPayload) // swipe-awayВідтворення сесій
Відтворюйте реальну візуальну картину того, що бачив користувач. Під час кожного запису SDK кодує стиснений кадр екрана (зображення JPEG) разом зі структурним знімком ієрархії елементів інтерфейсу та надсилає обидва — щоб програвач у дашборді міг показувати піксельно точне відтворення поруч із часовою шкалою взаємодій. Налаштуйте відтворення сесій для проєкту в Панель керування → Налаштування → Повтор сеансу. SDK автоматично зчитує та оновлює цю політику проєкту, зокрема маскування, режими запису й дозвіл на надсилання через мобільну мережу.
import io.kixo.sdk.Kixo
import io.kixo.sdk.KixoConfiguration
val config = KixoConfiguration.Builder(
projectId = "kx_proj_YOUR_PROJECT_ID",
apiKey = "kx_key_YOUR_API_KEY",
)
.build(applicationContext)
Kixo.configure(this, config)Якщо надсилання через мобільну мережу вимкнено, записані сесії в черзі чекатимуть на дозволену мережу.
Порада
Маскуйте перед надсиланням. Kixo записує пікселі, тому маскування застосовується до до того, як будь-які дані залишать пристрій. Поля пароля та e-mail визначаються автоматично й приховуються; текст у структурних знімках проходить через фільтр PII; а будь-який view, позначений через setKixoMask(true), перетворюється на непрозорий прямокутник у кадрі до кодуванням JPEG — його пікселі ніколи не залишають пристрій. Екрани Jetpack Compose за замовчуванням маскуються повністю (викличте setKixoMask(false) на зовнішньому ComposeView, щоб включити екран, який ви вже перевірили). У дашборді оператори переглядають запис поруч із часовою шкалою подій.
Збір даних
SDK збирає дані, увімкнені у вашому проєкті, а також події й властивості, які надсилає застосунок.
Налагодження
Kixo.diagnostics() повертає знімок стану SDK лише для читання — зручно для прихованого екрана налагодження або smoke-тесту. Дає змогу без debugger зрозуміти, чому події не надходять.
import io.kixo.sdk.Kixo
val diag = Kixo.diagnostics()
Log.d("Kixo", "queued=${diag.queue.bufferedEventCount}")
Log.d("Kixo", "paused=${diag.paused}") // collection paused state
Log.d("Kixo", "lifecycleState=${diag.lifecycleState}") // SDK lifecycle stateПримусово запустіть flush зі свого test harness — виклик блокується до timeoutMs на один мережевий round-trip:
import io.kixo.sdk.Kixo
// Async fire-and-forget — returns immediately.
Kixo.flush()
// Blocking variant for instrumentation tests. Never call on the main thread.
val landed: Boolean = Kixo.flushBlocking(timeoutMs = 5_000L)
assertTrue(landed)Compose Navigation
Маршрути Activity / Fragment одразу створюють події screen_view і структуровані записи screen_visit з метаданими про тривалість і переходи без додаткових налаштувань. Для Jetpack Compose Navigation викликайте Kixo.screen з LaunchedEffect, прив’язаного до маршруту, — тоді SDK бачитиме одну подію на кожен destination незалежно від кількості recomposition.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import io.kixo.sdk.Kixo
@Composable
fun AppNavHost(nav: NavHostController) {
NavHost(navController = nav, startDestination = "home") {
composable("home") {
LaunchedEffect("home") { Kixo.screen("HomeScreen") }
HomeScreen()
}
composable("settings") {
LaunchedEffect("settings") { Kixo.screen("SettingsScreen") }
SettingsScreen()
}
}
}AI-агенти для розробки
Публічний API SDK невеликий і добре пристосований до автодоповнення: усі методи зібрані в синглтоні Kixo, кожен приклад Kotlin у цьому посібнику починається з import io.kixo.sdk.Kixo, а в нашому README є блок "AI agent quick reference", який такі інструменти, як Claude Code, Cursor і Codex, можуть одразу вставити у свій контекст. Якщо ваш агент зайшов у глухий кут, почніть із цього канонічного варіанта:
// Tell your AI coding agent:
// "Integrate the Kixo Android SDK using io.kixo:kixo-android-sdk
// from https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo.
// Call Kixo.configure(this, projectId, apiKey) in Application.onCreate.
// Then use Kixo.track / Kixo.identify / Kixo.markGoal as needed."Примітка
Усі розділи вище написані з урахуванням цього сценарію: imports всюди вказані явно, типи завжди названі, а синглтон SDK ніколи не має псевдоніма. Передайте цю сторінку своєму агенту — і дайте йому довести інтеграцію до кінця.