Skip to content

Latest commit

 

History

History
133 lines (109 loc) · 4.52 KB

File metadata and controls

133 lines (109 loc) · 4.52 KB
name mobile-sync-android
summary Couchbase Mobile sync for Android (Kotlin) — configure Couchbase Lite replication, set up Sync Gateway, design Sync Function access control, implement offline-first architecture
description Couchbase Mobile sync for Android (Kotlin) — configure Couchbase Lite replication, set up Sync Gateway, design Sync Function access control, implement offline-first architecture
compatibility Couchbase Lite Android 4.x (Kotlin). Requires Sync Gateway 3.x or Capella App Services for cloud sync.
metadata
last_verified handoff
2026-05
condition skill
user is on iOS or Swift
mobile-sync-ios
condition skill
user asks about conflict resolution
mobile-conflict-resolution-android
condition skill
user is using Capella App Services instead of self-hosted Sync Gateway
app-services
condition skill
user asks about document design or channel strategy
mobile-data-modeling
condition skill
user asks about device-to-device or P2P sync
mobile-p2p-sync-android

Platform-agnostic concepts (architecture, Sync Function, troubleshooting): shared/mobile/sync-architecture.md

Couchbase Mobile Sync — Android

Configure Couchbase Lite replication to Sync Gateway or Capella App Services.

Sync Function template: templates/sync-function.js — copy this skeleton as a starting point.

Architecture

Android Device
  └── Couchbase Lite (embedded JSON database)
        │  WebSocket (wss://)
        ▼
  Sync Gateway / Capella App Services
        │
        ▼
  Couchbase Server / Capella

Basic replication setup

import com.couchbase.lite.*

val target = URLEndpoint(URI("wss://sync-gateway.example.com/mydb"))

val replConfig = ReplicatorConfiguration(target).apply {
    addCollection(collection, null)
    type          = ReplicatorType.PUSH_AND_PULL
    continuous    = true
    // Read from EncryptedSharedPreferences (androidx.security.crypto) — never hardcode
    val masterKey = MasterKey.Builder(context)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
    val encryptedPrefs = EncryptedSharedPreferences.create(
        context, "sg_creds", masterKey,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
    authenticator = BasicAuthenticator(
        encryptedPrefs.getString("sg_username", null)!!,
        encryptedPrefs.getString("sg_password", null)!!.toCharArray()
    )
}

val replicator = Replicator(replConfig)

val token = replicator.addChangeListener { change ->
    val status = change.status
    when (status.activityLevel) {
        ReplicatorActivityLevel.STOPPED  -> Log.i("Sync", "Stopped: ${status.error}")
        ReplicatorActivityLevel.OFFLINE  -> Log.i("Sync", "Offline")
        ReplicatorActivityLevel.IDLE     -> Log.i("Sync", "Idle — up to date")
        ReplicatorActivityLevel.BUSY     -> Log.i("Sync", "Syncing...")
        else -> {}
    }
}

replicator.start()

Session authentication (Capella App Services)

val replConfig = ReplicatorConfiguration(target).apply {
    addCollection(collection, null)
    authenticator = SessionAuthenticator("your-session-token")
}

Channel filtering

val collectionConfig = CollectionConfiguration().apply {
    channels = listOf("user.alice", "team.engineering")
}

val replConfig = ReplicatorConfiguration(target).apply {
    addCollection(collection, collectionConfig)
}

Document filtering (push)

val collectionConfig = CollectionConfiguration().apply {
    pushFilter = ReplicationFilter { document, _ ->
        document.getString("type") != "draft"
    }
}

Offline-first pattern

// Always read/write from the local database — replication happens in the background
fun saveNote(note: Note) {
    val doc = MutableDocument("note::${note.id}").apply {
        setString("title", note.title)
        setString("body", note.body)
        setString("userId", currentUser.id)
    }
    collection.save(doc)  // local write, syncs automatically
}

Troubleshooting

  • 401: wrong credentials or session expired
  • 403: Sync Function requireUser/requireRole rejected the document
  • WebSocket CLOSE 1008: Sync Gateway rejected the connection — check Sync Gateway logs
  • Enable REPLICATOR and NETWORK at DEBUG (see mobile-logging-android)