Przejdź do dokumentacji

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:

kotlin
// 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:

kotlin
// 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.

kotlin
// :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.

kotlin
// :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 ApplicationonCreate 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".

kotlin
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:

kotlin
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.

kotlin
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.

kotlin
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.

kotlin
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.

kotlin
// 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.

KluczTypOpis
$emailciąg znakówGłówny adres e-mail, często używany jako klucz do spinania tożsamości.
$phoneciąg znakówNumer telefonu w formacie E.164.
$nameciąg znakówPełna nazwa wyświetlana.
$first_nameciąg znakówImię.
$last_nameciąg znakówNazwisko.
$avatar_urlciąg znakówPełny URL obrazu awatara użytkownika.

Geo

Kontekst geograficzny.

KluczTypOpis
$countryciąg znakówKod kraju zgodny ze standardem ISO 3166.
$cityciąg znakówNazwa miasta.
$regionciąg znakówStan lub prowincja.
$timezoneciąg znakówStrefa IANA, np. America/Los_Angeles.
$languageciąg znakówTag IETF, np. en lub ru-RU.
$localeciąg znakówPełny identyfikator ustawień regionalnych.

Cykl życia

Kiedy ostatnio go widzieliśmy.

KluczTypOpis
$createdISO8601Czas rejestracji lub utworzenia konta.
$last_seenISO8601Czas ostatniej interakcji.

Subskrypcja

Ustaw, jeśli Twój produkt ma plany.

KluczTypOpis
$planciąg znakówSlug poziomu — free, pro, enterprise.
$subscription_statusciąg znakówactive / trial / cancelled / past_due.
$trial_endsISO8601Koniec bieżącego okresu próbnego.
$mrrliczbaMiesięczny przychód powtarzalny w walucie konta.
$subscription_startedISO8601Początek bieżącej subskrypcji.

E-commerce

Ustaw, jeśli sprzedajesz produkty.

KluczTypOpis
$lifetime_ordersliczbaLiczba zrealizowanych zamówień.
$lifetime_revenueliczbaŁączne wydatki.
$aovliczbaŚrednia wartość zamówienia.
$last_purchaseISO8601Ostatni udany zakup.
$first_purchaseISO8601Pierwszy udany zakup.
$cart_abandoned_countliczbaŁączna liczba porzuconych koszyków.

Media

Ustaw, jeśli publikujesz treści.

KluczTypOpis
$content_tierciąg znakówfree / premium / paid.
$subscribed_categoriesCiąg CSV lub tablicaKategorie obserwowane przez użytkownika.
$watch_time_totalliczbaŁączny czas oglądania w sekundach.
$last_playedISO8601Ostatnie rozpoczęcie odtwarzania.

Marketplace

Ustaw, jeśli Twój produkt działa jako platforma dwustronna.

KluczTypOpis
$seller_tierciąg znakówSlug poziomu po stronie sprzedawcy.
$buyer_tierciąg znakówSlug poziomu po stronie kupującego.
$listings_countliczbaAktywne ogłoszenia użytkownika.
$reviews_countliczbaOpinie otrzymane przez użytkownika.
$verifiedwartość logicznaStatus KYC.

Lojalność

Ustaw, jeśli korzystasz z programów lojalnościowych lub nagród.

KluczTypOpis
$loyalty_pointsliczbaBieżące saldo punktów do wykorzystania.
$vip_levelciąg znakówSlug poziomu VIP.
$referral_countliczbaSkuteczne 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.

kotlin
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.

kotlin
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.

kotlin
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ę:

kotlin
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

Replay 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ą.

kotlin
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.

kotlin
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

Wymuś opróżnienie kolejki z harnessu testowego — wywołanie blokuje się maksymalnie na timeoutMs, czekając na zakończenie rundy sieciowej:

kotlin
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.

kotlin
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:

kotlin
// 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.