Android SDK

Drop-in support SDK for Android apps. Jetpack Compose, Activity launches, or headless API.

Android SDK

Drop-in support SDK for Android apps. Replace Zendesk with a few lines of code.

Requirements

  • Min SDK 24 (Android 7.0+)
  • Kotlin 2.0+
  • Jetpack Compose (BOM 2024.12.01+)
  • OkHttp 4.12
  • kotlinx-serialization

Installation

Add the Premex artifact repository and the dependency to your module-level build.gradle.kts:

API Reference

All public classes and their full import paths:

ClassImportDescription
PremexSupportse.premex.support.PremexSupportSingleton entry point — initialize, show UI, or access lower-level clients
PremexSupportConfigse.premex.support.PremexSupportConfigConfiguration data class (baseUrl, productSlug)
FormTypese.premex.support.model.FormTypeEnum of form types (see Form Types)
FormSubmissionse.premex.support.model.FormSubmissionSealed interface for typed programmatic form data
FormSubmission.Supportse.premex.support.model.FormSubmissionSupport request form data
FormSubmission.FeatureRequestse.premex.support.model.FormSubmissionFeature request form data
FormSubmission.BugReportse.premex.support.model.FormSubmissionBug report form data
PremexApiClientse.premex.support.api.PremexApiClientREST API client (OkHttp + Coroutines)
ApiResultse.premex.support.api.ApiResultSealed result type (Success / Error)
SseEventSourcese.premex.support.api.SseEventSourceReal-time SSE event stream as Flow<ConversationEvent>
CustomerIdentityManagerse.premex.support.identity.CustomerIdentityManagerEncrypted customer identity storage
ConversationEventse.premex.support.model.ConversationEventSealed class for real-time events (NewComment, StateUpdate, etc.)
ConversationSummaryse.premex.support.model.ConversationSummaryLightweight conversation list item
ConversationDetailse.premex.support.model.ConversationDetailFull conversation with messages
PremexChatScreense.premex.support.ui.chat.PremexChatScreenCompose chat screen
PremexFormScreense.premex.support.ui.form.PremexFormScreenCompose form screen
PremexSupportThemese.premex.support.ui.theme.PremexSupportThemeMaterial 3 theme wrapper

Initialization

Call PremexSupport.initialize() once, as early as possible — typically in Application.onCreate() or your main Activity:

kotlin
import se.premex.support.PremexSupport
import se.premex.support.PremexSupportConfig

// Application.kt
PremexSupport.initialize(
    context = applicationContext,
    config = PremexSupportConfig(
        baseUrl = "https://support.premex.se",
        productSlug = "your-product-slug",
    ),
)

Jetpack Compose Integration (Recommended)

Embed the SDK's composables directly in your Compose navigation graph for the most seamless experience.

kotlin
import se.premex.support.ui.chat.PremexChatScreen
import se.premex.support.ui.form.PremexFormScreen
import se.premex.support.model.FormType

// Chat screen
PremexChatScreen(
    modifier = Modifier.fillMaxSize(),
    onNavigateBack = { navController.popBackStack() },
)

// Form screen
PremexFormScreen(
    formType = FormType.BUG_REPORT,
    modifier = Modifier.fillMaxSize(),
    onNavigateBack = { navController.popBackStack() },
    onSubmitted = { navController.popBackStack() },
)

A full NavHost example with chat and form routes:

kotlin
import se.premex.support.ui.chat.PremexChatScreen
import se.premex.support.ui.form.PremexFormScreen
import se.premex.support.model.FormType

NavHost(navController, startDestination = "home") {
    composable("home") {
        HomeScreen(
            onOpenChat = { navController.navigate("chat") },
            onOpenBugReport = { navController.navigate("form/bug_report") },
            onOpenFeatureRequest = { navController.navigate("form/feature_request") },
            onOpenSupport = { navController.navigate("form/support") },
        )
    }
    composable("chat") {
        PremexChatScreen(
            modifier = Modifier.fillMaxSize(),
            onNavigateBack = { navController.popBackStack() },
        )
    }
    composable("form/{formType}") { backStackEntry ->
        val formType = FormType.valueOf(
            backStackEntry.arguments?.getString("formType")
                ?.uppercase() ?: "SUPPORT",
        )
        PremexFormScreen(
            formType = formType,
            modifier = Modifier.fillMaxSize(),
            onNavigateBack = { navController.popBackStack() },
            onSubmitted = { navController.popBackStack() },
        )
    }
}

Wrap in PremexSupportTheme for the SDK's default Material 3 styling, or use your own MaterialTheme to customise colours, typography, and shapes.

Activity Integration (Quick Start)

For apps that don't use Compose navigation, launch the SDK's built-in activities directly:

kotlin
import se.premex.support.PremexSupport
import se.premex.support.model.FormType

// Launch chat
PremexSupport.showChat(context)

// Launch form — formType defaults to FormType.SUPPORT when omitted
PremexSupport.showForm(context)
PremexSupport.showForm(context, FormType.SUPPORT)
PremexSupport.showForm(context, FormType.FEATURE_REQUEST)
PremexSupport.showForm(context, FormType.BUG_REPORT)

Method signature:

kotlin
fun showForm(context: Context, formType: FormType = FormType.SUPPORT)
ParameterTypeDefaultDescription
contextContextAndroid context used to start the Activity
formTypeFormTypeFormType.SUPPORTWhich form to display

