Skip to content

Neutral API support tables, pairing notes, and Apple/Web pairing-state fix - #343

Merged
fotiDim merged 13 commits into
mainfrom
docs/api-support-icons
Oct 14, 2026
Merged

fotiDim merged 13 commits into
mainfrom
docs/api-support-icons

Conversation

@fotiDim

@fotiDim fotiDim commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Makes the API Support tables in README.md accurate and easier to read, and fixes Apple/Web onPairingStateChange, which the tables previously described incorrectly.

API tables

  • Neutral "not supported" marker. Replaced the red ❌ with a neutral em dash (—), matching universal_bluetooth_classic, and placed the legend above the tables so the markers are defined before their first use.
  • Clarified the ⏺ marker. It now means partial support (see notes) instead of the vague "platform-dependent".
  • Corrected unpair on iOS. It was —, but iOS 18+ removes accessories authorized through AccessorySetupKit, so it is now ⏺ with a note. macOS and Web remain —.
  • Corrected isPaired on iOS/macOS/Web. Now ⏺: it needs a pairingCommand and otherwise returns null (and triggers pairing as a side effect).

Fix: onPairingStateChange on Apple/Web

Apple and Web have no native bond-state API, so onPairingStateChange / pairingStateStream were never wired there. The 0.12.0 changelog claimed this support, but updateCallbackValue was false at every call site. pair() now reports the outcome of its encrypted-characteristic probe:

  • true via updatePairingState when the probe succeeds — on both the pairingCommand and the no-command read-all paths.
  • a failure event (false) via updatePairingFailure when it throws.

isPaired() still runs the same probe as a query and does not emit. The tables show onPairingStateChange as ⏺ for iOS/macOS/Web: pair() drives it, but there is no system-initiated bond event and unpair does not report.

Footnotes added

  • pair¹ — no dedicated pairing API on iOS/macOS/Web; pair() connects and reads or writes an encrypted characteristic so the OS triggers pairing. Works for all pairing methods on iOS/macOS. On Web the outcome depends on the browser's host OS: ConfirmOnly ("Just Works") pairing can be triggered on Web/macOS and Web/Android, but not on Web/Windows or Web/Linux — hence the conservative ⏺.
  • unpair² — iOS 18+ only, and only for accessories authorized through AccessorySetupKit (requestDevice); other devices fail with deviceNotFound.
  • isPaired³ — on iOS/macOS/Web it needs a pairingCommand with an encrypted read or write characteristic and returns null without one; it also triggers pairing if the device is not already paired.
  • onPairingStateChange⁴ — on iOS/macOS/Web pair() reports the outcome it drove: true when the encrypted-characteristic probe succeeds and false on failure. There is no system-initiated bond event and unpair does not report; read the state with isPaired(pairingCommand:).

Scope

README.md, CHANGELOG.md, a fix in lib/src/universal_ble.dart, and a new test/apple_web_pairing_state_test.dart.

Test plan

  • flutter test — all tests pass (4 new).
  • flutter analyze lib test — no issues.
  • Rendered the tables on GitHub to confirm column alignment and that the footnote markers resolve.

- Footnote ¹: say pair() "reads or writes" an encrypted characteristic,
  and reword the Web caveat to key off the browser host OS instead of
  the duplicated "on Web … on Web/Windows and Web/Linux" phrasing.
- isPaired: mark iOS/macOS/Web ⏺ (needs a pairingCommand, returns null
  without one) and note it in footnote ³, consistent with pair/unpair.
- Give each footnote its own paragraph so GitHub does not collapse them
  into a single wrapped blob.
- Move the legend above the client table so ⏺/— are defined before first
  use, and drop the duplicate below the peripheral table.
Note on _connectAndExecuteBleCommand that updateCallbackValue is false at
every call site, so nothing emits pairing state from there on any platform
(including iOS/macOS/Web, which have no native pairing-state callback), and
that enabling it on those platforms would require flipping the README's
onPairingStateChange row back to ⏺.
@fotiDim fotiDim changed the title docs: neutral status icons and clarified pairing support in the API tables Neutral API support tables, pairing notes, and Apple/Web pairing-state fix Oct 14, 2026
Apple and Web have no native bond API, so onPairingStateChange /
pairingStateStream were never wired there even though pair() drives
pairing by executing an encrypted characteristic. The 0.12.0 changelog
claimed support, but updateCallbackValue was false at every call site.

pair() now reports the probe outcome: updatePairingState(true) on success
and updatePairingFailure(false) when it throws. isPaired() keeps running
the same probe as a query without emitting.

- Wire updateCallbackValue: true from pair()'s Apple/Web branch, and make
  _connectAndExecuteBleCommand report success for both the pairingCommand
  and the read-all probes.
- Add test/apple_web_pairing_state_test.dart covering success, failure,
  the no-command read-all path, and that isPaired() stays silent.
- README: onPairingStateChange is ⏺ on iOS/macOS/Web again; rewrite
  footnote ⁴ and note the behaviour in the Pairing state section.
- CHANGELOG: document the fix and the incorrect 0.12.0 claim.
@fotiDim
fotiDim force-pushed the docs/api-support-icons branch from 78f837a to 951b109 Compare October 14, 2026 11:07
The no-command pair() path emitted isPaired=true unconditionally once the
device exposed a readable characteristic, because _attemptPairingReadingAll
swallowed every read error. It now returns whether any read succeeded and the
probe reports failure (false) when none could be read.

Scope the pairing-failure event to the probe step so connection/discovery
failures no longer surface as pairing state changes, and add tests for the
failing read-all and connection-failure paths.
isPaired relies on the same encrypted-characteristic probe as pair, so mark it
supported (checkmark) on iOS/macOS to match pair, keeping the Web column at
partial. Also replace the word 'bond' in the pairing notes with 'pairing'.
The Web probe reads an already-paired device's encrypted characteristic on any
host OS, so the query returns a correct answer regardless of whether the browser
can trigger ConfirmOnly pairing.
Put the superscript indicators next to the ⏺ circle instead of the API name,
and only circle rows carry one (isPaired is now all-checkmark). Drop the
onPairingStateChange and pair notes that repeated the Pairing section, and
shorten the 'Pairing state changes' prose to point at the note.
@fotiDim
fotiDim merged commit 4855e95 into main Oct 14, 2026
3 checks passed
@fotiDim
fotiDim deleted the docs/api-support-icons branch October 14, 2026 12:26
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.

2 participants