Skip to content

Native Mobile SDKs

RTCstack ships native iOS (Swift) and Android (Kotlin) SDKs that mirror the @rtcstack/sdk contract — the same createCall → connect → events model as the web SDK, wrapping LiveKit's native clients the same way the web SDK wraps livekit-client. Native and web clients interoperate in the same room.

Each platform also ships a UI kit (SwiftUI / Jetpack Compose) built on LiveKit's official Components libraries, with a drop-in VideoConference view and the same design tokens as the web kits.

Status — preview, not yet published

Both SDKs compile against their pinned LiveKit dependencies and the cross-platform wire-format conformance tests pass (Android 7/7, iOS 6/6). The device-level features (CallKit/VoIP, screen share, audio routing, incoming-call push) are implemented but require a real-device pass with your own app/push credentials, and the packages are not yet published to CocoaPods trunk / Maven Central / a tagged release. Install today from source (SPM-from-git on iOS); registry coordinates land on first publish. Track Phase 6 for the release.

What you get

iOSAndroid
Client SDKRTCstackKit (Swift Package / CocoaPods)com.rtcstack:sdk (AAR)
UI kitRTCstackUI (SwiftUI)com.rtcstack:ui-compose (Compose)
Built onclient-sdk-swift + components-swiftlivekit-android + livekit-android-compose-components
Min targetiOS 15.0+Android API 24 (7.0)+

Pinned dependencies: iOS client-sdk-swift 2.14.1 + components-swift 0.1.7; Android livekit-android 2.24.1 + livekit-android-compose-components 2.3.0.

The same two-channel architecture as web

The connection model is identical to the web architecture:

  • Signaling — WSS to your LiveKit endpoint (Caddy-proxied). Native SDK ↔ LiveKit server.
  • Media — WebRTC/SRTP over UDP, direct to the LiveKit SFU (or a TURN relay on TLS:443).
  • The RTCstack REST API is not involved during a call. It is called once, before the call, to mint a token.
1. Your app authenticates the user                         (your responsibility)
2. Your backend mints a token:
     POST /v1/token  { roomId, userId, name, role }
     → { token: "<JWT>", url: "wss://…/livekit", expiresAt }
3. Native client connects:
     let call = RTCstack.createCall(.init(token: token, url: url))   // Swift
     val call = RTCstack.createCall(context, CallOptions(token, url)) // Kotlin
     try await call.connect()
4. Room state + media negotiated over WSS; media flows over UDP

Secrets never ship in a mobile binary

Token issuance requires your API_KEY / API_SECRET for HMAC signing — these are trivially extractable from a mobile binary and must never be embedded. The native SDKs therefore:

  • Take { token, url } exactly like the web SDK — your backend mints the token.
  • Accept a tokenRefresher closure / suspend function that calls your backend, never the RTCstack API directly.
  • Do not bundle the HMAC-signing REST client.

See Token Flow for the backend side.

Cross-platform wire-format interop

Native clients exchange chat, reactions, speaking indicators, and transcript segments with web clients in the same room over the LiveKit data channel. The payload format is a frozen cross-platform contract — UTF-8 JSON keyed on a type discriminator — enforced by conformance tests on all three platforms.

TypeJSON
chat{"type":"chat","text":"…","id":"…"}
reaction{"type":"reaction","emoji":"…"}
speaking{"type":"speaking","speakerId":"…","speaker":"…"}
transcript{"type":"transcript","text":"…","speakerId":"…","speaker":"…","startMs":1234}

Unknown type values are ignored for forward compatibility. LiveKit does not loop data back to the sender, so sending a message does not fire a local messageReceived — the UI kits echo the user's own outgoing messages. Any change to this format is a major version bump across all SDKs together.

API parity at a glance

The conceptual core (~80%) ports verbatim from the web SDK; the reactive primitive is the only thing that changes — Combine @Published / PassthroughSubject on iOS, Kotlin StateFlow / SharedFlow on Android.

Web (@rtcstack/sdk)iOS (RTCstackKit)Android (com.rtcstack:sdk)
createCall({ token, url })RTCstack.createCall(_:)RTCstack.createCall(context, …)
call.connect() / disconnect()connect() / disconnect()connect() / disconnect()
toggleMic / toggleCamerasamesame
startScreenShareReplayKit broadcastMediaProjection consent
sendMessage / sendReactionsamesame
call.on('event', …)events (Combine)events (SharedFlow)
reactive state@Published propsStateFlow props

The remaining ~20% is native-only platform integration — CallKit/VoIP and ConnectionService/FCM incoming calls, ReplayKit/MediaProjection screen share, audio session/focus management, and foreground-service lifecycle. These are first-class, opt-in modules documented per platform.

Next steps

  • iOS (Swift) — SPM install, the Call API, CallKit/VoIP/ReplayKit, the SwiftUI kit
  • Android (Kotlin) — Gradle install, the Call API, foreground service / FCM / MediaProjection, the Compose kit