Skip to content

Confirming iOS limitations: writeCharacteristic, subscribeToCharacteristic, unsubscribeFromCharacteristic (central) and GATT read/write request handling (peripheral) — are these intentionally not yet implemented? #35

@MaganAnkur

Description

@MaganAnkur

Hi, first thanks for the work on this library — the Nitro-based architecture is great.

I'm evaluating munim-bluetooth@0.3.27 for a project that needs bidirectional BLE between iOS and Android (iOS↔iOS, iOS↔Android, Android↔iOS, Android↔Android, in any role). I'd like to confirm a few things I observed by reading the source. I'm not opening these as bug reports — just asking for confirmation and roadmap context.

1. iOS central — writeCharacteristic returns "Not implemented"

In ios/HybridMunimBluetooth.swift lines 476-480, the implementation appears to be a stub:

func writeCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String, value: String, writeType: WriteType?) throws -> Promise<Void> {
    let promise = Promise<Void>()
    promise.reject(withError: NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Not implemented"]))
    return promise
}

I confirmed at runtime that calling writeCharacteristic(...) from JS on iOS rejects with Error Domain=MunimBluetooth Code=1 "Not implemented" immediately, before any CoreBluetooth call.

Question: Is iOS writeCharacteristic intentionally left as a stub for this version? Is full CBCharacteristicWriteType.withResponse / .withoutResponse support planned, and if so, what's the rough timeline?

2. iOS central — subscribeToCharacteristic and unsubscribeFromCharacteristic are no-ops

ios/HybridMunimBluetooth.swift lines 482-488:

func subscribeToCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws {
    // Not implemented
}

func unsubscribeFromCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws {
    // Not implemented
}

These functions silently return without calling peripheral.setNotifyValue(true, for: characteristic). The characteristicValueChanged event documented in the README also seems to have no emit path on iOS as a result.

Question: Is iOS notification/indication support planned? Is there a workaround you'd suggest in the meantime (polling reads, etc.)?

3. iOS peripheral — missing GATT request handlers

In ios/HybridMunimBluetooth.swift, the PeripheralManagerDelegateProxy (lines 16-38) implements only:

  • peripheralManagerDidUpdateState
  • peripheralManagerDidStartAdvertising
  • peripheralManager(_:didAdd:error:)
  • peripheralManager(_:willRestoreState:)

It does not implement:

  • peripheralManager(_:didReceiveRead:)
  • peripheralManager(_:didReceiveWrite:)
  • peripheralManager(_:central:didSubscribeTo:)
  • peripheralManager(_:central:didUnsubscribeFrom:)
  • peripheralManagerIsReady(toUpdateSubscribers:)

A repo-wide grep for didReceiveRead, didReceiveWrite, CBATTRequest, and respond(to: returns zero matches across the iOS source.

Per Apple's CoreBluetooth contract, without these handlers the peripheral cannot respond to incoming GATT operations from a connected central — CoreBluetooth will reject reads/writes regardless of the properties set on the CBMutableCharacteristic.

Question: Is iOS peripheral GATT request handling planned? Or is the iOS peripheral intentionally limited to advertising only (since iOS-as-peripheral has heavy Apple-imposed background restrictions anyway)?

4. Documentation — should the README disclose the iOS gaps?

The README currently lists writeCharacteristic, subscribeToCharacteristic, unsubscribeFromCharacteristic, and peripheral GATT operations as supported features (under "🚀 Features" → "Real-time Communication: Support for read, write, and notify operations"), without flagging the iOS-vs-Android disparity. New users who don't read the Swift source will likely hit the same surprise I did — only finding out at runtime when their write fails.

Question: Would you be open to a PR that adds an "iOS support matrix" section to the README, listing exactly which functions are currently iOS-supported, Android-supported, or both? I'm happy to put that together.

5. Other behavioral observations (lower priority — happy to file separately if you'd prefer)

While testing I also hit:

  • connect() has no internal timeout on either platform — if the peripheral doesn't respond, no callback fires and the Nitro Promise<Void> is eventually destroyed with the cryptic error Error: Timeouted: Promise<()> was destroyed!. Workaround: wrap in a JS-side Promise.race with disconnect() cleanup.
  • On iOS, CBPeripheral references cached in discoveredPeripherals[deviceId] can become stale after stopScan(), causing connect() to silently hang forever. Workaround: re-scan briefly to refresh the reference before connecting.
  • ScanCallback.onScanFailed(errorCode:) on Android (Kotlin file lines 350-353) only logs to logcat; nothing is emitted to JS, so failures like SCAN_FAILED_SCANNING_TOO_FREQUENTLY are invisible to the app.
  • Android restartAdvertising (Kotlin lines 645-668) packs flags + 128-bit UUID + local name + TX power into a single primary advertisement, which exceeds the 31-byte limit for most realistic combinations. Result is onStartFailure(1) (DATA_TOO_LARGE) logged to logcat; JS thinks advertising started. A setScanResponseData() split would help.
  • Android stopAdvertising does not appear to call BluetoothGattServer.removeService() or clearServices(), so each Stop → Start cycle accumulates services. After 3 cycles a connected central sees 3 copies of the same service in discoverServices.

Question: Are any of these on your radar already? Want me to file them as separate issues or batch into a follow-up?


Thanks again — the library has real promise, I'd just like clarity on what's safe to depend on right now and what's coming next so I can plan around it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions