ble_peer_session 0.3.0 copy "ble_peer_session: ^0.3.0" to clipboard
ble_peer_session: ^0.3.0 copied to clipboard

Offline BLE peer-to-peer sessions for Flutter — discovery, consent handshake, and bidirectional messaging.

ble_peer_session #

Offline BLE peer-to-peer sessions for Flutter: discovery, consent handshake, and bidirectional messaging for local games and chat.

Scope: 1:1 only (one host + one client). No Wi‑Fi or internet required.


15-second start #

Host — wait for a friend #

import 'package:ble_peer_session/ble_peer_session.dart';

final peer = Peer.create(appName: 'MyGame');

final host = await peer.host(
  localUser: PeerUser(id: 'me', displayName: 'Alice'),
);

host.messagesStream.listen((message) {
  if (message.type == PeerMessageTypes.sessionInvite) {
    host.accept(); // friend wants to join
  }
});

await host.sendText('Room is ready');
host.textMessages.listen(print);

Client — find host and say hello #

final peer = Peer.create(appName: 'MyGame');

final client = await peer.client(
  localUser: PeerUser(id: 'me', displayName: 'Bob'),
);

client.nearbyHostsStream.listen((hosts) {
  if (hosts.isEmpty) return;
  client.invite(hosts.first); // sends invite, not "BLE connect"
});

client.textMessages.listen(print);
await client.sendText('Hello!');

That is the whole mental model:

Step Host Client
Start peer.host(localUser: …) peer.client(localUser: …)
Find peer waits nearbyHostsStream
Connect accept() on invite invite(host)
Chat sendText() / textMessages same

No UUIDs. No PeerEndpoint. No type/payload unless you need custom game data.


Table of contents #

  1. Two API levels
  2. Mental model
  3. Setup
  4. Connection flow
  5. Custom messages (advanced)
  6. Bluetooth adapter
  7. Errors
  8. Android setup
  9. Migration guides

Two API levels #

Concept API
Entry Peer.create(appName: 'MyGame') — UUIDs generated automatically
Who am I PeerUser(id: '…', displayName: '…')
Host await peer.host(localUser: user)
Client await peer.client(localUser: user)
Nearby friend PeerNearby in nearbyHostsStream
Connect client.invite(host)
Text chat sendText() / textMessages
Game JSON sendJson('game.move', {'row': 1}) / jsonMessages

Level 2 — advanced (full control) #

Concept API
Custom UUIDs Peer.create(config: BlePeerConfig(...), logger: logger)
Wire endpoint startWithEndpoint / startDiscoveryWithEndpoint
Raw device connect(device)
Any payload PeerMessage.app(type: '…', payload: …)
Session types PeerMessageTypes.sessionInvite, etc.

Mental model #

Think in people and invitations, not BLE:

flowchart LR
  Host[Host waits]
  Client[Client scans]
  Invite[Client invites]
  Accept[Host accepts]
  Chat[sendText / sendJson]

  Host --> Invite
  Client --> Invite
  Invite --> Accept
  Accept --> Chat

Under the hood: advertising, GATT, JSON frames — you never need to touch that for basic use.


Setup #

final peer = Peer.create(appName: 'MyGame');

// Optional: check Bluetooth before starting
if (peer.adapterStatus == PeerAdapterStatus.disabled) {
  // show "Enable Bluetooth" UI
}

// Android 12+
await peer.permissions.checkPermissions();

Custom UUIDs (only if you know why):

final peer = Peer.create(
  config: BlePeerConfig(
    appName: 'MyGame',
    serviceUuid: '0000180d-0000-1000-8000-00805f9b34fb',
    characteristicUuid: '00002a37-0000-1000-8000-00805f9b34fb',
  ),
  logger: myLogger,
);

Connection flow #

sequenceDiagram
  participant Host
  participant Client

  Host->>Host: peer.host(localUser)
  Client->>Client: peer.client(localUser)
  Client->>Host: invite(host)
  Note over Host: sessionInvite message
  Host->>Client: accept()
  Note over Host,Client: connected
  Client->>Host: sendText("Hello")

Phases (connectionStreamPeerConnectionPhase):

  • waitingForPeer — host advertising / client browsing
  • awaitingUserDecision — host sees invite, call accept() or reject()
  • awaitingRemoteDecision — client sent invite, waiting
  • connected — send messages

Custom messages (advanced) #

// Typed app message
await host.sendJson('game.move', {'row': 1, 'column': 2});

// Or full control
await host.send(
  PeerMessage.app(
    sender: host.localEndpoint!,
    type: 'game.move',
    payload: {'row': 1, 'column': 2},
  ),
);

Reserved session types (PeerMessageTypes.*) are handled automatically during handshake.


Bluetooth adapter #

The package does not turn Bluetooth on. Observe status and guide the user:

peer.adapterStatusStream.listen((status) {
  switch (status) {
    case PeerAdapterStatus.disabled:
      // prompt user
    case PeerAdapterStatus.enabled:
      // ready
    default:
      break;
  }
});

Errors #

All failures throw PeerException with PeerErrorCode. See doc/ERROR_CODES.md.


Android setup #

Add to AndroidManifest.xml:

<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

Migration guides #

  • 0.1.x → 0.2.0
  • 0.2.x → 0.3.0

License #

MIT

1
likes
0
points
625
downloads

Publisher

unverified uploader

Weekly Downloads

Offline BLE peer-to-peer sessions for Flutter — discovery, consent handshake, and bidirectional messaging.

Repository (GitHub)
View/report issues

Topics

#bluetooth #ble #flutter #p2p #peer-to-peer

License

unknown (license)

Dependencies

bluetooth_low_energy, device_info_plus, flutter, flutter_blue_plus, meta, permission_handler, url_launcher

More

Packages that depend on ble_peer_session