Skip to content

feat: add BLE peripheral mode (advertising + GATT server)#18

Open
alachhman wants to merge 3 commits into
zykeco:mainfrom
alachhman:feat/peripheral-mode
Open

feat: add BLE peripheral mode (advertising + GATT server)#18
alachhman wants to merge 3 commits into
zykeco:mainfrom
alachhman:feat/peripheral-mode

Conversation

@alachhman
Copy link
Copy Markdown

Summary

  • Adds complete BLE peripheral mode API alongside existing central mode
  • iOS: CBPeripheralManager with delegate, GATT service/characteristic management, 60s native value cache for background resilience
  • Android: BluetoothLeAdvertiser + BluetoothGattServer with full callback handling, CCCD descriptor management
  • JS: Full BleNitroManager wrapper methods with ByteArray conversion
  • Expo config plugin already supports peripheral permissions — no plugin changes needed

API Added

  • startAdvertising(serviceUUIDs, localName) / stopAdvertising() / isAdvertising()
  • addService(uuid, isPrimary, characteristics) / removeService(uuid) / removeAllServices()
  • updateCharacteristicValue(serviceUUID, charUUID, data) — native-side 60s cache
  • onReadRequest(callback) / onWriteRequest(callback) — JS callbacks for dynamic characteristics
  • respondToRequest(requestId, status, offset, data) — async response to pending requests
  • notifyCharacteristic(serviceUUID, charUUID, data) — push to subscribed centrals
  • peripheralState() / subscribeToPeripheralStateChange(callback)

New Types

  • GATTCharacteristicProperty enum (Read, Write, WriteWithoutResponse, Notify, Indicate)
  • GATTCharacteristicPermission enum (Readable, Writeable)
  • GATTCharacteristicConfig interface
  • ReadRequestCallback / WriteRequestCallback types

Design Notes

  • Characteristics with value: null trigger onReadRequest JS callback (dynamic values)
  • Characteristics with a non-null value are served directly by the native BLE stack (static values)
  • iOS: Background advertising preserves service UUID only (OS strips custom data); GATT reads still work
  • Android: ADVERTISE_MODE_LOW_POWER default; BLUETOOTH_ADVERTISE permission via existing androidAdvertisingEnabled config flag
  • Native-side 60s TTL cache shields against JS runtime suspension in background

Test Plan

  • 11 new unit tests for peripheral JS manager methods (all pass)
  • All 23 existing central-mode tests still pass (34 total)
  • iOS foreground: advertise + GATT read from another device
  • Android foreground: advertise + GATT read from another device
  • Cross-platform: iOS advertise ↔ Android scan (and vice versa)
  • iOS background: advertising continues, GATT reads succeed

🤖 Generated with Claude Code

Anthony and others added 3 commits April 16, 2026 11:59
- Add GATTCharacteristicProperty, GATTCharacteristicPermission enums
- Add GATTCharacteristicConfig, ReadRequestCallback, WriteRequestCallback types
- Add 14 peripheral methods to NativeBleNitro interface
- Add JS wrapper methods to BleNitroManager (advertising, GATT, requests)
- Add 11 new unit tests for peripheral mode
- Export new types from package index

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
iOS:
- CBPeripheralManager with BleGattServerDelegate
- GATT service/characteristic construction from config
- Read request handling with 60s native value cache
- Write request forwarding to JS callbacks
- Central subscription tracking for notifications
- Background advertising support via state restoration

Android:
- BluetoothLeAdvertiser with LOW_POWER mode
- BluetoothGattServer with full callback handling
- Read request cache (60s TTL) with JS fallback
- Write request forwarding with ArrayBuffer wrapping
- CCCD descriptor management for notify/indicate
- Lazy GATT server initialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant