# How Bitchat Android Manages Peer-to-Peer File Sharing: A Deep Dive into the Mesh Networking Implementation

> Discover how Bitchat Android's three-layer architecture enables secure peer-to-peer file sharing over BLE or Wi-Fi Aware. Explore the mesh networking implementation.

- Repository: [permissionlesstech/bitchat-android](https://github.com/permissionlesstech/bitchat-android)
- Tags: deep-dive
- Published: 2026-08-04

---

**Bitchat Android implements end-to-end encrypted peer-to-peer file sharing through a three-layer architecture that separates UI coordination, mesh core logic, and transport-specific delivery over BLE or Wi-Fi Aware.**

According to the [permissionlesstech/bitchat-android](https://github.com/permissionlesstech/bitchat-android) source code, peer-to-peer file sharing is built on top of a unified mesh networking stack that automatically handles fragmentation, encryption, and transport selection. This article examines how the components work together to deliver files without centralized servers.

## The Three-Layer Architecture

Bitchat Android splits file sharing into distinct responsibilities:

| Layer | Primary Class | Responsibility |
|-------|-------------|--------------|
| **UI Layer** | [`MediaSendingManager.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/MediaSendingManager.kt) | Collects file data, initiates preparation, commits transfers |
| **Mesh Core** | [`UnifiedMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/UnifiedMeshService.kt) / [`MeshCore.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/MeshCore.kt) | Selects transport, fragments files, manages encryption |
| **Transport** | [`BluetoothMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/BluetoothMeshService.kt) / [`WifiAwareMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/WifiAwareMeshService.kt) | Delivers packets over radio and handles cancellation |

This separation allows the app to support multiple transports while presenting a unified API to the UI layer.

## File Payload Representation with TLV Encoding

Files are encoded using **`BitchatFilePacket`**, which structures metadata and content into a Type-Length-Value (TLV) format defined in [[`/app/src/main/java/com/bitchat/android/model/BitchatFilePacket.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main//app/src/main/java/com/bitchat/android/model/BitchatFilePacket.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/model/BitchatFilePacket.kt).

The encoding scheme uses variable-length fields:

- **Standard TLVs**: 2-byte length fields for metadata (filename, MIME type, size)
- **CONTENT TLV**: 4-byte length field to support large file chunking (up to 65,535 bytes per chunk)

The decoder tolerates unknown TLV types and concatenates multiple `CONTENT` TLVs, ensuring forward compatibility with future protocol versions.

## Preparing a Private File Transfer

When a user selects a file, `MediaSendingManager` initiates preparation through the mesh service:

```kotlin
val preparation = meshService.prepareFilePrivate(
    recipientPeerID = peerId,
    file = filePacket,
    transferId = UUID.randomUUID().toString(),
    allowLegacyFallback = false
)

```

Underneath this call, `MeshCore.prepareFilePrivate` (accessed via `UnifiedMeshService`) delegates to `PrivateMediaTransferPreparer`. This preparer:

1. Builds TLV fragments from the file packet
2. Signs each packet for authenticity
3. Returns a **`PrivateMediaPreparation.Ready`** containing a `commit()` lambda

The `commit()` lambda dispatches routed packets through `MeshTransport`, which handles any additional fragmentation required by the underlying BLE or Wi-Fi link. The implementation in [`MeshCore.kt#L61-L84`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/MeshCore.kt#L61-L84) ensures packets are ready before any radio transmission begins.

## Transport Selection and Commit

`UnifiedMeshService` determines whether to use Bluetooth Low Energy or Wi-Fi Aware based on peer readiness, as shown in [`UnifiedMeshService.kt#L87-L106`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/UnifiedMeshService.kt#L87-L106):

```kotlin
// Simplified logic from the source
if (bluetooth.isPeerReady(recipientPeerID)) {
    bluetooth.prepareFilePrivate(...)
} else if (wifiService?.isPeerReady(recipientPeerID) == true) {
    wifiService.prepareFilePrivate(...)
}

```

Once the UI receives a `Ready` object, `MediaSendingManager` calls `commitPreparedPrivateFile`. This function:

- Creates a local echo message for UI feedback
- Stores the `transferId ↔ messageId` mapping
- Invokes `preparation.transfer.commit()` to begin actual transmission

The UI updates to "sent" status on success, or marks the echo failed if the commit errors out [(`MediaSendingManager.kt#L50-L68`)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt#L50-L68).

## End-to-End Encryption Requirements

All file fragments are encrypted with the **Noise protocol**. `MeshCore` enforces that a Noise session exists before allowing `prepareFilePrivate` to proceed:

```kotlin
// From MeshCore.kt#L460-L470
require(hasEstablishedSession(peerId)) {
    "No Noise session established with peer $peerId"
}

```

If missing, the UI layer automatically triggers `meshService.initiateNoiseHandshake(peerId)` before retrying the file preparation. This ensures no unencrypted file data ever reaches the transport layer.

## Cancellation Flow

Users can abort transfers through a unified cancellation API:

```kotlin
val cancelled = meshService.cancelFileTransfer(transferId)

```

The request propagates:

1. `UnifiedMeshService.cancelFileTransfer` → both BLE and Wi-Fi services
2. Each transport removes pending fragments from its send queue
3. Success is reported if either transport acknowledges cancellation

Both `BluetoothMeshService` and `WifiAwareMeshService` implement `cancelFileTransfer(transferId)` by forwarding to their underlying `MeshTransport` implementations [(`BluetoothMeshService.kt#L942-L1000`)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt#L942-L1000).

## Complete File Sharing Example

Here's the full workflow combining all layers:

```kotlin
// 1. Build file packet from raw bytes
val fileBytes = Files.readAllBytes(Paths.get("/sdcard/Download/photo.jpg"))
val filePacket = BitchatFilePacket(
    fileName = "photo.jpg",
    fileSize = fileBytes.size.toLong(),
    mimeType = "image/jpeg",
    content = fileBytes
)

// 2. Request encrypted private transfer preparation
val transferId = UUID.randomUUID().toString()
val prep = meshService.prepareFilePrivate(
    recipientPeerID = peerId,
    file = filePacket,
    transferId = transferId,
    allowLegacyFallback = false
)

// 3. Commit when ready (typically inside a coroutine)
when (prep) {
    is PrivateMediaPreparation.Ready -> {
        // Creates local echo, then transmits
        mediaSendingManager.commitPreparedPrivateFile(prep, transferId)
    }
    is PrivateMediaPreparation.NeedsHandshake -> {
        meshService.initiateNoiseHandshake(peerId)
        // Retry after handshake completes
    }
}

// 4. Cancel if user aborts
val cancelled = meshService.cancelFileTransfer(transferId)

```

## Key Implementation Files

| File | GitHub Path | Role |
|------|-------------|------|
| [`BitchatFilePacket.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/BitchatFilePacket.kt) | [[`model/BitchatFilePacket.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/model/BitchatFilePacket.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/model/BitchatFilePacket.kt) | TLV serialization |
| [`MeshCore.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/MeshCore.kt) | [[`mesh/MeshCore.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/mesh/MeshCore.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/MeshCore.kt) | Encryption, preparation orchestration |
| [`UnifiedMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/UnifiedMeshService.kt) | [[`mesh/UnifiedMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/mesh/UnifiedMeshService.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/UnifiedMeshService.kt) | Public API, transport selection |
| [`BluetoothMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/BluetoothMeshService.kt) | [[`mesh/BluetoothMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/mesh/BluetoothMeshService.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt) | BLE transport |
| [`WifiAwareMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/WifiAwareMeshService.kt) | [[`wifi-aware/WifiAwareMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/wifi-aware/WifiAwareMeshService.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshService.kt) | Wi-Fi Aware transport |
| [`MediaSendingManager.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/MediaSendingManager.kt) | [[`ui/MediaSendingManager.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/ui/MediaSendingManager.kt)](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt) | UI coordination |

## Summary

- **Bitchat Android** uses a layered architecture for peer-to-peer file sharing: UI (`MediaSendingManager`), mesh core (`UnifiedMeshService`/`MeshCore`), and transport (`BluetoothMeshService`/`WifiAwareMeshService`).
- **TLV encoding** in `BitchatFilePacket` handles metadata and chunked content with forward-compatible parsing.
- **Noise protocol encryption** is mandatory—`prepareFilePrivate` requires an established session or triggers automatic handshake.
- **Transport-agnostic preparation** allows seamless fallback between BLE and Wi-Fi Aware without UI changes.
- **Unified cancellation** propagates through all layers to stop transfers cleanly.

## Frequently Asked Questions

### What transport protocols does Bitchat Android use for file sharing?

Bitchat Android supports **Bluetooth Low Energy (BLE)** and **Wi-Fi Aware** as transport protocols. The `UnifiedMeshService` automatically selects between them based on peer readiness, falling back to whichever connection is available. Both transports implement the same interface for fragmentation, sending, and cancellation.

### How large can files be in Bitchat's peer-to-peer sharing?

The TLV encoding supports large files through chunked `CONTENT` fields with 4-byte length headers (max 65,535 bytes per chunk). Multiple `CONTENT` TLVs are concatenated during decoding, so practical limits depend on available storage and transfer time rather than protocol constraints.

### Is file sharing in Bitchat Android encrypted?

Yes—all file transfers use **end-to-end encryption via the Noise protocol**. [`MeshCore.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/MeshCore.kt) enforces that a Noise session exists before `prepareFilePrivate` succeeds. If no session exists, the UI automatically initiates a handshake. No file data is transmitted without encryption.

### Can users cancel file transfers mid-send?

Yes. Calling `meshService.cancelFileTransfer(transferId)` propagates to both BLE and Wi-Fi Aware transports, which remove pending fragments from their send queues. The cancellation succeeds if either transport acknowledges it, ensuring no orphaned transmissions continue.