Android SDK
Kixo Android SDK obsługuje Kotlin 2.0+ i Java, wymaga minSdk 24 (Android 7.0) i jest kompilowany względem compileSdk 35. Aplikacja hosta nadal odpowiada za własne targetSdk. Jedno wywołanie Kixo.configure w klasie Application.onCreate wystarczy, aby automatycznie śledzić ekrany, stuknięcia, sesje, awarie i zdarzenia cyklu życia. Śledzenie push wymaga mostka FCM opisanego niżej. Automatyczne śledzenie żądań sieciowych nie jest częścią bieżącego wydania na Android. SDK obsługuje też odtwarzanie sesji, tożsamość i cele.
Szybki start
Trzy pliki. Dodaj repozytorium Maven, dodaj zależność, a potem wstaw dwie linie do klasy dziedziczącej po Application.
Wymagania kompilacyjne: compileSdk 35, minSdk 24, Kotlin 2.0+ albo Java oraz bytecode 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")
}
}
}Uwaga
To cała integracja analityki. Standardowe mechanizmy automatycznego śledzenia są domyślnie włączone; push nadal wymaga mostka FCM opisanego niżej. Poszczególne flagi nadpisuj przez KixoConfiguration.Builder(...) tylko wtedy, gdy jest to potrzebne.
Dodaj do aplikacji
Repozytorium Maven dla Kixo jest hostowane w GitHub Pages. Dodaj je obok google() i mavenCentral() w 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")
}
}
}Następnie zadeklaruj zależność w module aplikacji:
// app/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20")
}Wskazówka
android.permission.INTERNET i android.permission.ACCESS_NETWORK_STATE są już uwzględnione w manifeście SDK. Uprawnienia do powiadomień pozostają po stronie aplikacji i deklarujesz je dopiero wtedy, gdy włączasz funkcje push.
Projekty wielomodułowe
Konfiguracja implementation w Gradle jest nieprzechodnia: zadeklarowanie implementation("io.kixo:kixo-android-sdk:0.1.20") w module bibliotecznym (np. :core_domain) NIE udostępnia Kixo modułowi :app ani żadnemu innemu odbiorcy. Działają dwa podejścia — wybierz jedno.
Wzorzec A — każdy moduł, który wywołuje Kixo, deklaruje tę zależność samodzielnie (zalecane). utrzymuje minimalny classpath każdego modułu i zapobiega kaskadowym przebudowom. Użyj katalogu wersji (libs.kixo.sdk), aby numer wersji zmieniać w jednym miejscu.
// :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
}Wzorzec B — reeksport przez api(...). Jedna deklaracja, ale publiczne ABI modułu bibliotecznego zaczyna zawierać typy Kixo — każda zmiana wersji wymusza przebudowę wszystkich modułów zależnych. Używaj tego tylko wtedy, gdy biblioteka wykorzystuje typy Kixo we własnych publicznych sygnaturach, na przykład zwraca KixoDiagnostics z funkcji.
// :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
}Ostrzeżenie
Jeśli podczas kompilacji w module pojawia się Unresolved reference: Kixo, temu modułowi brakuje własnej zależności od SDK — dodaj powyższą linię implementation albo użyj wzorca B.
Inicjalizacja
Skonfiguruj Kixo w klasie dziedziczącej po Application — onCreate uruchamia się przed każdą aktywnością, więc każde wyświetlenie ekranu, stuknięcie i zdarzenie cyklu życia jest rejestrowane od pierwszej klatki. Zarejestruj Application w manifeście przez 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",
)
}
}Jeśli potrzebujesz bardziej szczegółowej konfiguracji — flag automatycznego śledzenia, częstotliwości opróżniania kolejki, próbkowania odtwarzania czy własnego hosta API — utwórz KixoConfiguration jawnie:
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)Uwaga
Idempotentne. Drugie wywołanie configure w tym samym procesie jest ignorowane i zapisuje wpis WARN — SDK zachowuje pierwszą konfigurację. Zdarzenia zakolejkowane przez singleton uwierzytelniania po przed, zanim configure dojdzie do skutku, są buforowane (limit 50) i odtwarzane po podłączeniu SDK, więc możesz wywoływać Kixo.identify(...) z kontekstu globalnego jeszcze przed zakończeniem Application.onCreate.
Śledzenie zdarzeń
Większość instrumentacji opiera się na trzech prymitywach: track do zdarzeń, markGoal do sygnałów konwersji i addBreadcrumb do kontekstu niezwiązanego z pojedynczym zdarzeniem.
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",
)Wskazówka
Cele mają poziomy ważności. Oznaczone cele zasilają lejki aktywacji w Kixo oraz codzienne zadanie cron wykrywające zmiany — jeśli wolumen celu spadnie tydzień do tygodnia o 70%, w panelu pojawi się przy nim oznaczenie Wymaga sprawdzenia. Używaj markGoal dla kilku momentów, które naprawdę mają znaczenie, a track dla całej reszty.
Zdarzenia standardowe
Wygodna nakładka na Kixo.track dla zdarzeń, które Kixo rozpoznaje po nazwie — dosłowne klucze tekstowe dopasowywane przez backendowy mechanizm wykrywania zdarzeń standardowych. Daje walidację kształtu właściwości w czasie kompilacji i jedno źródło prawdy dla nazewnictwa.
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)Identyfikuj użytkowników
Powiąż kolejne zdarzenia ze stałym identyfikatorem użytkownika i zestawem atrybutów. Połączenie aktywności anonimowej i rozpoznanej następuje w Kixo — zdarzenia zarejestrowane przed identify zostaną wstecznie przypisane do tego samego użytkownika.
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()⚠️ Pułapka znaku dolara w Kotlinie. Standardowe klucze tożsamości mają prefiks $ ($email, $name, $first_name) — a w literałach Kotlin musi znak dolara trzeba zapisać jako "\$email". Zapis "$email" interpoluje wartość zmiennej email, więc trafia ona po cichu jako atrybut własne i nigdy nie wypełnia kolumn e-mail / imię w Audience. Najprostsze rozwiązanie: użyj typowanego przeciążenia (SDK 0.1.13+), którego nie da się pomylić: Kixo.setUserProperty(StandardProperty.EMAIL, email).
Oznacz użytkownika na potrzeby segmentacji
Użyj setUserProperty z wartością wartość logiczna, aby przypisać użytkownikowi prostą flagę tak/nie. Flaga pozostaje między uruchomieniami i zasila segmenty, kampanie e-mail oraz zapytania w czacie — bez żadnej dodatkowej konfiguracji poza wywołaniem 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",
))Właściwości są zapisywane przez SharedPreferences, pozostają między uruchomieniami i automatycznie trafiają do każdego wysyłanego zdarzenia. W czacie możesz napisać np. "wyślij powitalny e-mail do użytkowników, gdzie subscribe ma wartość true" — Kixo zbuduje segment i przygotuje szkic szablonu za Ciebie. Są czyszczone przy Kixo.reset().
Katalog standardowych właściwości
Zarezerwowane klucze właściwości mają prefiks $, więc nie kolidują z własnymi cechami. Katalog Kixo obejmuje 37 kluczy w 3 uniwersalnych pakietach (tożsamość, geo, cykl życia) oraz 5 pakietach wertykalnych B2B (subskrypcja, e-commerce, media, marketplace, lojalność). Ustaw tylko te, które pasują do Twojego produktu — dashboard dostosuje się i pokaże wyłącznie uzupełnione pakiety.
Tożsamość
Zawsze istotne. Ustawia kolumny nagłówka profilu.
| Klucz | Typ | Opis |
|---|---|---|
$email | ciąg znaków | Główny adres e-mail, często używany jako klucz do spinania tożsamości. |
$phone | ciąg znaków | Numer telefonu w formacie E.164. |
$name | ciąg znaków | Pełna nazwa wyświetlana. |
$first_name | ciąg znaków | Imię. |
$last_name | ciąg znaków | Nazwisko. |
$avatar_url | ciąg znaków | Pełny URL obrazu awatara użytkownika. |
Geo
Kontekst geograficzny.
| Klucz | Typ | Opis |
|---|---|---|
$country | ciąg znaków | Kod kraju zgodny ze standardem ISO 3166. |
$city | ciąg znaków | Nazwa miasta. |
$region | ciąg znaków | Stan lub prowincja. |
$timezone | ciąg znaków | Strefa IANA, np. America/Los_Angeles. |
$language | ciąg znaków | Tag IETF, np. en lub ru-RU. |
$locale | ciąg znaków | Pełny identyfikator ustawień regionalnych. |
Cykl życia
Kiedy ostatnio go widzieliśmy.
| Klucz | Typ | Opis |
|---|---|---|
$created | ISO8601 | Czas rejestracji lub utworzenia konta. |
$last_seen | ISO8601 | Czas ostatniej interakcji. |
Subskrypcja
Ustaw, jeśli Twój produkt ma plany.
| Klucz | Typ | Opis |
|---|---|---|
$plan | ciąg znaków | Slug poziomu — free, pro, enterprise. |
$subscription_status | ciąg znaków | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | Koniec bieżącego okresu próbnego. |
$mrr | liczba | Miesięczny przychód powtarzalny w walucie konta. |
$subscription_started | ISO8601 | Początek bieżącej subskrypcji. |
E-commerce
Ustaw, jeśli sprzedajesz produkty.
| Klucz | Typ | Opis |
|---|---|---|
$lifetime_orders | liczba | Liczba zrealizowanych zamówień. |
$lifetime_revenue | liczba | Łączne wydatki. |
$aov | liczba | Średnia wartość zamówienia. |
$last_purchase | ISO8601 | Ostatni udany zakup. |
$first_purchase | ISO8601 | Pierwszy udany zakup. |
$cart_abandoned_count | liczba | Łączna liczba porzuconych koszyków. |
Media
Ustaw, jeśli publikujesz treści.
| Klucz | Typ | Opis |
|---|---|---|
$content_tier | ciąg znaków | free / premium / paid. |
$subscribed_categories | Ciąg CSV lub tablica | Kategorie obserwowane przez użytkownika. |
$watch_time_total | liczba | Łączny czas oglądania w sekundach. |
$last_played | ISO8601 | Ostatnie rozpoczęcie odtwarzania. |
Marketplace
Ustaw, jeśli Twój produkt działa jako platforma dwustronna.
| Klucz | Typ | Opis |
|---|---|---|
$seller_tier | ciąg znaków | Slug poziomu po stronie sprzedawcy. |
$buyer_tier | ciąg znaków | Slug poziomu po stronie kupującego. |
$listings_count | liczba | Aktywne ogłoszenia użytkownika. |
$reviews_count | liczba | Opinie otrzymane przez użytkownika. |
$verified | wartość logiczna | Status KYC. |
Lojalność
Ustaw, jeśli korzystasz z programów lojalnościowych lub nagród.
| Klucz | Typ | Opis |
|---|---|---|
$loyalty_points | liczba | Bieżące saldo punktów do wykorzystania. |
$vip_level | ciąg znaków | Slug poziomu VIP. |
$referral_count | liczba | Skuteczne polecenia przypisane do tego użytkownika. |
Wskazówka
Nie widzisz tu swojego wzorca? Dla cech niestandardowych używaj zwykłych kluczy. Pojawią się w panelu Custom Traits w Dashboard, bez zaśmiecania kolumn profilu. Pięć pakietów branżowych powyżej to celowe propozycje najczęstszych struktur B2B — terminologia specyficzna dla klienta, np. shipping_plan, pozostaje bez prefiksu.
Super-properties
Pary klucz-wartość przypisane do sesji, automatycznie dołączane do każdego wysyłanego zdarzenia. To coś innego niż atrybuty identify, które opisują tożsamość; super-properties opisują kontekst sesji — aktywny wariant A/B, wariant kompilacji czy włączone flagi funkcji. Są zachowywane między uruchomieniami i czyszczone przy reset(). Przy konflikcie zawsze wygrywają właściwości ustawione dla pojedynczego zdarzenia przez properties w 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()Powiadomienia push
Masz dwie ścieżki integracji. Wybierz A, jeśli korzystasz z FCM i chcesz najszybszej działającej konfiguracji; wybierz B, jeśli masz już własny FirebaseMessagingService, którego nie możesz przebudować, albo chcesz jawnie kontrolować, które dostarczenia FCM widzi Kixo.
Opcja A — rozszerz KixoFirebaseMessagingService (automatyczne śledzenie)
Utwórz klasę dziedziczącą po KixoFirebaseMessagingService i wywołaj super.onMessageReceived(...) w swoim override — Kixo automatycznie emituje push_received (widoczny payload) albo push_silent (tylko dane). Klasa bazowa obsługuje też rejestrację onNewToken, jeśli jej nie nadpiszesz. Rejestracja AndroidManifest.xml pozostaje bez zmian względem zwykłego serwisu 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
}
}Uwaga
Kixo kompiluje tę opcjonalną klasę z Firebase Messaging, ale nie dodaje Firebase do aplikacji jako zależności przechodniej. W SDK Firebase jest zadeklarowane jako compileOnly; jeśli wybierasz tę opcję, aplikacja musi już zależeć od firebase-messaging, tak jak każdy receiver FCM.
Opcja B — wywołuj ręczne API z własnego serwisu FCM
Zarejestruj token FCM w Kixo przez FirebaseMessagingService.onNewToken, a następnie jawnie zapisuj każde dostarczenie. Wybierz tę ścieżkę, jeśli chcesz, aby Kixo widziało tylko część dostarczeń FCM. Na Android obecnie obsługiwane są wyłącznie dostarczenia 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 nie udostępnia uniwersalnego punktu zaczepienia cyklu życia dla otwarć, odrzuceń ani przycisków akcji powiadomień. Przekaż te sygnały z intentów lub receiverów powiadomień tworzonych przez aplikację:
import io.kixo.sdk.Kixo
Kixo.logPushOpened(payload = pushPayload) // open
Kixo.logPushOpened(payload = pushPayload, actionId = "reply") // action-button tap
Kixo.logPushDismissed(payload = pushPayload) // swipe-awayReplay sesji
Odtwórz rzeczywistą, wizualną rekonstrukcję tego, co widział użytkownik. Przy każdym przechwyceniu SDK koduje skompresowaną klatkę ekranu (obraz JPEG) razem ze strukturalną migawką hierarchii widoków i wysyła oba elementy — dzięki temu odtwarzacz w panelu może pokazać odtworzenie zgodne co do piksela wraz z osią czasu interakcji. Odtwarzanie dla projektu skonfigurujesz w Dashboard → Ustawienia → Odtwarzanie sesji. SDK automatycznie odczytuje i odświeża tę politykę projektu, w tym zasady maskowania, tryby przechwytywania i zgodę na wysyłanie przez sieć komórkową.
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)Gdy wysyłanie przez sieć komórkową jest wyłączone, zakolejkowane odtwarzanie czeka na dozwolone połączenie.
Wskazówka
Maskowanie przed wysłaniem. Kixo przechwytuje piksele, więc maskowanie działa przed, zanim cokolwiek opuści urządzenie. Pola hasła i adresu e-mail są wykrywane automatycznie i redagowane; tekst w migawkach strukturalnych przechodzi przez filtr PII; a każdy widok oznaczony przez setKixoMask(true) jest rasteryzowany do nieprzezroczystego prostokąta w klatce przed, zanim obraz JPEG zostanie zakodowany — jego piksele nigdy nie opuszczają urządzenia. Ekrany Jetpack Compose są domyślnie maskowane w całości (wywołaj setKixoMask(false) na najbardziej zewnętrznym ComposeView, aby uwzględnić ekran, który został już sprawdzony). W panelu analitycznym odtwarzacz sesji jest wyświetlany obok osi czasu zdarzeń.
Zbieranie danych
SDK zbiera dane włączone w projekcie oraz zdarzenia i właściwości wysyłane przez aplikację.
Debugowanie
Kixo.diagnostics() zwraca migawkę stanu SDK tylko do odczytu — przydatną na ukrytym ekranie debugowym albo w smoke teście. Pozwala odpowiedzieć na pytanie „dlaczego moje zdarzenia nie płyną?” bez użycia debuggera.
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 stateWymuś opróżnienie kolejki z harnessu testowego — wywołanie blokuje się maksymalnie na timeoutMs, czekając na zakończenie rundy sieciowej:
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
Trasy Activity / Fragment od razu generują zdarzenia screen_viewevents oraz ustrukturyzowane rekordy screen_visit z metadanymi czasu spędzonego na ekranie i przepływu. W przypadku Jetpack Compose Navigation wywołuj Kixo.screen z LaunchedEffect powiązanego z trasą — wtedy SDK zobaczy jedno zdarzenie na każdy ekran docelowy, niezależnie od liczby rekompozycji.
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()
}
}
}Agenci AI do programowania
Publiczne API SDK jest niewielkie i zaprojektowane pod autouzupełnianie kodu — każda metoda znajduje się na singletonie Kixo, każdy przykład w Kotlinie w tym przewodniku zaczyna się od import io.kixo.sdk.Kixo, a nasze README zawiera blok „AI agent quick reference”, który narzędzia takie jak Claude Code, Cursor i Codex mogą wkleić bezpośrednio do swojego kontekstu. Jeśli agent utknie, zacznij od tego wzorca:
// 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."Uwaga
Każda sekcja powyżej została napisana z myślą o tym sposobie pracy — importy są zawsze jawne, typy zawsze nazwane, a singleton SDK nigdy nie ma aliasu. Przekaż tę stronę agentowi i pozwól mu poprowadzić dalsze kroki.