The official Android client for Bedrud — a self-hostable, LiveKit-powered video meeting platform.
This app is a pure client. It doesn't run a server; you point it at one or more Bedrud
server instances (https://your-server/api) and it handles auth, rooms, and live meetings.
For the server, web app, and other platforms, see the main Bedrud project.
- Video & audio meetings — WebRTC rooms powered by the LiveKit Android SDK
- Connect to multiple servers — add several Bedrud instances and switch between them; each keeps its own login
- Add a server by QR — scan a Bedrud server's QR code to fill in its URL instead of typing it
- Meetings as real calls — joining starts a self-managed telecom call, so meetings get proper audio routing, a call notification with mute/hangup, and survive backgrounding
- Screen off at your ear — with the call on the earpiece, covering the proximity sensor blanks the screen and ignores touches, so a cheek cannot press anything
- Picture-in-Picture — keep the meeting visible while using other apps
- Screen sharing — several people can present at once, and watching a stream is opt-in per viewer
- In-meeting chat over the LiveKit data channel — messages grouped by sender, emoji reactions with a breakdown of who reacted, tappable links, copying or sharing a message to any other app, polls to vote in, and image sharing with any received picture savable to the gallery
- Meeting sounds — a chime when someone joins or leaves and a pop when a message arrives, played on the call's own audio route
- Push to talk & voice sensitivity — hold-to-talk input mode, a manual voice gate for voice activity, per-person volume, and device noise suppression
- Admin moderation — kick and ban controls for room hosts
- Flexible sign-in — email/password, guest access, OAuth, and FIDO2 passkeys
- Localized — 10 languages with right-to-left (Arabic, Persian) support
- Android 9 (API 28) or newer
- One or more reachable Bedrud server instances
- Install the app (build it yourself — see below — or grab a release APK).
- On first launch, choose a server — continue with the default public server, or enter your own Bedrud server URL. You can add more servers and switch between them later.
- Sign in (or join as a guest), then create or join a room.
You'll need the Android SDK and JDK 17. Android Studio (latest stable) is the easiest path — open the project and let it sync.
From the command line:
# Debug APK
./gradlew assembleDebug
# Release APK (requires a keystore, see below)
./gradlew assembleRelease
# Run unit tests
./gradlew testDebug APKs land in app/build/outputs/apk/. Builds are split per ABI
(arm64-v8a, armeabi-v7a, x86_64) with a universal APK also produced.
A root Makefile wraps the commands above, plus the device, CI-parity, and release
steps. It only launches gradlew, adb, git and gh — nothing is reimplemented, so
the Gradle commands stay valid if you prefer them.
make help # every target, grouped
make doctor # check JDK / SDK / adb / gh, and whether signing is configured
make build # debug APKs
make build-dev # dev APKs — install side by side with the real app
make build-release # release APKs
make install # build + install debug (also: install-dev, uninstall, run)
make logcat # tail logcat for this app only
make check # lint + unit tests — exactly what CI gates a PR on
make cleanBuilds accept SERVER=<host> as a shorthand for -PdefaultServerHost (see below), e.g.
make build-dev SERVER=staging.example.com.
Releases are cut from git tags — there is no version number stored in the repo (see Versioning):
make version # current tag, next patch/minor/major, release state
make tag-patch # create the next tag locally (also: tag-minor, tag-major)
make tag-push # push it
make release-beta TAG=1.3.1 # dispatch the signed release workflow for that tag
make release-stable TAG=1.3.1 # …or promote it to stable
make release-status # recent release runsOn Windows, run these from Git Bash or WSL. make isn't bundled with Git for Windows —
install it with winget install ezwinports.make or scoop install make.
versionName and versionCode are not stored in the repo. versionCode comes from the
CI run number and versionName from the tag the release workflow was dispatched against,
both passed to Gradle as -P flags (see app/build.gradle.kts). So the git tag is the
single source of truth, and nothing needs a manual bump — make tag-patch and friends
create tags, they don't edit files.
Building and signing a release happens only in .github/workflows/release.yml, which is
dispatched manually against a tag, gated on lint and unit tests passing for that exact
commit, and on approval from the beta-signing / production-signing environments. The
make release-* targets start that run; they never sign anything locally.
The Add Instance screen pre-fills bedrud.xyz as the server host. To ship a build that
defaults to a different instance (for example a staging or self-hosted deployment), pass
-PdefaultServerHost at build time — no code changes needed:
./gradlew assembleRelease -PdefaultServerHost=meet.example.comThe value is baked into BuildConfig.DEFAULT_SERVER_HOST; when the flag is omitted, builds
fall back to bedrud.xyz. Users can still change the host on the Add Instance screen either way.
For a signed release build, create a keystore.properties file in the project root:
storeFile=/path/to/your.keystore
storePassword=...
keyAlias=...
keyPassword=...If the file is absent, release builds are simply left unsigned.
Single-module Kotlin app (com.bedrud.app) built with Jetpack Compose and Material 3.
There are no ViewModels — screen state lives in MutableStateFlow on manager classes and
is collected with collectAsState().
| Concern | Choice |
|---|---|
| UI | Jetpack Compose + Material 3 |
| DI | Koin |
| Networking | Retrofit + OkHttp (Gson) |
| Realtime media | LiveKit Android SDK |
| Calls | Self-managed telecom ConnectionService (foreground service) |
| Auth storage | EncryptedSharedPreferences, per instance |
| Passkeys | AndroidX Credential Manager + Play Services FIDO |
| Images | Coil |
Multi-instance is the spine of the app. InstanceManager rebuilds the auth manager,
Retrofit APIs, and the LiveKit RoomManager for whichever server is active, and the UI
reacts to the swap. This is why every login, room list, and meeting is scoped to a server.
Source layout (app/src/main/java/com/bedrud/app/):
core/
api/ Retrofit services + DTOs
auth/ login, tokens, passkeys
call/ telecom ConnectionService (meetings-as-calls)
chat/ in-meeting chat
deeplink/ /m/ and /c/ link handling
di/ Koin modules
instance/ multi-server management
livekit/ RoomManager — LiveKit lifecycle
meeting/ meeting logic (chat wire, video aspect)
pip/ picture-in-picture state
recent/ recent rooms
ui/
components/ shared Compose widgets
screens/ auth, dashboard, instance, main, meeting, admin, profile, settings
theme/ colors, typography
- AGENTS.md — developer guide and conventions
- DESIGN.md — design system notes
- CONTRIBUTING.md — how to contribute
- README-OLD.md — the original monorepo README (full-stack Bedrud), kept for reference
Apache-2.0. See NOTICE for attributions.