Flutter
Add calls, chat and a prebuilt call UI to your Flutter app. The SDK wraps signalling (ring/accept), media (LiveKit) and chat behind one small client — with a drop-in UI-Kit, or bring your own.
Install
1flutter pub add socrits livekit_client permission_handlerAdd platform permissions (Android needs min SDK 21):
1<!-- android/app/src/main/AndroidManifest.xml -->2<uses-permission android:name="android.permission.INTERNET"/>3<uses-permission android:name="android.permission.CAMERA"/>4<uses-permission android:name="android.permission.RECORD_AUDIO"/>5<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>6<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>78<!-- ios/Runner/Info.plist -->9<key>NSCameraUsageDescription</key><string>Video calls</string>10<key>NSMicrophoneUsageDescription</key><string>Voice calls</string>Initialize & connect
Create the client with your Socrits base URL and connect the signalling socket. The app authenticates with a session token your backend mints — see Server & tokens.
1import 'package:socrits/socrits.dart';2import 'package:livekit_client/livekit_client.dart' as lk;34final client = Socrits(baseUrl: 'https://cloud.unitythink.com');56// Connect the signalling socket. Your backend issues the user's session token7// (POST /v1/session with your sk_live_ key) — never embed the key in the app.8await client.connect(9 sessionEndpoint: 'https://your-backend.com/socrits/session', // returns { token }10 userId: 'alice',11 userName: 'Alice',12);13// (or, if you already have a token) await client.connect(userToken: token, userId: 'alice');Set up callbacks
1// Wire these once, right after connect()2client.onIncomingCall = (IncomingCall call) {3 // show your ringing screen, then accept or reject:4 // final room = await client.accept(call);5 // client.reject(call);6};7client.onCallConnected = (lk.Room room, CallMode mode) {8 // both sides are in the room now — show the call screen (see below)9};10client.onCallRejected = (callId) { /* callee declined */ };11client.onCallEnded = (reason) { /* other side hung up / left */ };1213// Offline ringing: register the device's FCM token so Socrits can push a ring14client.registerDevice(fcmToken, platform: 'android');Make & receive a call
1// Caller: start a call. Returns a callId; the callee gets onIncomingCall.2final callId = await client.invite(3 toUserId: 'bob',4 mode: CallMode.video, // or CallMode.voice5);67// Callee: inside onIncomingCall8final room = await client.accept(call); // joins the media room9// onCallConnected fires on BOTH sides with the connected lk.Room.Option A — with the UI-Kit
SocritsCallView is a complete WhatsApp-style call screen: remote video full-screen, your camera in a PiP, a live timer, and Speaker / Flip / Video / Mute / End controls (voice calls show a pulsing avatar). Hand it the connected room and you’re done.
1import 'package:socrits/socrits.dart';23client.onCallConnected = (room, mode) {4 Navigator.of(context).push(MaterialPageRoute(5 builder: (_) => Scaffold(6 body: SocritsCallView(7 room: room,8 title: 'Bob',9 initialCam: mode == CallMode.video,10 onHangUp: () => Navigator.of(context).maybePop(),11 ),12 ),13 ));14};Widget parameters
room— the connectedlk.Roomfromaccept()/onCallConnected. Required.title— name shown for the other party.initialMic/initialCam— starting mic/camera state (default true).onHangUp— called when the user taps End or the call ends; pop your screen here.
Option B — without the UI-Kit
Prefer your own design? accept() and onCallConnected give you the raw LiveKit Room. Control tracks and render video yourself with livekit_client:
1// You get the raw LiveKit Room from accept() / onCallConnected — build any UI you want.2final lk.Room room = await client.accept(call);34// controls5await room.localParticipant?.setMicrophoneEnabled(true);6await room.localParticipant?.setCameraEnabled(mode == CallMode.video);78// render remote video9final listener = room.createListener();10listener.on<lk.TrackSubscribedEvent>((e) {11 if (e.track is lk.VideoTrack) {12 setState(() => remote = e.track as lk.VideoTrack);13 }14});15// in build(): if (remote != null) lk.VideoTrackRenderer(remote!)1617// end the call18await room.disconnect();Chat
1// 1:1 or group chat rides the same connection2client.onMessage = (ChatMessage m) { /* append to the thread */ };34await client.sendMessage(toUserId: 'bob', text: 'Hey!');5final history = await client.messageHistory(conversationId, limit: 30);6final convos = await client.conversations();7client.setTyping(conversationId, true);8client.markRead(conversationId);registerDevice(), plus — on Xiaomi/Oppo/Vivo — Autostart enabled and battery set to “No restrictions” for your app, or the OS blocks the wake-up push.