A peer-to-peer chat app that works without the internet. Devices on the same local network discover each other with Android's Network Service Discovery (NSD/mDNS), then one device hosts a chat room over a raw TCP socket while the others join it. Recent rooms are remembered locally with Room, so you can find them again quickly.
- No server required — chat runs over your LAN via mDNS discovery + TCP sockets.
- Host a room or join one from the discovered devices list.
- Real-time message feed with a simple send/receive client and server.
- Device list persisted locally with Room.
- MVVM architecture with Hilt dependency injection and Jetpack Navigation.
![]() |
![]() |
|---|
The reusable parts live in the :offlinechat-core library module, while :app is a thin
demo application on top of it:
offlinechat-core/ # reusable library (:offlinechat-core)
└── src/main/java/org/turkiye/offlinechat/
├── data/
│ ├── entity/ # Room entities
│ ├── local/ # Room database, DAOs, type converters
│ ├── model/ # network/UI models
│ └── remote/ # Retrofit API (optional REST layer)
├── di/ # Hilt modules (Api, App, Database)
├── interfaces/ # discovery / room / click listeners
├── repository/ # UsersRepository
└── util/ # constants, extensions, IP helpers
app/ # demo application (:app)
└── src/main/java/org/turkiye/offlinechat/
├── App.kt
└── ui/
├── activitys/ # MainActivity
├── adapters/ # RecyclerView / Array adapters
├── dialogs/ # join dialog
└── fragments/ # main / client / server fragments + view models
The app follows MVVM: fragments observe LiveData exposed by @HiltViewModel
view models, which delegate to repositories backed by Room and the network layer.
- Kotlin + Coroutines / Flow
- Hilt (Dagger) for dependency injection
- Room for local persistence (schema exported to
offlinechat-core/schemas) - Retrofit + OkHttp for the optional REST layer
- Jetpack Navigation for in-app navigation
- ViewBinding for type-safe view access
The app requests WiFi/network permissions so that mDNS discovery and the local socket server can operate:
INTERNET, ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE, CHANGE_WIFI_STATE,
CHANGE_WIFI_MULTICAST_STATE, NEARBY_WIFI_DEVICES.
All devices must be on the same network.
| Tool | Version |
|---|---|
| minSdk | 24 |
| compileSdk / targetSdk | 36 |
| Gradle | 8.14.5 |
| Android Gradle Plugin | 8.13.2 |
| Kotlin | 2.2.21 |
| JDK | 17 |
./gradlew assembleDebug # debug APK
./gradlew assembleRelease # release APKThe data, repository and dependency-injection layers are packaged as the
:offlinechat-core Android library (com.ferhatozcelik:offlinechat-core). Publish it to
your local Maven repository and consume it from another project:
./gradlew :offlinechat-core:publishToMavenLocal -PVERSION_NAME=1.0.0repositories {
mavenLocal()
}
dependencies {
implementation("com.ferhatozcelik:offlinechat-core:1.0.0")
}Ferhat OZCELIK
- GitHub: @ferhatozcelik
- LinkedIn: ferhatozcelik
Apache License 2.0 — see LICENSE. If this project helped you, give it a ⭐️.

