The Bedrud Android app is built with Jetpack Compose and Kotlin, providing a native video meeting experience with picture-in-picture, deep linking, and multi-instance support.
Technology Stack
| Technology | Version | Purpose |
|---|---|---|
| Kotlin | 2.1.0 | Language |
| Jetpack Compose | Material 3 | UI toolkit |
| Koin | 4.0.0 | Dependency injection |
| Retrofit + OkHttp | Latest | HTTP client |
| LiveKit Android SDK | 2.23.3 | WebRTC media |
| Credentials API | Latest | Passkey support |
| Encrypted SharedPreferences | Latest | Secure storage |
| Coil | Latest | Image loading |
Target: Min SDK 28, Target SDK 35, JDK 17
Directory Structure
apps/android/app/src/main/java/com/bedrud/app/
├── BedrudApplication.kt # Application class (Koin init)
├── MainActivity.kt # Single-activity entry point
├── core/
│ ├── api/ # Retrofit API client
│ │ ├── ApiClient.kt # Base HTTP client with auth interceptor
│ │ ├── AuthApi.kt # Auth endpoint definitions
│ │ └── RoomApi.kt # Room endpoint definitions
│ ├── auth/
│ │ └── AuthManager.kt # Token management, login/logout
│ ├── call/
│ │ ├── CallService.kt # Foreground service for calls
│ │ └── CallConnectionService.kt # Android ConnectionService
│ ├── deeplink/
│ │ └── DeepLinkHandler.kt # Handle bedrud.com deep links
│ ├── di/
│ │ └── AppModule.kt # Koin module definitions
│ ├── instance/
│ │ ├── InstanceManager.kt # Central multi-instance orchestrator
│ │ ├── InstanceStore.kt # Persistent instance storage
│ │ └── InstanceDeps.kt # Per-instance dependency container
│ ├── livekit/
│ │ └── RoomManager.kt # LiveKit room connection manager
│ └── pip/
│ └── PipManager.kt # Picture-in-Picture controller
├── models/
│ ├── User.kt # User data model
│ ├── Room.kt # Room data model
│ ├── Instance.kt # Server instance model
│ └── ApiResponse.kt # API response wrappers
└── ui/
├── screens/
│ ├── auth/
│ │ ├── LoginScreen.kt # Email/password + passkey login
│ │ └── RegisterScreen.kt # Account registration
│ ├── dashboard/
│ │ └── DashboardScreen.kt # Room list and management
│ ├── meeting/
│ │ └── MeetingScreen.kt # Video call interface
│ ├── instance/
│ │ ├── AddInstanceScreen.kt # Add server instance
│ │ └── InstanceSwitcher.kt # Switch between instances
│ ├── profile/
│ │ └── ProfileScreen.kt # User profile
│ └── settings/
│ └── SettingsScreen.kt # App settings
├── components/ # Reusable Compose components
└── theme/ # Material 3 theme definition
Multi-Instance Architecture
The Android app supports connecting to multiple Bedrud servers simultaneously.
flowchart TB
subgraph IM ["InstanceManager (Koin singleton)"]
IS["InstanceStore<br/>Persists list to SharedPreferences"]
AI["Active Instance (StateFlow)"]
INST["instances: List Instance"]
end
subgraph DEPS ["InstanceDeps"]
AM["AuthManager"]
AC["ApiClient"]
AA["AuthApi"]
RA["RoomApi"]
PM["PasskeyManager"]
RM["RoomManager"]
end
AI */} DEPSKey Pattern
All per-instance dependencies are exposed as StateFlow<T?> on InstanceManager. Composables collect them:
val authManager = instanceManager.authManager.collectAsState().value ?: return
val roomApi = instanceManager.roomApi.collectAsState().value ?: returnThe ?: return pattern ensures the composable doesn’t render until the instance is fully initialized.
Navigation Flow
flowchart LR
A["No instances"] */} B[AddInstanceScreen]
C["Has instances, not logged in"] */} D[LoginScreen]
E["Has instances, logged in"] */} F[DashboardScreen]The instance switcher appears as a ModalBottomSheet triggered from the Dashboard toolbar.
Features
Surface produit (ce que les utilisateurs obtiennent)
| Zone | Comportement |
|---|---|
| Auth | Connexion / inscription (et passkeys si pris en charge) |
| Tableau de bord | Liste des salles ; salles récentes après une jointure |
| Deep links | Les URL de salle collées / ouvertes résolvent la bonne salle |
| Réunion | Rejoindre, couper le micro, quitter ; chrome de contrôles utilisable |
| Scène / partage | Overlay de scène et chemin de partage d’écran quand l’appareil le permet |
| Telecom | Connexion d’appel gérée en propre ; la déconnexion termine la réunion proprement |
| RTL | Locales fa / ar avec Shabnam — le chrome ne doit pas être rogné |
Les concepts produit partagés (scène, chat, tableau blanc sur le web) sont documentés sous Utiliser Bedrud. La parité de fonctions avec le web peut varier selon la version.
Deep Linking
The app handles URLs matching:
https://bedrud.com/m/*- Direct room joinhttps://bedrud.com/c/*- Room join by code
Configured via intent filters in AndroidManifest.xml. Room URL parsing (BedrudURLParser and related) should open the correct room from a paste or external link.
Call Management
- CallService - Foreground service that keeps the connection alive during calls
- CallConnectionService - Integrates with Android’s telephony framework for proper call UI
- Required permissions:
MANAGE_OWN_CALLS,FOREGROUND_SERVICE_PHONE_CALL,FOREGROUND_SERVICE_CAMERA,FOREGROUND_SERVICE_MICROPHONE
Picture-in-Picture
The meeting screen supports PiP mode, allowing users to see the video feed while using other apps.
Passkeys
Uses Android’s Credentials API for FIDO2/WebAuthn passkey registration and login.
Building
# Debug APK
make build-android-debug
# Release APK (requires keystore.properties)
make build-android
# Build + install on connected device
make release-android
# Open in Android Studio
make dev-androidRelease Signing
Release builds require a keystore.properties file in the android project root with your signing configuration.