> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Kotlin Quickstart

> Install the Dynamic Kotlin SDK on Android with AARs, initialize it in Compose, and sign users in with the built-in UI.

> [!TIP]
>
> **📱 Complete Example App**: For a fully functional Android app demonstrating all SDK
> features, check out our [Android SDK Example App](https://github.com/dynamic-labs-oss/android-sdk-and-sample-app/tree/main/ExampleApp/DynamicSDKExample). It
> includes authentication flows (email/SMS OTP, social login, passkeys), wallet management, EVM, Solana,
> Bitcoin, TON, and SUI transactions, MFA, and passkey examples with Jetpack Compose.

> [tab] Agent-friendly
>
> > [!TIP]
> >
> > Add the Dynamic docs MCP to your AI editor first: your agent can then query the docs directly. Instructions are on the [Welcome page](https://docs.dynamic.xyz/docs/get-started/welcome.md).
>
> Copy this prompt into your LLM (e.g. Claude, ChatGPT, Cursor) to implement Dynamic in your Android app with Kotlin.
>
> ````markdown theme={"system"}
> # Kotlin SDK Quickstart
>
> ## Purpose and Usage
>
> This document provides structured quickstart information for the Dynamic Kotlin SDK (Android). It is designed to be consumed by LLMs to generate accurate installation commands and code examples based on user requirements.
>
> > **Important scope note:** The Dynamic Kotlin SDK is for **Android native apps** using Jetpack Compose. It provides embedded wallets, authentication (email OTP, SMS OTP, social login, passkeys), and multi-chain support. This quickstart covers EVM and Solana; the SDK also exposes Bitcoin, TON, and SUI modules. It uses AAR files, and there is no Maven Central publication yet.
>
> ---
>
> ## How to use this document
>
> Start by asking the user which path they want:
>
> > "Would you like a **Quick start** (EVM only, Jetpack Compose, zero configuration; recommended if you're just getting started) or a **Custom setup** (choose your chains and configuration)?"
>
> - If the user chooses **Quick start**: follow the Quick Start Path section exactly. Do not ask any configuration questions; execute the happy path as written.
> - If the user chooses **Custom setup**: follow the Custom Setup Path section and ask all configuration questions before proceeding.
>
> ---
>
> ## Quick Start Path
>
> > Use this path when the user chooses Quick start. Execute every step in order. Do not skip steps. Do not ask configuration questions.
>
> **Stack:** Kotlin + Jetpack Compose + EVM only
>
> ### Step 1: Prerequisites
>
> Tell the user:
> - Android SDK 28+ (Android 9.0+) is required
> - Kotlin 2.1.0+ is required
> - Gradle 8.x+ is required
> - Java 17 is required
> - A Dynamic environment ID is required: get it at https://console.dynamic.xyz/dashboard/overview
>
> Ask the user for their environment ID before proceeding.
>
> ### Step 2: Download AAR files
>
> Download the latest AAR files from https://github.com/dynamic-labs-oss/android-sdk-and-sample-app:
>
> - `dynamic-sdk-android.aar` (required)
>
> Place it in `app/libs/`.
>
> ### Step 3: Add dependencies
>
> Add to `build.gradle.kts`:
>
> ```kotlin
> dependencies {
>     // Dynamic SDK AAR
>     implementation(files("libs/dynamic-sdk-android.aar"))
>
>     // Required transitive dependencies
>     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
>     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
>     implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
>     implementation("androidx.webkit:webkit:1.8.0")
>     implementation("com.squareup.okhttp3:okhttp:4.12.0")
>     implementation("androidx.browser:browser:1.7.0")
>     implementation("androidx.datastore:datastore-preferences:1.1.1")
>     implementation("com.google.crypto.tink:tink-android:1.15.0")
>     implementation("androidx.credentials:credentials:1.2.2")
>     implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
>     implementation("com.google.android.gms:play-services-auth:20.7.0")
>     implementation(platform("androidx.compose:compose-bom:2024.09.00"))
>     implementation("androidx.compose.ui:ui")
>     implementation("androidx.compose.foundation:foundation")
>     implementation("androidx.compose.runtime:runtime")
>     implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
>
>     // Used by the code in this quickstart
>     implementation("androidx.activity:activity-compose:1.8.1")
>     implementation("androidx.compose.material3:material3")
>     implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
> }
> ```
>
> ### Step 4: Configure AndroidManifest.xml
>
> ```xml
> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
>     <uses-permission android:name="android.permission.INTERNET" />
>     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
>
>     <application android:usesCleartextTraffic="true" ...>
>         <activity
>             android:name=".MainActivity"
>             android:exported="true"
>             android:launchMode="singleTask">
>             <intent-filter>
>                 <action android:name="android.intent.action.MAIN" />
>                 <category android:name="android.intent.category.LAUNCHER" />
>             </intent-filter>
>         </activity>
>
>         <!-- OAuth Callback Activity (Required) -->
>         <activity
>             android:name="com.dynamic.sdk.android.Auth.AuthCallbackActivity"
>             android:exported="true"
>             android:launchMode="singleTop"
>             android:noHistory="true"
>             android:theme="@android:style/Theme.Translucent.NoTitleBar">
>             <intent-filter>
>                 <action android:name="android.intent.action.VIEW" />
>                 <category android:name="android.intent.category.DEFAULT" />
>                 <category android:name="android.intent.category.BROWSABLE" />
>                 <data android:scheme="yourappscheme" />
>             </intent-filter>
>         </activity>
>     </application>
> </manifest>
> ```
>
> > The `android:scheme` must match the `redirectUrl` in `ClientProps`. For example, if `redirectUrl = "myapp://"`, use `android:scheme="myapp"`.
>
> ### Step 5: Initialize the SDK
>
> ```kotlin
> import android.os.Bundle
> import androidx.activity.ComponentActivity
> import androidx.activity.compose.setContent
> import androidx.compose.foundation.layout.*
> import androidx.compose.material3.*
> import androidx.compose.ui.Modifier
> import com.dynamic.sdk.android.DynamicSDK
> import com.dynamic.sdk.android.UI.DynamicUI
> import com.dynamic.sdk.android.core.ClientProps
> import com.dynamic.sdk.android.core.LoggerLevel
>
> class MainActivity : ComponentActivity() {
>     override fun onCreate(savedInstanceState: Bundle?) {
>         super.onCreate(savedInstanceState)
>
>         val props = ClientProps(
>             environmentId = "your-environment-id",
>             appLogoUrl = "https://your-app.com/logo.png",
>             appName = "Your App Name",
>             redirectUrl = "yourappscheme://",
>             appOrigin = "https://your-app.com",
>             logLevel = LoggerLevel.DEBUG
>         )
>         DynamicSDK.initialize(props, applicationContext, this)
>
>         setContent {
>             MaterialTheme {
>                 Surface(
>                     modifier = Modifier.fillMaxSize(),
>                     color = MaterialTheme.colorScheme.background
>                 ) {
>                     Box(modifier = Modifier.fillMaxSize()) {
>                         AppContent()
>                         DynamicUI() // Required overlay for auth flows
>                     }
>                 }
>             }
>         }
>     }
> }
> ```
>
> ### Step 6: Show the auth UI
>
> ```kotlin
> import androidx.compose.material3.*
> import androidx.compose.runtime.*
> import com.dynamic.sdk.android.DynamicSDK
>
> @Composable
> fun LoginScreen() {
>     val sdk = DynamicSDK.getInstance()
>     Button(onClick = { sdk.ui.showAuth() }) {
>         Text("Sign In")
>     }
> }
> ```
>
> ### Step 7: Listen for auth state changes
>
> ```kotlin
> import androidx.lifecycle.ViewModel
> import androidx.lifecycle.viewModelScope
> import com.dynamic.sdk.android.DynamicSDK
> import com.dynamic.sdk.android.Models.UserProfile
> import kotlinx.coroutines.flow.MutableStateFlow
> import kotlinx.coroutines.flow.StateFlow
> import kotlinx.coroutines.launch
>
> class AuthViewModel : ViewModel() {
>     private val sdk = DynamicSDK.getInstance()
>
>     private val _user = MutableStateFlow<UserProfile?>(null)
>     val user: StateFlow<UserProfile?> = _user
>
>     private val _isAuthenticated = MutableStateFlow(false)
>     val isAuthenticated: StateFlow<Boolean> = _isAuthenticated
>
>     init {
>         _isAuthenticated.value = sdk.auth.authenticatedUser != null
>         _user.value = sdk.auth.authenticatedUser
>
>         viewModelScope.launch {
>             sdk.auth.authenticatedUserChanges.collect { user ->
>                 _user.value = user
>                 _isAuthenticated.value = user != null
>             }
>         }
>     }
> }
> ```
>
> ### Step 8: Enable features in console
>
> Tell the user:
> 1. Go to https://console.dynamic.xyz/dashboard/overview
> 2. Go to **Authentication** and enable Email OTP
> 3. Go to **Wallets** and enable embedded wallets
> 4. Go to **Chains** and enable an EVM testnet (e.g. Base Sepolia)
>
> ---
>
> ## Custom Setup Path
>
> > Use this path when the user chooses Custom setup. Ask ALL questions below before generating any code.
>
> **Questions to ask the user:**
> 1. Which chains do you need? (EVM / Solana / Bitcoin / TON / SUI)
> 2. What is your app's URL scheme for OAuth callbacks? (e.g. `myapp://`)
> 3. What authentication methods do you want? (Email OTP, SMS OTP, Social login, Passkeys)
> 4. Do you need WalletConnect support for connecting to dApps?
>
> ### Configuration differences
>
> **Solana support:** Add these extra dependencies:
>
> ```kotlin
> implementation(files("libs/solana-web3.aar"))
> implementation("org.sol4k:sol4k:0.6.0")
> ```
>
> **WalletConnect support:** Add `reownProjectId` to `ClientProps`:
>
> ```kotlin
> val props = ClientProps(
>     environmentId = "your-environment-id",
>     appLogoUrl = "https://your-app.com/logo.png",
>     appName = "Your App Name",
>     redirectUrl = "yourappscheme://",
>     appOrigin = "https://your-app.com",
>     reownProjectId = "your-reown-project-id"
> )
> ```
>
> ### SDK Access (after initialization)
>
> ```kotlin
> val sdk = DynamicSDK.getInstance()
>
> // Auth
> sdk.ui.showAuth()
> sdk.auth.authenticatedUser
> sdk.auth.authenticatedUserChanges
>
> // Wallets
> sdk.wallets.userWallets
> sdk.wallets.primary
>
> // User profile
> sdk.ui.showUserProfile()
>
> // Logout
> sdk.auth.logout() // suspend function, call from a coroutine
> ```
>
> ### Wallet display example
>
> ```kotlin
> import com.dynamic.sdk.android.Models.BaseWallet
> import kotlinx.coroutines.flow.MutableStateFlow
>
> class HomeViewModel : ViewModel() {
>     private val sdk = DynamicSDK.getInstance()
>     private val _wallets = MutableStateFlow<List<BaseWallet>>(emptyList())
>     val wallets: StateFlow<List<BaseWallet>> = _wallets
>
>     init {
>         _wallets.value = sdk.wallets.userWallets
>         viewModelScope.launch {
>             sdk.wallets.userWalletsChanges.collect { newWallets ->
>                 _wallets.value = newWallets
>             }
>         }
>     }
> }
> ```
>
> ---
>
> ## Critical Reference
>
> | Correct | Incorrect | Notes |
> |---|---|---|
> | Place AAR in `app/libs/` | Reference a Maven coordinate | SDK is not on Maven Central |
> | Call `DynamicSDK.initialize()` in `onCreate()` | Call `getInstance()` before `initialize()` | Throws if not initialized |
> | Include `DynamicUI()` in root Compose layout | Omit `DynamicUI()` | Auth overlay won't appear |
> | Match `android:scheme` to `redirectUrl` | Use different values | OAuth callbacks break |
> | Use `viewModelScope.launch` for Flow collection | Collect on the main thread without lifecycle scope | Leaks coroutines |
> | Whitelist deep link in Dynamic Console | Skip console config | OAuth returns fail silently |
>
> ---
>
> ## Troubleshooting: Common Issues
>
> ### 1: "Could not resolve: dynamic-sdk-android.aar"
> Ensure the AAR file is in `app/libs/`. Clean the build (Build → Clean Project). Restart Android Studio.
>
> ### 2: SDK not initialized
> `DynamicSDK.initialize()` must be called in `MainActivity.onCreate()` before any views call `DynamicSDK.getInstance()`.
>
> ### 3: OAuth callbacks not working
> Verify the URL scheme in `AndroidManifest.xml` matches `redirectUrl` in `ClientProps`. Whitelist the deep link URL in the Dynamic Console under **Security → Whitelist Mobile Deeplink**.
>
> ### 4: Wallets not appearing after login
> Wallets are created asynchronously. Use `sdk.wallets.userWalletsChanges` Flow to listen for updates. Check that embedded wallets are enabled in the console.
>
> ### 5: DynamicUI overlay not showing
> Ensure `DynamicUI()` is in your root Compose layout inside a `Box` or similar container that supports overlays.
>
> If the issue persists, check https://docs.dynamic.xyz/overview/troubleshooting/general.
>
> ---
>
> ## Beyond This Quickstart
>
> This prompt covers initial setup only. For deeper guides (authentication flows, wallet operations, session management, transactions, etc.), fetch the full documentation index:
>
> **https://www.dynamic.xyz/docs/llms.txt**
>
> This file contains every page in the Dynamic documentation organized by SDK. Search for the "Kotlin SDK" section to discover all available pages and their URLs. Use it as your navigation source for any question beyond what this quickstart covers.
>
> Alternatively, if the Dynamic MCP server is available in your environment, query it directly for any documentation page.
> ````

> [tab] Step-by-step
>
> > [accordion] Prerequisites
> >
> > Before you begin, make sure you have:
> >
> > * **Android SDK 28+** (Android 9.0+)
> > * **Kotlin 2.1.0+**
> > * **Gradle 8.x+**
> > * **Java 17**
> > * **Dynamic Account**: Environment ID from [Dynamic Console](https://console.dynamic.xyz/dashboard/overview)
>
> ## Install the SDK
>
> This guide uses AAR-based setup (there is no interactive embed on this page).
>
> ### Step 1: Download AAR files
>
> Download the latest AAR files from the [Dynamic Android SDK repository](https://github.com/dynamic-labs-oss/android-sdk-and-sample-app):
>
> * `dynamic-sdk-android.aar` (required)
> * `solana-web3.aar` (optional, only if you need Solana support)
>
> Place them in your project's `app/libs` directory.
>
> ### Step 2: Add dependencies
>
> Add the Dynamic SDK and all required dependencies to your `build.gradle.kts`:
>
> ```kotlin build.gradle.kts theme={"system"}
> dependencies {
>     // ==========================================
>     // Dynamic SDK AAR Files
>     // ==========================================
>
>     // Core SDK (required)
>     implementation(files("libs/dynamic-sdk-android.aar"))
>
>     // Solana SDK (optional - remove if not needed)
>     implementation(files("libs/solana-web3.aar"))
>     implementation("org.sol4k:sol4k:0.6.0")  // Required by Dynamic Solana SDK
>
>     // ==========================================
>     // Required transitive dependencies
>     // ==========================================
>
>     // Kotlin Coroutines
>     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
>     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
>
>     // JSON serialization
>     implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
>
>     // Android WebView
>     implementation("androidx.webkit:webkit:1.8.0")
>
>     // HTTP client
>     implementation("com.squareup.okhttp3:okhttp:4.12.0")
>
>     // Custom Tabs for authentication
>     implementation("androidx.browser:browser:1.7.0")
>
>     // Secure storage - DataStore + Tink
>     implementation("androidx.datastore:datastore-preferences:1.1.1")
>     implementation("com.google.crypto.tink:tink-android:1.15.0")
>
>     // Passkeys support
>     implementation("androidx.credentials:credentials:1.2.2")
>     implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
>     implementation("com.google.android.gms:play-services-auth:20.7.0")
>
>     // Jetpack Compose (required for DynamicUI)
>     implementation(platform("androidx.compose:compose-bom:2024.09.00"))
>     implementation("androidx.compose.ui:ui")
>     implementation("androidx.compose.foundation:foundation")
>     implementation("androidx.compose.runtime:runtime")
>     implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
>
>     // ==========================================
>     // Used by the code in this quickstart
>     // ==========================================
>
>     implementation("androidx.activity:activity-compose:1.8.1")
>     implementation("androidx.compose.material3:material3")
>     implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
> }
> ```
>
> > [!NOTE]
> >
> > If you don't need Solana support, you can skip the `solana-web3.aar` and `sol4k` dependencies.
>
> ## Configure AndroidManifest.xml
>
> Add the required permissions and activities to your `AndroidManifest.xml`:
>
> ```xml AndroidManifest.xml theme={"system"}
> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
>     <uses-permission android:name="android.permission.INTERNET" />
>     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
>
>     <application
>         android:usesCleartextTraffic="true"
>         ...>
>
>         <activity
>             android:name=".MainActivity"
>             android:exported="true"
>             android:launchMode="singleTask">
>             <intent-filter>
>                 <action android:name="android.intent.action.MAIN" />
>                 <category android:name="android.intent.category.LAUNCHER" />
>             </intent-filter>
>         </activity>
>
>         <!-- OAuth Callback Activity (Required) -->
>         <activity
>             android:name="com.dynamic.sdk.android.Auth.AuthCallbackActivity"
>             android:exported="true"
>             android:launchMode="singleTop"
>             android:noHistory="true"
>             android:theme="@android:style/Theme.Translucent.NoTitleBar">
>             <intent-filter>
>                 <action android:name="android.intent.action.VIEW" />
>                 <category android:name="android.intent.category.DEFAULT" />
>                 <category android:name="android.intent.category.BROWSABLE" />
>                 <data android:scheme="yourappscheme" />
>             </intent-filter>
>         </activity>
>     </application>
> </manifest>
> ```
>
> > [!WARNING]
> >
> > Make sure the `android:scheme` in your manifest matches the `redirectUrl` in your `ClientProps`. For example, if `redirectUrl = "myapp://"`, then use `android:scheme="myapp"`.
>
> ## Initialize the SDK
>
> Initialize the Dynamic SDK in your MainActivity:
>
> ```kotlin MainActivity.kt theme={"system"}
> import android.os.Bundle
> import androidx.activity.ComponentActivity
> import androidx.activity.compose.setContent
> import androidx.compose.foundation.layout.*
> import androidx.compose.material3.*
> import androidx.compose.ui.Modifier
> import com.dynamic.sdk.android.DynamicSDK
> import com.dynamic.sdk.android.UI.DynamicUI
> import com.dynamic.sdk.android.core.ClientProps
> import com.dynamic.sdk.android.core.LoggerLevel
>
> class MainActivity : ComponentActivity() {
>     override fun onCreate(savedInstanceState: Bundle?) {
>         super.onCreate(savedInstanceState)
>
>         // Initialize Dynamic SDK
>         val props = ClientProps(
>             environmentId = "your-environment-id",
>             appLogoUrl = "https://your-app.com/logo.png",
>             appName = "Your App Name",
>             redirectUrl = "yourappscheme://",
>             appOrigin = "https://your-app.com",
>             logLevel = LoggerLevel.DEBUG
>         )
>         DynamicSDK.initialize(props, applicationContext, this)
>
>         setContent {
>             MaterialTheme {
>                 Surface(
>                     modifier = Modifier.fillMaxSize(),
>                     color = MaterialTheme.colorScheme.background
>                 ) {
>                     Box(modifier = Modifier.fillMaxSize()) {
>                         // Main app content
>                         AppContent()
>
>                         // Dynamic SDK WebView overlay (required for auth flows)
>                         DynamicUI()
>                     }
>                 }
>             }
>         }
>     }
> }
> ```
>
> ### Configuration Options
>
> The `ClientProps` supports various configuration options:
>
> | Property | Description | Required |
> | - | - | - |
> | `environmentId` | Your Dynamic environment ID from the Dynamic Console | Yes |
> | `appName` | Your app's display name (defaults to `Dynamic`) | No |
> | `appLogoUrl` | URL to your app's logo (shown in auth UI) | No |
> | `redirectUrl` | Deep link URL scheme for OAuth callbacks (required for social login) | No |
> | `appOrigin` | Your app's origin URL | No |
> | `reownProjectId` | Reown (WalletConnect) project ID for [connecting to dApps](https://docs.dynamic.xyz/docs/kotlin/wallets/global-wallets/walletconnect.md) | No |
> | `logLevel` | Logging level (`LoggerLevel.DEBUG`, `LoggerLevel.INFO`, `LoggerLevel.WARN`, `LoggerLevel.ERROR`) | No |
>
> ### Access the SDK
>
> After initialization, access the SDK singleton anywhere in your app:
>
> ```kotlin theme={"system"}
> val sdk = DynamicSDK.getInstance()
>
> // Show auth modal
> sdk.ui.showAuth()
>
> // Check auth state
> val isAuthenticated = sdk.auth.authenticatedUser != null
>
> // Get wallets
> val wallets = sdk.wallets.userWallets
>
> // Get primary wallet
> val primaryWallet = sdk.wallets.primary
> ```
>
> ## Basic Usage
>
> ### Using Built-in Authentication UI
>
> The easiest way to add authentication is using the built-in UI:
>
> ```kotlin theme={"system"}
> import androidx.compose.foundation.layout.*
> import androidx.compose.material3.*
> import androidx.compose.runtime.*
> import androidx.compose.ui.Modifier
> import androidx.compose.ui.unit.dp
> import com.dynamic.sdk.android.DynamicSDK
>
> @Composable
> fun LoginScreen() {
>     val sdk = DynamicSDK.getInstance()
>
>     Column(
>         modifier = Modifier
>             .fillMaxSize()
>             .padding(16.dp),
>         verticalArrangement = Arrangement.Center
>     ) {
>         Button(
>             onClick = { sdk.ui.showAuth() },
>             modifier = Modifier.fillMaxWidth()
>         ) {
>             Text("Sign In")
>         }
>     }
> }
> ```
>
> ### Listening for Authentication State
>
> Use Kotlin Flow to react to authentication changes:
>
> ```kotlin theme={"system"}
> import androidx.compose.foundation.layout.*
> import androidx.compose.material3.*
> import androidx.compose.runtime.*
> import androidx.compose.ui.Modifier
> import androidx.lifecycle.ViewModel
> import androidx.lifecycle.viewModelScope
> import com.dynamic.sdk.android.DynamicSDK
> import com.dynamic.sdk.android.Models.UserProfile
> import kotlinx.coroutines.flow.MutableStateFlow
> import kotlinx.coroutines.flow.StateFlow
> import kotlinx.coroutines.launch
>
> class AuthViewModel : ViewModel() {
>     private val sdk = DynamicSDK.getInstance()
>
>     private val _user = MutableStateFlow<UserProfile?>(null)
>     val user: StateFlow<UserProfile?> = _user
>
>     private val _isAuthenticated = MutableStateFlow(false)
>     val isAuthenticated: StateFlow<Boolean> = _isAuthenticated
>
>     init {
>         // Check initial auth state
>         _isAuthenticated.value = sdk.auth.authenticatedUser != null
>         _user.value = sdk.auth.authenticatedUser
>
>         // Listen for auth state changes
>         viewModelScope.launch {
>             sdk.auth.authenticatedUserChanges.collect { user ->
>                 _user.value = user
>                 _isAuthenticated.value = user != null
>             }
>         }
>     }
> }
>
> @Composable
> fun AppContent(viewModel: AuthViewModel) {
>     val isAuthenticated by viewModel.isAuthenticated.collectAsState()
>
>     if (isAuthenticated) {
>         HomeScreen()
>     } else {
>         LoginScreen()
>     }
> }
> ```
>
> ### Complete Example with Wallets
>
> ```kotlin theme={"system"}
> import androidx.compose.foundation.layout.*
> import androidx.compose.foundation.lazy.LazyColumn
> import androidx.compose.foundation.lazy.items
> import androidx.compose.material3.*
> import androidx.compose.runtime.*
> import androidx.compose.ui.Modifier
> import androidx.compose.ui.unit.dp
> import androidx.lifecycle.ViewModel
> import androidx.lifecycle.viewModelScope
> import com.dynamic.sdk.android.DynamicSDK
> import com.dynamic.sdk.android.Models.BaseWallet
> import kotlinx.coroutines.flow.MutableStateFlow
> import kotlinx.coroutines.flow.StateFlow
> import kotlinx.coroutines.launch
>
> class HomeViewModel : ViewModel() {
>     private val sdk = DynamicSDK.getInstance()
>
>     private val _wallets = MutableStateFlow<List<BaseWallet>>(emptyList())
>     val wallets: StateFlow<List<BaseWallet>> = _wallets
>
>     init {
>         // Get current wallets
>         _wallets.value = sdk.wallets.userWallets
>
>         // Listen for wallet changes
>         viewModelScope.launch {
>             sdk.wallets.userWalletsChanges.collect { newWallets ->
>                 _wallets.value = newWallets
>             }
>         }
>     }
>
>     fun showUserProfile() {
>         sdk.ui.showUserProfile()
>     }
>
>     fun logout() {
>         viewModelScope.launch {
>             sdk.auth.logout()
>         }
>     }
> }
>
> @Composable
> fun HomeScreen(viewModel: HomeViewModel) {
>     val wallets by viewModel.wallets.collectAsState()
>
>     Column(
>         modifier = Modifier
>             .fillMaxSize()
>             .padding(16.dp)
>     ) {
>         Text(
>             text = "Welcome!",
>             style = MaterialTheme.typography.headlineMedium
>         )
>
>         Spacer(modifier = Modifier.height(16.dp))
>
>         if (wallets.isEmpty()) {
>             CircularProgressIndicator()
>             Text("Creating wallets...")
>         } else {
>             LazyColumn {
>                 items(wallets) { wallet ->
>                     WalletCard(wallet)
>                 }
>             }
>         }
>
>         Spacer(modifier = Modifier.height(16.dp))
>
>         Button(
>             onClick = { viewModel.showUserProfile() },
>             modifier = Modifier.fillMaxWidth()
>         ) {
>             Text("Show Profile")
>         }
>
>         Button(
>             onClick = { viewModel.logout() },
>             modifier = Modifier.fillMaxWidth(),
>             colors = ButtonDefaults.buttonColors(
>                 containerColor = MaterialTheme.colorScheme.error
>             )
>         ) {
>             Text("Logout")
>         }
>     }
> }
>
> @Composable
> fun WalletCard(wallet: BaseWallet) {
>     Card(
>         modifier = Modifier
>             .fillMaxWidth()
>             .padding(vertical = 8.dp)
>     ) {
>         Column(modifier = Modifier.padding(16.dp)) {
>             Text(
>                 text = wallet.chain.uppercase(),
>                 style = MaterialTheme.typography.labelMedium,
>                 color = MaterialTheme.colorScheme.primary
>             )
>             Text(
>                 text = wallet.address,
>                 style = MaterialTheme.typography.bodyMedium
>             )
>         }
>     }
> }
> ```
>
> ## Enable Features in Console
>
> Before you can use authentication and wallet features, enable them in your Dynamic Console:
>
> 1. Go to your [Dynamic Console](https://console.dynamic.xyz/dashboard/overview)
>
> 2. Select your project
>
> 3. Go to **Authentication** and enable the methods you want to use:
>    * Email OTP
>    * SMS OTP
>    * Social providers (Google, Apple, Farcaster, etc.)
>    * Passkeys
>
> 4. Go to **Wallets** and enable embedded wallets
>
> 5. Go to **Chains** and enable the networks you want to support (EVM, Solana, Bitcoin, TON, or SUI)
>
> > [!TIP]
> >
> > For testing, we recommend starting with Email OTP authentication and an EVM
> > testnet like Base Sepolia. This gives you a complete setup without requiring
> > real phone numbers or mainnet transactions.
>
> ## Troubleshooting
>
> ### Common Issues
>
> * **Could not resolve: dynamic-sdk-android.aar**
>   * Make sure you've placed the AAR file in your `app/libs` directory
>   * Try cleaning the build (Build → Clean Project)
>   * Restart Android Studio
> * **SDK not initialized**
>   * Ensure `DynamicSDK.initialize()` is called in your `MainActivity.onCreate()` before any views access the SDK
>   * Don't call `DynamicSDK.getInstance()` before initialization
> * **Authentication callbacks not working**
>   * Verify your URL scheme is configured in `AndroidManifest.xml`
>   * Ensure the `redirectUrl` matches your URL scheme
>   * Whitelist your deep link URL in the Dynamic Console under **Security → Whitelist Mobile Deeplink**
> * **Wallets not appearing after login**
>   * Wallets are created asynchronously after authentication
>   * Use `sdk.wallets.userWalletsChanges` Flow to listen for wallet updates
>   * Check that embedded wallets are enabled in your console
> * **DynamicUI overlay not showing**
>   * Make sure `DynamicUI()` composable is included in your app's root layout
>   * Verify it's placed inside a `Box` or similar container that allows overlays
>
> ## Next Steps
>
> > [!WARNING]
> >
> > **Step-up authentication** and **device registration** are required
> > before accepting the `2026_04_01` API version. You must implement
> > both manually in your headless integration.
> > See the [upgrade guide](https://docs.dynamic.xyz/docs/get-started/migrations/api/2026_04_01.md).
>
> Your SDK is configured. You can go deeper here:
>
> 1. **[Authentication Guide](https://docs.dynamic.xyz/docs/kotlin/headless-authentication.md)**: Learn how to implement user authentication with email, SMS, and passkeys
>
> 2. **[Social Authentication](https://docs.dynamic.xyz/docs/kotlin/social-authentication.md)**: Add social login options like Google, Apple, and Farcaster
>
> 3. **[Session Management](https://docs.dynamic.xyz/docs/kotlin/session-management.md)**: Manage authentication state with Kotlin Flow
>
> 4. **[Wallet Operations](https://docs.dynamic.xyz/docs/kotlin/wallets/general/token-balances.md)**: Work with balances and sign messages
>
> 5. **[EVM Operations](https://docs.dynamic.xyz/docs/kotlin/wallets/evm/send-eth.md)**: Perform EVM transactions
>
> 6. **[Solana Operations](https://docs.dynamic.xyz/docs/kotlin/wallets/solana/connection.md)**: Send Solana transactions
>
> 7. **[Connect to dApps](https://docs.dynamic.xyz/docs/kotlin/wallets/global-wallets/walletconnect.md)**: Use WalletConnect to connect your embedded wallet to any dApp
>
> 8. **[Step-up authentication](https://docs.dynamic.xyz/docs/kotlin/step-up-auth.md)**: required before accepting the `2026_04_01` API version
>
> 9. **[Device registration](https://docs.dynamic.xyz/docs/kotlin/device-registration.md)**: required before accepting the `2026_04_01` API version
>
> > [!NOTE]
> >
> > Building without DynamicUI()? See the [Authentication screens](https://docs.dynamic.xyz/docs/kotlin/headless-authentication.md) for a full list of screens your app needs to handle.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.