# How Bitchat Android Handles File Transfers Over the Mesh Network

> Discover how Bitchat Android handles file transfers over its mesh network. Learn about packet wrapping, TLV encoding, and routing via BLE or Wi-Fi Aware for seamless data exchange.

- Repository: [permissionlesstech/bitchat-android](https://github.com/permissionlesstech/bitchat-android)
- Tags: how-to-guide
- Published: 2026-07-28

---

**TLDR:** Bitchat Android wraps every file in a `BitchatFilePacket`, TLV-encodes the payload, routes it through `UnifiedMeshService` as a `MessageType.FILE_TRANSFER` packet over BLE or Wi-Fi Aware, and reconstructs it on the remote side via `BitchatFilePacket.decode()`.

Bitchat Android enables decentralized peer-to-peer communication without relying on internet infrastructure. Its file transfer mechanism reuses the exact same mesh transport pipeline that carries text messages, ensuring consistency across the codebase. Understanding how Bitchat Android handles file transfers over the mesh network starts with tracing a file from the UI picker all the way to the remote device’s storage layer.

## From URI to Packet: Creating a BitchatFilePacket

When a user selects a file via the system content picker, the UI layer—coordinated by `MediaSendingManager` in [`app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt)—invokes `FileSharingManager.createFilePacketFromUri(context, uri, optionalName)`. This method copies the content to a temporary location using `FileUtils.copyFileForSending`, reads the raw bytes, and assembles a `BitchatFilePacket` instance.

The source of truth for this logic lives in [`app/src/main/java/com/bitchat/android/model/FileSharingManager.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/model/FileSharingManager.kt).

```kotlin
val packet = FileSharingManager.createFilePacketFromUri(context, uri, optionalName)

```

This single call bridges the UI layer and the domain model, returning a packet ready for serialization.

## TLV Encoding the File Payload

`BitchatFilePacket.encode()` converts the file metadata and content into a binary TLV byte array. Each field is prefixed with a 1-byte type identifier, followed by a length field—2 bytes for `filename`, `filesize`, and `mime-type`, and 4 bytes for the `content` payload.

Large files may generate multiple `CONTENT` TLVs, although the transport layer fragments packets at the MTU level when running over BLE. The encoder itself is implemented 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).

```kotlin
val encodedBytes = packet.encode()

```

The resulting byte array contains the fully self-describing structure needed for reconstruction on any mesh peer.

## Routing the Packet Through UnifiedMeshService

Once encoded, the payload is injected into the mesh core as a standard message. The caller passes `MessageType.FILE_TRANSFER` so that downstream nodes recognize the packet type correctly. `UnifiedMeshService.sendMessage(...)` abstracts the concrete transport and forwards the call to whichever backend is currently active.

According to the Bitchat Android source code, the two primary transport implementations are:

- `BluetoothMeshService` for BLE mesh links
- `WifiAwareMeshService` for Wi-Fi Aware links

Both implementations are located under `app/src/main/java/com/bitchat/android/mesh/`, with the Wi-Fi Aware variant residing in [`app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshService.kt).

```kotlin
meshCore.sendMessage(
    payload = encodedFile,
    type = MessageType.FILE_TRANSFER
)

```

This design means file transfers benefit from the same retry, discovery, and routing logic used for regular chat messages.

## Receiving and Decoding Files on the Remote Peer

Incoming packets land in `MessageHandler`, where the `MessageType` field is inspected. When the value equals `MessageType.FILE_TRANSFER`, the handler reconstructs the original packet with `BitchatFilePacket.decode(packet.payload)` and delegates file-system persistence to `FileSharingManager.processReceivedFile(..)`.

The return value is a `ReceivedFileInfo` object that carries the original filename, total size, MIME type, and raw `ByteArray`. The UI layer then surfaces a save or open action inside the chat bubble.

The relevant files are [`app/src/main/java/com/bitchat/android/mesh/MessageHandler.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/MessageHandler.kt) and [`app/src/main/java/com/bitchat/android/model/FileSharingManager.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/model/FileSharingManager.kt).

```kotlin
val filePacket = BitchatFilePacket.decode(packet.payload)
val fileInfo = FileSharingManager.processReceivedFile(filePacket)

```

Because decoding mirrors encoding exactly, the receiver rebuilds the identical structure that left the sender’s device.

## Canceling an Active File Transfer

Either peer can abort a transfer mid-flight by calling `meshService.cancelFileTransfer(transferId)`. `UnifiedMeshService` propagates the cancellation request to each concrete transport implementation, invoking `BluetoothMeshService.cancelFileTransfer` and `WifiAwareMeshService.cancelFileTransfer` as appropriate.

This ensures that buffers are released and partial files are discarded regardless of which radio path the packet was traversing.

```kotlin
val cancelled = meshService.cancelFileTransfer(transferId)
if (cancelled) Log.d("Transfer", "Cancelled $transferId")

```

The cancellation API lives alongside the send logic in [`app/src/main/java/com/bitchat/android/mesh/UnifiedMeshService.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/app/src/main/java/com/bitchat/android/mesh/UnifiedMeshService.kt).

## Summary

- Bitchat Android reuses its text-message mesh pipeline for **file transfers** by tagging packets with `MessageType.FILE_TRANSFER`.
- `FileSharingManager.createFilePacketFromUri()` and `BitchatFilePacket.encode()` handle packaging and TLV serialization in `app/src/main/java/com/bitchat/android/model/`.
- `UnifiedMeshService` routes encoded payloads through BLE or Wi-Fi Aware without exposing transport details to the UI.
- `MessageHandler` and `BitchatFilePacket.decode()` reconstruct the file into a `ReceivedFileInfo` object on the receiving peer.
- Transfers can be aborted at any time via `cancelFileTransfer()`, which reaches both `BluetoothMeshService` and `WifiAwareMeshService`.

## Frequently Asked Questions

### How does Bitchat Android avoid duplicating transport code for files versus text?

It reuses the same `UnifiedMeshService` infrastructure. Files are simply `BitchatPacket` instances whose `MessageType` is set to `FILE_TRANSFER`. The BLE and Wi-Fi Aware layers remain unaware of the payload content, so no separate file transport stack is required.

### What happens if a file is larger than the BLE MTU?

`BitchatFilePacket.encode()` structures the payload in TLV format, and the underlying transport—specifically `BluetoothMeshService`—fragments the byte stream at the MTU level. The code in [`BitchatFilePacket.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/BitchatFilePacket.kt) can emit multiple `CONTENT` TLVs, but in practice the transport handles segmentation transparently.

### Which class is responsible for converting a received byte array back into a usable file?

`MessageHandler` detects the `FILE_TRANSFER` type and calls `BitchatFilePacket.decode()`. It then passes the decoded packet to `FileSharingManager.processReceivedFile(..)`, which returns a `ReceivedFileInfo` containing the filename, MIME type, and raw bytes for the UI to save or open.

### Can a user cancel a file transfer after it has started?

Yes. The public API `meshService.cancelFileTransfer(transferId)` dispatches cancellation to the active transport implementations in `BluetoothMeshService` and `WifiAwareMeshService`, releasing resources and stopping the transfer on both ends.