Form Types

The FormType enum (se.premex.support.model.FormType) determines which fields are presented to the user. Each value has a displayName property used as the form heading.

ValuedisplayNameUse caseFields
FormType.SUPPORT"Support Request"General help requests and questionsSubject, Message
FormType.FEATURE_REQUEST"Feature Request"Suggest new features or improvementsTitle, Use Case, Proposed Solution (optional), Priority
FormType.BUG_REPORT"Bug Report"Report defects with reproduction stepsTitle, Steps to Reproduce, Expected Behavior, Actual Behavior, Environment (optional)

Programmatic Form Submission

Submit forms without showing any UI. The SDK builds the same structured markdown body as the built-in form screens and sends it via the REST API.

Each form type has a dedicated data class with named, typed properties — no string keys to remember.

kotlin
import se.premex.support.PremexSupport
import se.premex.support.model.FormSubmission
import se.premex.support.api.ApiResult

// All submitForm() calls are suspend functions — call from a coroutine scope
lifecycleScope.launch {
    // Support request
    val result = PremexSupport.submitForm(
        FormSubmission.Support(
            name = "Jane Doe",
            email = "jane@example.com",
            subject = "Login not working",
            message = "I cannot log in after resetting my password.",
        ),
    )
    when (result) {
        is ApiResult.Success -> Log.d("Support", "Created: ${result.data.conversationId}")
        is ApiResult.Error -> Log.e("Support", "Error: ${result.message}")
    }

    // Feature request
    PremexSupport.submitForm(
        FormSubmission.FeatureRequest(
            name = "Jane Doe",
            email = "jane@example.com",
            featureTitle = "Dark mode",
            useCase = "The app is too bright at night.",
            proposedSolution = "Add a toggle in Settings.",  // optional
            priority = "Important",                          // optional, defaults to "Nice to have"
        ),
    )

    // Bug report
    PremexSupport.submitForm(
        FormSubmission.BugReport(
            name = "Jane Doe",
            email = "jane@example.com",
            bugTitle = "Login button unresponsive",
            stepsToReproduce = "1. Go to login\n2. Click Login",
            expectedBehavior = "Should log in.",
            actualBehavior = "Nothing happens.",
            environment = "Pixel 8, Android 15",  // optional
        ),
    )
}

You can also use the lower-level PremexApiClient.submitForm() directly if you need to supply a custom customerId:

kotlin
import se.premex.support.PremexSupport
import se.premex.support.model.FormSubmission

lifecycleScope.launch {
    val client = PremexSupport.apiClient
    client.submitForm(
        customerId = "cust_custom-id",
        form = FormSubmission.Support(
            name = "Jane",
            email = "jane@example.com",
            subject = "Help",
            message = "Details here.",
        ),
    )
}

Headless API

Build a fully custom UI on top of the SDK's networking and identity layers:

kotlin
import se.premex.support.PremexSupport
import se.premex.support.model.ConversationEvent

val client = PremexSupport.apiClient
val customerId = PremexSupport.identityManager.customerId

// List conversations
val result = client.listConversations(customerId)

// Create conversation (raw, without form structure)
val created = client.createConversation(
    customerId = customerId,
    subject = "Need help",
    message = "I can't find the settings page",
)

// Real-time events
PremexSupport.sseEventSource
    .observeEvents(conversationId, customerId)
    .collect { event ->
        when (event) {
            is ConversationEvent.NewComment -> { /* new message */ }
            is ConversationEvent.StateUpdate -> { /* status changed */ }
            else -> { /* other events */ }
        }
    }

The observeEvents function returns a Flow<ConversationEvent> backed by an SSE connection. It reconnects automatically on network failures.

Theming

PremexSupportTheme provides Material 3 defaults with full light/dark mode support. To match your app's brand, wrap the SDK composables in your own MaterialTheme:

kotlin
MaterialTheme(
    colorScheme = YourColorScheme,
) {
    PremexChatScreen(...)
}

The SDK reads colours, typography, and shapes from the nearest MaterialTheme in the composition tree, so no additional configuration is required.

Customer Identity

  • A unique cust_<UUID> identifier is auto-generated on first use.
  • Stored in encrypted SharedPreferences (AndroidX Security).
  • Persists across app sessions and app updates.
  • Clear it manually when needed: PremexSupport.identityManager.clear()

Migration from Zendesk

Switching from the Zendesk SDK is straightforward. The API surface maps almost one-to-one:

ZendeskPremex Support
Zendesk.initialize(...)PremexSupport.initialize(...)
MessagingActivity.show(...)PremexSupport.showChat(context)
RequestActivity.show(...)PremexSupport.showForm(context)

Architecture

The SDK is organised in layers, each of which can be used independently:

  • se.premex.support.PremexSupport — Singleton entry point. Owns the lifecycle of all other components.
  • se.premex.support.api.PremexApiClient — REST API client built on OkHttp + Kotlin Coroutines.
  • se.premex.support.api.SseEventSource — Real-time event stream that converts SSE into a Flow<ConversationEvent>.
  • se.premex.support.identity.CustomerIdentityManager — Encrypted identity storage backed by AndroidX Security.
  • se.premex.support.model.* — Data models: FormType, FormSubmission, ConversationEvent, ConversationSummary, ConversationDetail.
  • se.premex.support.ui.* — Compose UI: PremexChatScreen, PremexFormScreen, PremexSupportTheme, and supporting composables.