Vika SDK Documentation
Android SDK untuk voice-powered navigation dalam aplikasi JKN Mobile. Integrasikan voice assistant dengan mudah menggunakan deep link navigation.
Voice Recognition
AI-powered voice recognition dengan akurasi 98%+ untuk Bahasa Indonesia
Deep Link Navigation
Navigasi otomatis menggunakan Android Deep Links
Real-time Updates
Socket.IO integration untuk response real-time
Installation
1. Configure GitHub Packages
Tambahkan repository GitHub Packages ke
settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/arafat1419/VIKA")
}
}
}
2. Add Dependency
Tambahkan dependency ke
build.gradle.kts
(app module):
dependencies {
// Vika SDK
implementation("com.vika.sdk:vika-sdk:1.0.3")
}
3. Sync Project
Klik Sync Now atau jalankan:
./gradlew build
Quick Start
Panduan cepat untuk mengintegrasikan Vika SDK dalam 3 langkah sederhana.
Step 1: Initialize SDK
Initialize SDK di
Application
class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Configure SDK
val config = SDKConfig.Builder("YOUR_API_KEY")
.debugMode(BuildConfig.DEBUG)
.allowedDeepLinkSchemes("jkn")
.language(VikaLanguage.INDONESIAN)
.build()
// Initialize SDK
VikaSDK.initialize(
context = this,
config = config,
callback = object : VikaSDK.Companion.InitCallback {
override fun onSuccess() {
// SDK ready, register screens
registerScreens()
}
override fun onError(error: Throwable) {
// Handle initialization error
Log.e("Vika", "Init failed", error)
}
}
)
}
}
Step 2: Register Screens
Daftarkan semua screen yang bisa diakses via voice:
private fun registerScreens() {
val sdk = VikaSDK.getInstance()
sdk.registerScreens(listOf(
ScreenRegistration(
screenId = "pendaftaran",
screenName = "Pendaftaran Peserta",
description = "Halaman untuk mendaftar sebagai peserta BPJS Kesehatan baru",
deepLink = "jkn://pendaftaran",
navigationType = NavigationType.DeepLink("jkn://pendaftaran"),
keywords = listOf("daftar", "registrasi", "peserta baru")
),
ScreenRegistration(
screenId = "faskes",
screenName = "Daftar Faskes",
description = "Daftar fasilitas kesehatan terdekat",
deepLink = "jkn://faskes",
navigationType = NavigationType.DeepLink("jkn://faskes"),
keywords = listOf("rumah sakit", "klinik", "puskesmas")
)
))
}
Step 3: Open Voice UI
Panggil Voice UI dari button atau menu:
// Simple usage
VikaSDK.getInstance().openVikaSDK(context)
// With custom options
val options = VikaUIOptions.builder()
.displayMode(VikaDisplayMode.BOTTOM_SHEET)
.appLogo(R.mipmap.ic_launcher)
.appTitle("JKN Mobile")
.build()
VikaSDK.getInstance().openVikaSDK(context, options)
[Screenshot: Voice UI Interface]
Configuration
Customize SDK behavior dengan berbagai opsi konfigurasi.
SDKConfig Options
| Parameter | Type | Default | Description |
|---|---|---|---|
apiKey |
String | - | Required. API key dari dashboard |
minConfidenceThreshold |
Float | 0.7 | Minimum confidence (0.0-1.0) untuk navigasi |
debugMode |
Boolean | false | Enable debug logging (disable di production) |
analyticsEnabled |
Boolean | true | Track navigation analytics |
timeoutMillis |
Long | 10000 | Network request timeout (ms) |
allowedDeepLinkSchemes |
List<String> | [] | Whitelist deep link schemes (e.g., "jkn") |
language |
VikaLanguage | ENGLISH | UI language (ENGLISH / INDONESIAN) |
Complete Configuration Example
val config = SDKConfig.Builder("your-api-key")
.minConfidenceThreshold(0.8f)
.analyticsEnabled(true)
.debugMode(BuildConfig.DEBUG)
.timeout(15000L)
.maxRetries(3)
.cacheEnabled(true)
.allowedDeepLinkSchemes("jkn", "bpjs")
.language(VikaLanguage.INDONESIAN)
.socketReconnectionAttempts(5)
.socketReconnectionDelay(2000L)
.build()
Screen Registration
Register screens agar bisa diakses via voice commands. Semakin detail informasi yang diberikan, semakin akurat AI mencocokkan voice command.
ScreenRegistration Fields
| Field | Type | Required | Description |
|---|---|---|---|
screenId |
String | ✅ | Unique identifier (e.g., "pendaftaran") |
screenName |
String | ✅ | Display name (e.g., "Pendaftaran Peserta") |
description |
String | ✅ | Detail apa yang ada di screen ini (untuk AI matching) |
deepLink |
String | ✅ | Deep link URI (e.g., "jkn://pendaftaran") |
navigationType |
NavigationType | ✅ | Tipe navigasi (DeepLink only untuk saat ini) |
keywords |
List<String> | ❌ | Additional keywords untuk improve matching accuracy |
Best Practices
Example: JKN Mobile Screens
val jknScreens = listOf(
// Home / Dashboard
ScreenRegistration(
screenId = "home",
screenName = "Beranda",
description = "Halaman utama JKN Mobile dengan informasi kartu, riwayat kunjungan, dan menu utama",
deepLink = "jkn://home",
navigationType = NavigationType.DeepLink("jkn://home"),
keywords = listOf("beranda", "home", "utama", "dashboard")
),
// Pendaftaran Peserta
ScreenRegistration(
screenId = "pendaftaran",
screenName = "Pendaftaran Peserta",
description = "Form pendaftaran peserta BPJS Kesehatan baru dengan upload dokumen KTP dan KK",
deepLink = "jkn://pendaftaran",
navigationType = NavigationType.DeepLink("jkn://pendaftaran"),
keywords = listOf("daftar", "registrasi", "peserta baru", "buat akun")
),
// Faskes Terdekat
ScreenRegistration(
screenId = "faskes",
screenName = "Fasilitas Kesehatan",
description = "Cari faskes terdekat: rumah sakit, klinik, puskesmas dengan peta dan navigasi",
deepLink = "jkn://faskes",
navigationType = NavigationType.DeepLink("jkn://faskes"),
keywords = listOf("faskes", "rumah sakit", "rs", "klinik", "puskesmas")
),
// Kartu Digital
ScreenRegistration(
screenId = "kartu",
screenName = "Kartu Digital",
description = "Tampilkan kartu BPJS digital dengan barcode dan informasi peserta",
deepLink = "jkn://kartu",
navigationType = NavigationType.DeepLink("jkn://kartu"),
keywords = listOf("kartu", "bpjs", "digital", "e-kartu")
),
// Riwayat Kunjungan
ScreenRegistration(
screenId = "riwayat",
screenName = "Riwayat Kunjungan",
description = "Histori kunjungan ke faskes dengan detail diagnosis dan obat",
deepLink = "jkn://riwayat",
navigationType = NavigationType.DeepLink("jkn://riwayat"),
keywords = listOf("riwayat", "history", "kunjungan", "rekam medis")
)
)
// Register all screens
VikaSDK.getInstance().registerScreens(jknScreens)
Deep Link Setup
Vika SDK menggunakan Android Deep Links untuk navigasi. Anda harus setup deep links di AndroidManifest.xml dan handle intent di Activity.
1. Configure AndroidManifest.xml
Tambahkan intent-filter untuk deep links di MainActivity:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop">
<!-- Main launcher intent -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Deep link intent filter -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Your app's deep link scheme -->
<data android:scheme="jkn" />
</intent-filter>
</activity>
2. Handle Deep Links in Activity
Handle incoming deep link intents di onCreate dan onNewIntent:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Handle deep link from onCreate
handleIntent(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
// Handle deep link from onNewIntent (when app is already running)
handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
val data: Uri? = intent.data
if (data != null && data.scheme == "jkn") {
// Parse deep link
when (data.host) {
"home" -> navigateToHome()
"pendaftaran" -> navigateToPendaftaran()
"faskes" -> navigateToFaskes()
"kartu" -> navigateToKartu()
"riwayat" -> navigateToRiwayat()
else -> Log.w("DeepLink", "Unknown host: ${data.host}")
}
}
}
private fun navigateToHome() {
// Navigate using your navigation framework (Jetpack Navigation, etc)
navController.navigate("home")
}
// Implement other navigation methods...
}
3. Test Deep Links
Test deep links menggunakan ADB command:
# Test deep link to pendaftaran screen
adb shell am start -W -a android.intent.action.VIEW -d "jkn://pendaftaran" com.jkn.mobile
# Test deep link to faskes screen
adb shell am start -W -a android.intent.action.VIEW -d "jkn://faskes" com.jkn.mobile
[Diagram: Deep Link Flow]
Voice UI
Vika SDK menyediakan UI untuk voice recording dengan waveform visualization. UI bisa ditampilkan dalam 3 mode berbeda.
Display Modes
FULLSCREEN
Full screen activity dengan branding app dan waveform besar. Best untuk first-time users.
DIALOG
Modal dialog dengan dismiss outside. Compact dan tidak mengganggu context.
BOTTOM_SHEET
Bottom sheet yang slide dari bawah. Modern dan familiar untuk mobile users.
Usage Examples
// 1. Simple fullscreen (default)
VikaSDK.getInstance().openVikaSDK(context)
// 2. Dialog mode with custom branding
val dialogOptions = VikaUIOptions.builder()
.displayMode(VikaDisplayMode.DIALOG)
.appLogo(R.drawable.ic_jkn_logo)
.appTitle("JKN Mobile")
.dismissOnTouchOutside(true)
.build()
VikaSDK.getInstance().openVikaSDK(context, dialogOptions)
// 3. Bottom sheet with custom theme
val customTheme = VikaThemeConfig(
primaryColor = 0xFF0FAF65, // JKN Green
secondaryColor = 0xFF059669, // Darker green
backgroundColor = 0xFFFFFFFF, // White
textColor = 0xFF1F2937, // Dark gray
surfaceColor = 0xFFF9FAFB, // Light gray
waveformColor = 0xFF0FAF65 // JKN Green
)
val bottomSheetOptions = VikaUIOptions.builder()
.displayMode(VikaDisplayMode.BOTTOM_SHEET)
.appLogo(R.drawable.ic_jkn_logo)
.appTitle("Vika Assistant")
.theme(customTheme)
.dismissOnTouchOutside(true)
.build()
VikaSDK.getInstance().openVikaSDK(context, bottomSheetOptions)
UI Customization
Customize Voice UI agar match dengan branding JKN Mobile menggunakan VikaThemeConfig.
Theme Configuration
| Property | Type | Description |
|---|---|---|
primaryColor |
Long (0xFFRRGGBB) | Main brand color untuk buttons & accents |
secondaryColor |
Long (0xFFRRGGBB) | Secondary color untuk highlights |
backgroundColor |
Long (0xFFRRGGBB) | Background color (usually white/dark) |
textColor |
Long (0xFFRRGGBB) | Primary text color |
surfaceColor |
Long (0xFFRRGGBB) | Card/surface background color |
waveformColor |
Long (0xFFRRGGBB) | Waveform visualization color |
Predefined Themes
// Default Dark Theme
val darkTheme = VikaThemeConfig.DEFAULT_DARK
// Default Light Theme
val lightTheme = VikaThemeConfig.DEFAULT_LIGHT
// JKN Mobile Theme (Custom)
val jknTheme = VikaThemeConfig(
primaryColor = 0xFF0FAF65, // BPJS Green
secondaryColor = 0xFF059669,
backgroundColor = 0xFFFFFFFF,
textColor = 0xFF111827,
surfaceColor = 0xFFF3F4F6,
waveformColor = 0xFF0FAF65
)
// Apply theme
val options = VikaUIOptions.builder()
.theme(jknTheme)
.build()
VikaSDK.getInstance().openVikaSDK(context, options)
Socket.IO Events
SDK menggunakan Socket.IO untuk menerima hasil processing voice secara real-time. Anda bisa listen ke events untuk custom handling.
Listen to Conversation Events
val sdk = VikaSDK.getInstance()
// Set conversation listener
sdk.setConversationListener(object : VikaSDK.ConversationListener {
override fun onConversationProcessed(event: ConversationProcessedEvent) {
// Called when voice is processed and navigation result is ready
Log.d("Vika", "Transcription: ${event.transcription}")
Log.d("Vika", "Target Screen: ${event.navigationData.deepLink}")
Log.d("Vika", "Confidence: ${event.navigationData.confidence}")
// SDK will automatically navigate via deep link
// But you can add custom logic here
if (event.navigationData.confidence < 0.8f) {
// Show confirmation dialog for low confidence
showNavigationConfirmation(event.navigationData)
}
}
override fun onError(error: VikaError) {
// Handle errors
when (error) {
is VikaError.Network -> {
Toast.makeText(context, "Network error", Toast.LENGTH_SHORT).show()
}
is VikaError.SocketConnection -> {
Toast.makeText(context, "Connection lost", Toast.LENGTH_SHORT).show()
}
else -> {
Log.e("Vika", "Error: ${error.message}")
}
}
}
})
Socket Connection Management
val sdk = VikaSDK.getInstance()
// Check connection status
if (sdk.isSocketConnected()) {
Log.d("Vika", "Socket is connected")
}
// Manually disconnect (if needed)
sdk.disconnectSocket()
// Manually reconnect
sdk.reconnectSocket()
Security
Vika SDK implements multiple security layers untuk protect data dan prevent unauthorized access.
Security Features
AES-256 Encryption
Semua data sensitive di-encrypt dengan AES-256-CBC sebelum dikirim ke server.
Certificate Pinning
Optional certificate pinning untuk prevent man-in-the-middle attacks.
Request Signing
Semua requests di-sign dengan HMAC-SHA256 untuk verify authenticity.
Deep Link Validation
Whitelist allowed schemes untuk prevent malicious deep links.
Security Best Practices
// Secure configuration for production
val secureConfig = SDKConfig.Builder(BuildConfig.VIKA_API_KEY)
.debugMode(false) // Disable debug logs
.allowedDeepLinkSchemes("jkn") // Only allow "jkn://" scheme
.certificatePinning( // Optional: Pin server certificate
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
)
.build()
// Store API key in BuildConfig (build.gradle.kts)
// buildConfigField("String", "VIKA_API_KEY", "\"${project.findProperty("vika.api.key")}\")"
PII Data Masking
Vika SDK secara otomatis melindungi data sensitif peserta BPJS dengan melakukan masking terhadap PII (Personally Identifiable Information) sebelum data dikirim ke LLM untuk processing.
Bagaimana Cara Kerjanya?
Hasil konversi voice input menjadi text akan dideteksi dan di-mask PII-nya terlebih dahulu.
Deeplink yang akan dikirim ke LLM juga sudah di-mask untuk menghilangkan parameter sensitif.
Data yang sudah di-anonymize dikirim ke LLM untuk menentukan intent dan deeplink yang sesuai.
Data asli tetap tersimpan di device dan tidak pernah terekspos ke external services.
Jenis Data yang Di-Mask
Identitas Pribadi
- NIK (Nomor Induk Kependudukan)
- Nomor Kartu BPJS
- Nama Lengkap
- Tanggal Lahir
Informasi Kontak
- Nomor Telepon
- Email Address
- Alamat Lengkap
Data Kesehatan
- Nomor Rekam Medis
- Diagnosis
- Riwayat Penyakit
Informasi Finansial
- Nomor Rekening
- Informasi Pembayaran
- Iuran BPJS
Contoh Masking
// User voice input hasil speech-to-text
"Saya mau cek status klaim untuk nomor kartu BPJS 0001234567890 atas nama Budi Santoso NIK 3201012345678901"
// Data yang dikirim ke LLM sudah di-anonymize
"Saya mau cek status klaim untuk nomor kartu BPJS [MASKED_BPJS_NUMBER] atas nama [MASKED_NAME] NIK [MASKED_NIK]"
// LLM hanya menerima intent, bukan data sensitif
// LLM Response: "navigate to status klaim page"
// Deeplink yang di-return:
"jkn://status-klaim" // Tanpa parameter sensitif
API Reference
Complete reference untuk semua public APIs di Vika SDK.
VikaSDK Class
Static Methods (Companion)
Initialize SDK with config. Must be called before using other methods.
Get singleton SDK instance. Throws exception if not initialized.
Check if SDK has been initialized.
Destroy SDK instance and clean up resources.
Instance Methods
Register single screen for voice navigation.
Register multiple screens at once.
Open Voice UI with default options (fullscreen).
Open Voice UI with custom display mode and theme.
Set listener to receive real-time conversation results via Socket.IO.
Check if backend initialization was successful.
Check if Socket.IO is currently connected.
Troubleshooting
Solusi untuk common issues yang mungkin Anda temui.
SDK Initialization Failed
Error: "Backend initialization failed" atau timeout
Solutions:
- Check internet connection
- Verify API key is valid (get from dashboard)
- Check if backend server is running
- Increase timeout: .timeout(30000L)
- Check Logcat for detailed error
Deep Link Not Working
Navigation tidak trigger setelah voice command
Solutions:
- Verify intent-filter in AndroidManifest.xml
- Check launchMode is "singleTop" for MainActivity
- Implement onNewIntent() to handle deep links when app is running
- Test deep link with ADB: adb shell am start -d "jkn://screen"
- Verify scheme is in allowedDeepLinkSchemes config
Voice Not Recognized Accurately
AI salah mencocokkan screen atau confidence terlalu rendah
Solutions:
- Add more detailed descriptions to ScreenRegistration
- Add more keywords (synonyms, variations)
- Lower minConfidenceThreshold if too strict (default: 0.7)
- Test with clear audio in quiet environment
- Check language setting matches voice input
Socket Connection Lost
Real-time updates tidak diterima
Solutions:
- SDK auto-reconnects, wait for reconnection
- Check isSocketConnected() to verify connection status
- Increase reconnection attempts: .socketReconnectionAttempts(10)
- Check network stability
- Call reconnectSocket() to manually trigger reconnect
Dependency Resolution Failed
Gradle sync error: "Could not resolve com.vika.sdk:vika-sdk"
Solutions:
- Check maven repository URL is correct
- Verify internet connection
- Try ./gradlew build --refresh-dependencies
- Clear Gradle cache: ./gradlew clean