Overview
The Dynamic Kotlin SDK provides a comprehensive API for building Web3-enabled Android applications. This reference documents all the modules, functions, and types available in the SDK.Requirements
- Android API Level 26+
- Kotlin 1.9+
- Gradle 8.0+
Installation
Copy
Ask AI
// build.gradle.kts
dependencies {
implementation("com.dynamic:android-sdk:VERSION")
}
SDK Architecture
The SDK uses a singleton pattern with modular access to different functionalities:Copy
Ask AI
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.DynamicSDKConfig
// Initialize at app launch (in Application or MainActivity)
DynamicSDK.initialize(
context = applicationContext,
config = DynamicSDKConfig(
environmentId = "YOUR_ENV_ID"
)
)
// Access SDK instance
val sdk = DynamicSDK.getInstance()
// Access modules
sdk.auth // Authentication
sdk.wallets // Wallet management
sdk.evm // EVM chain operations
sdk.solana // Solana operations
sdk.networks // Available networks
sdk.mfa // Multi-factor authentication
sdk.passkeys // Passkey management
sdk.ui // Built-in UI components
Core Modules
Initialization
Copy
Ask AI
// Initialize SDK (call once at app launch)
DynamicSDK.initialize(
context = applicationContext,
config = DynamicSDKConfig(
environmentId = "YOUR_ENV_ID"
)
)
// Get SDK instance
val sdk = DynamicSDK.getInstance()
Authentication (sdk.auth)
Copy
Ask AI
// Current user
val user = sdk.auth.authenticatedUser
// Auth token
val token = sdk.auth.token
// Reactive flows (Kotlin Coroutines)
sdk.auth.authenticatedUserChanges // StateFlow<UserProfile?>
sdk.auth.tokenChanges // StateFlow<String?>
// Logout
sdk.auth.logout()
// Email OTP
sdk.auth.email.sendOTP("[email protected]")
sdk.auth.email.verifyOTP("123456")
sdk.auth.email.resendOTP()
// SMS OTP
val phoneData = PhoneData(dialCode = "+1", iso2 = "US", phone = "5551234567")
sdk.auth.sms.sendOTP(phoneData)
sdk.auth.sms.verifyOTP("123456")
sdk.auth.sms.resendOTP()
// Social authentication
sdk.auth.social.connect(SocialAuthModule.SocialProvider.GOOGLE)
sdk.auth.social.connect(SocialAuthModule.SocialProvider.APPLE)
sdk.auth.social.connect(SocialAuthModule.SocialProvider.FARCASTER)
// Passkey authentication
sdk.auth.passkey.signIn()
// External JWT
sdk.auth.externalAuth.signInWithExternalJwt(
SignInWithExternalJwtParams(jwt = "your-jwt")
)
Wallets (sdk.wallets)
Copy
Ask AI
// Current wallets
val wallets = sdk.wallets.userWallets // List<BaseWallet>
// Reactive flow (Kotlin Coroutines)
sdk.wallets.userWalletsChanges // StateFlow<List<BaseWallet>>
// Get balance
val balance = sdk.wallets.getBalance(wallet)
// Get current network
val network = sdk.wallets.getNetwork(wallet)
// Switch network
sdk.wallets.switchNetwork(wallet, targetNetwork)
// Set primary wallet
sdk.wallets.setPrimary(walletId)
// Sign message
val signature = sdk.wallets.signMessage(wallet, "Hello")
// Sign typed data (EIP-712)
val signature = sdk.wallets.signTypedData(wallet, typedDataJson)
// Verify signature
val isValid = sdk.wallets.verifySignature(
wallet = wallet,
message = "Hello",
signature = signature
)
EVM Operations (sdk.evm)
Copy
Ask AI
// Create public client for chain
val client = sdk.evm.createPublicClient(chainId = 1)
// Get gas price
val gasPrice = client.getGasPrice()
// Send transaction
val transaction = EthereumTransaction(
to = "0x...",
value = "1000000000000000", // Wei as String
gasLimit = 21000,
maxFeePerGas = gasPrice,
maxPriorityFeePerGas = gasPrice
)
val txHash = sdk.evm.sendTransaction(wallet, transaction)
// Sign transaction (without sending)
val signedTx = sdk.evm.signTransaction(wallet, transaction)
// Write to contract
val input = WriteContractInput(
address = "0x...",
functionName = "transfer",
args = listOf(recipient, amount),
abi = listOf(/* ABI maps */)
)
val txHash = sdk.evm.writeContract(wallet, input)
Solana Operations (sdk.solana)
Copy
Ask AI
// Create connection
val connection = sdk.solana.createConnection()
// Get latest blockhash
val blockhashResult = connection.getLatestBlockhash()
val blockhash = blockhashResult.blockhash
// Create signer
val signer = sdk.solana.createSigner(wallet)
// Sign message
val signature = signer.signMessage("Hello")
// Sign transaction
val signedTx = signer.signEncodedTransaction(base64Transaction)
// Sign and send transaction
val signature = signer.signAndSendEncodedTransaction(base64Transaction)
Networks (sdk.networks)
Copy
Ask AI
// Available EVM networks
val evmNetworks = sdk.networks.evm // List<GenericNetwork>
// Available Solana networks
val solanaNetworks = sdk.networks.solana // List<GenericNetwork>
// Network properties
network.name // String
network.chainId // For EVM
network.networkId // For Solana
MFA (sdk.mfa)
Copy
Ask AI
// Get user devices
val devices = sdk.mfa.getUserDevices()
// Add TOTP device (returns MfaAddDevice with secret)
val device = sdk.mfa.addDevice("totp")
// Verify device
sdk.mfa.verifyDevice("123456", "totp")
// Authenticate device to get MFA token
val token = sdk.mfa.authenticateDevice(
MfaAuthenticateDevice(
code = "123456",
deviceId = deviceId,
createMfaToken = MfaCreateToken(singleUse = true)
)
)
// Delete device (requires MFA token)
sdk.mfa.deleteUserDevice(deviceId, mfaAuthToken = token)
// Recovery codes
val codes = sdk.mfa.getRecoveryCodes(generateNewCodes = false)
sdk.mfa.acknowledgeRecoveryCodes() // Mark codes as shown to user
sdk.mfa.authenticateRecoveryCode(recoveryCode)
Passkeys (sdk.passkeys)
Copy
Ask AI
// Get user's passkeys
val passkeys = sdk.passkeys.getPasskeys()
// Register new passkey
sdk.passkeys.registerPasskey()
// Authenticate with passkey for MFA
val response = sdk.passkeys.authenticatePasskeyMFA(
createMfaToken = MfaCreateToken(singleUse = true),
relatedOriginRpId = null
)
// Delete passkey
sdk.passkeys.deletePasskey(
DeletePasskeyRequest(passkeyId = passkeyId)
)
// Passkey properties
passkey.id // String - Unique identifier
passkey.createdAt // String - Creation timestamp (ISO format)
passkey.lastUsedAt // String? - Last authentication time
passkey.isDefault // Boolean? - Whether this is the default passkey
Built-in UI (sdk.ui)
Copy
Ask AI
// Show authentication UI
sdk.ui.showAuth()
// Show user profile
sdk.ui.showUserProfile()
Data Types
DynamicSDKConfig
Copy
Ask AI
DynamicSDKConfig(
environmentId: String // Required
)
BaseWallet
Copy
Ask AI
wallet.address // String - Wallet address
wallet.chain // String - "EVM" or "SOL"
wallet.walletName // String? - Wallet name
wallet.id // String? - Wallet ID for API operations
UserProfile
Copy
Ask AI
user.userId // String?
user.email // String?
user.phoneNumber // String?
// Additional properties available
PhoneData
Copy
Ask AI
PhoneData(
dialCode: String, // e.g., "+1"
iso2: String, // e.g., "US"
phone: String // Phone number without country code
)
WriteContractInput
Copy
Ask AI
WriteContractInput(
address: String,
functionName: String,
args: List<Any>,
abi: List<Map<String, Any>>
)
GenericNetwork
Copy
Ask AI
network.name // String
network.chainId // For EVM networks
network.networkId // For Solana networks
Error Handling
All SDK functions can throw exceptions. Use Kotlin’s native error handling:Copy
Ask AI
try {
sdk.auth.email.verifyOTP(code)
} catch (e: Exception) {
Log.e("Auth", "Error: ${e.message}")
}
Copy
Ask AI
viewModelScope.launch {
try {
sdk.auth.email.sendOTP(email)
} catch (e: Exception) {
errorMessage.value = "Failed: ${e.message}"
}
}
Quick Reference Example
Copy
Ask AI
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.DynamicSDKConfig
import android.app.Application
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
DynamicSDK.initialize(
context = applicationContext,
config = DynamicSDKConfig(
environmentId = "YOUR_ENV_ID"
)
)
}
}
// In your MainActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
}
@Composable
fun MyApp() {
val sdk = DynamicSDK.getInstance()
var isAuthenticated by remember {
mutableStateOf(sdk.auth.authenticatedUser != null)
}
LaunchedEffect(Unit) {
sdk.auth.authenticatedUserChanges.collect { user ->
isAuthenticated = user != null
}
}
if (isAuthenticated) {
HomeScreen()
} else {
LoginScreen()
}
}
@Composable
fun LoginScreen() {
val sdk = DynamicSDK.getInstance()
Button(onClick = { sdk.ui.showAuth() }) {
Text("Sign In")
}
}
@Composable
fun HomeScreen() {
val sdk = DynamicSDK.getInstance()
Column {
Text("Welcome!")
Button(onClick = { sdk.ui.showUserProfile() }) {
Text("View Profile")
}
Button(onClick = {
try {
sdk.auth.logout()
} catch (e: Exception) {
Log.e("Home", "Logout failed: ${e.message}")
}
}) {
Text("Logout")
}
}
}
Session State Management with ViewModel
For production apps, use a ViewModel for better state management:Copy
Ask AI
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dynamic.sdk.android.DynamicSDK
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class SessionViewModel : ViewModel() {
private val sdk = DynamicSDK.getInstance()
private val _isAuthenticated = MutableStateFlow(
sdk.auth.authenticatedUser != null
)
val isAuthenticated: StateFlow<Boolean> = _isAuthenticated.asStateFlow()
init {
// Observe authentication changes
viewModelScope.launch {
sdk.auth.authenticatedUserChanges.collect { user ->
_isAuthenticated.value = user != null
}
}
}
fun logout() {
viewModelScope.launch {
try {
sdk.auth.logout()
} catch (e: Exception) {
Log.e("SessionVM", "Logout failed: ${e.message}")
}
}
}
}
// Use in Compose
@Composable
fun AppContent() {
val viewModel: SessionViewModel = viewModel()
val isAuthenticated by viewModel.isAuthenticated.collectAsState()
if (isAuthenticated) {
HomeScreen()
} else {
LoginScreen()
}
}
Complete Example App: For a fully functional Android app demonstrating all SDK
features, check the Screens directory in the documentation repository for complete
implementation examples.