From 79b90b33acba27fa08d9020186111b6f4ac35d36 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Sun, 9 Nov 2025 22:47:40 +0100 Subject: [PATCH 1/3] Update readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d4447f9..85734fe 100644 --- a/README.md +++ b/README.md @@ -530,6 +530,7 @@ class FlutterAccessoryManagerMock extends FlutterAccessoryManagerInterface { // Set custom platform specific implementation (e.g. for testing) FlutterAccessoryManager.setInstance(FlutterAccessoryManagerMock()); ``` +<<<<<<< HEAD ## 🧩 Apps using Flutter Accessory Manager @@ -539,4 +540,6 @@ Here are some of the apps leveraging the power of `flutter_accessory_manager` in |:--:|:--| > 💡 **Built something cool with Flutter Accessory Manager?** > We'd love to showcase your app here! -> Open a pull request and add it to this section. Please include your app icon in svg! \ No newline at end of file +> Open a pull request and add it to this section. Please include your app icon in svg! +======= +>>>>>>> 274eb2b (Update readme) From bc860494b97906f1a469eb6bb525e64a5498e056 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 10 Nov 2025 23:08:39 +0100 Subject: [PATCH 2/3] Update readme --- README.md | 298 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 191 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 85734fe..47234a2 100644 --- a/README.md +++ b/README.md @@ -6,32 +6,37 @@ A cross-platform (Android/iOS/macOS/Windows/Linux) plugin for managing Bluetooth ## Features -- [Scanning](#scanning) -- [Pairing & Unpairing](#pairing--unpairing) -- [Connecting](#connecting) -- [HID Reports](#hid-reports) -- [SDP Service Registration](#sdp-service-registration) -- [iOS External Accessory](#ios-external-accessory) +- **Unified Cross-Platform API** - Write once, works everywhere. No platform checks needed! +- [Scanning](#scanning) - Works on all platforms (iOS uses picker dialog) +- [Pairing & Unpairing](#pairing--unpairing) - Works on all platforms +- [Connecting](#connecting) - Unified connection API across all platforms +- [HID Reports](#hid-reports) - Available on Android/macOS/Windows +- [SDP Service Registration](#sdp-service-registration) - Available on Android/macOS/Windows +- [iOS External Accessory](#ios-external-accessory) - Integrated into unified API ## API Support +> **✨ Unified API Design:** Core APIs work across all platforms. Platform differences are handled transparently - you write the same code everywhere! APIs marked with ❌ are not supported on those platforms. + | | Android | iOS | macOS | Windows | Linux | | :------------------- | :-----: | :-: | :---: | :-----: | :---: | -| showBluetoothAccessoryPicker | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | ❌ | -| startScan/stopScan | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| pair/unpair | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| getPairedDevices | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| connect (HID) | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | -| disconnect | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸* | +| startScan/stopScan | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| pair/unpair | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| getPairedDevices | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| connect | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸* | +| disconnect | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸* | | sendReport | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | | setupSdp/closeSdp | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | -| closeEASession | ❌ | âœ”ī¸ | ❌ | ❌ | ❌ | -| accessoryConnected/Disconnected | ❌ | âœ”ī¸ | ❌ | ❌ | ❌ | -| onConnectionStateChanged (HID) | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | +| showBluetoothAccessoryPicker | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | ❌ | +| onDeviceDiscovered | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| onDeviceRemoved | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| onConnectionStateChanged | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | | onGetReport | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | | onSdpServiceRegistrationUpdate | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | -*Linux `disconnect()` is basic disconnect only, not HID-specific. +**Platform Implementation Notes:** +- *iOS: Uses External Accessory framework (picker-based discovery/pairing, EA sessions for connection) +- *Linux: Basic Bluetooth connection (not HID-specific) ## Getting Started @@ -52,12 +57,16 @@ import 'package:flutter_accessory_manager/flutter_accessory_manager.dart'; ### Start Scanning -Start scanning for Bluetooth devices: +Start scanning for Bluetooth devices. Works on all platforms: ```dart await FlutterAccessoryManager.startScan(); ``` +> **Platform Behavior:** +> - **Android/macOS/Windows/Linux:** Starts Bluetooth device discovery +> - **iOS:** Automatically shows the External Accessory picker dialog + ### Stop Scanning Stop scanning for Bluetooth devices: @@ -74,42 +83,66 @@ Check if currently scanning: bool isScanning = await FlutterAccessoryManager.isScanning(); ``` +> **iOS:** Returns `true` while the picker dialog is open + ### Device Discovery -Listen to discovered devices: +Listen to discovered devices. This unified callback works on all platforms: ```dart -FlutterAccessoryManager.onBluetoothDeviceDiscover = (BluetoothDevice device) { +FlutterAccessoryManager.onDeviceDiscovered = (BluetoothDevice device) { print('Device discovered: ${device.name} (${device.address})'); print('RSSI: ${device.rssi}'); print('Paired: ${device.paired}'); print('Device Type: ${device.deviceType}'); print('Device Class: ${device.deviceClass}'); + + // Check if iOS External Accessory + if (device.isExternalAccessory == true) { + print('iOS External Accessory'); + print('Manufacturer: ${device.manufacturer}'); + print('Protocols: ${device.protocolStrings}'); + } }; ``` +> **Platform Behavior:** +> - **Android/macOS/Windows/Linux:** Triggered when devices are discovered during scan +> - **iOS:** Triggered when user selects a device from the picker (automatically shown by `startScan()`) + ### Device Removed -Listen to device removal events: +Listen to device removal events. Works on all platforms: ```dart -FlutterAccessoryManager.onBluetoothDeviceRemoved = (BluetoothDevice device) { +FlutterAccessoryManager.onDeviceRemoved = (BluetoothDevice device) { print('Device removed: ${device.name} (${device.address})'); }; ``` +> **Platform Behavior:** +> - **Android/macOS/Windows/Linux:** Triggered when device is removed from range +> - **iOS:** Triggered when External Accessory disconnects + ### Get Paired Devices -Get a list of all paired devices: +Get a list of all paired/connected devices. Works on all platforms: ```dart List devices = await FlutterAccessoryManager.getPairedDevices(); for (var device in devices) { - print('Paired device: ${device.name} - ${device.address}'); + print('Device: ${device.name} - ${device.address}'); + if (device.isExternalAccessory == true) { + print(' iOS External Accessory'); + } } ``` +> **Platform Behavior:** +> - **Android/macOS/Windows/Linux:** Returns list of paired Bluetooth devices +> - **iOS:** Returns list of connected External Accessories (converted to `BluetoothDevice`) + ### Show Bluetooth Accessory Picker Show the native Bluetooth accessory picker dialog. On iOS, this displays the External Accessory picker. @@ -126,13 +159,13 @@ await FlutterAccessoryManager.showBluetoothAccessoryPicker( ); ``` -> **Note:** Not available on Linux. +> **Note:** Not available on Linux. On iOS, `startScan()` automatically shows the picker, so you typically don't need to call this directly. ## Pairing & Unpairing ### Pair -Pair with a Bluetooth device by its address: +Pair with a Bluetooth device by its address. Works on all platforms: ```dart bool success = await FlutterAccessoryManager.pair('00:11:22:33:44:55'); @@ -144,37 +177,51 @@ if (success) { } ``` +> **Platform Behavior:** +> - **Android/macOS/Windows/Linux:** Standard Bluetooth pairing +> - **iOS:** If device is already connected via External Accessory, returns `true`. Otherwise, shows picker dialog and waits for user selection + ### Unpair -Unpair a Bluetooth device: +Unpair a Bluetooth device. Works on all platforms: ```dart await FlutterAccessoryManager.unpair('00:11:22:33:44:55'); ``` +> **iOS:** Disconnects the External Accessory if connected + ## Connecting -### Connect (HID) +### Connect -Connect to a Bluetooth HID device: +Connect to a Bluetooth device. Works on all platforms: ```dart await FlutterAccessoryManager.connect('00:11:22:33:44:55'); ``` -> **Platform Note:** Available on Android, macOS, and Windows. Not available on iOS (uses External Accessory framework) or Linux. +> **Platform Behavior:** +> - **Android/macOS/Windows:** Establishes HID connection +> - **iOS:** Opens External Accessory session (if device not found, shows picker first) +> - **Linux:** Establishes basic Bluetooth connection (if supported) ### Disconnect -Disconnect from a Bluetooth device: +Disconnect from a Bluetooth device. Works on all platforms: ```dart await FlutterAccessoryManager.disconnect('00:11:22:33:44:55'); ``` +> **Platform Behavior:** +> - **Android/macOS/Windows:** Disconnects HID connection +> - **iOS:** Closes External Accessory session +> - **Linux:** Disconnects basic Bluetooth connection + ### Connection State Changes -Listen to connection state changes: +Listen to connection state changes. This unified callback works on all platforms: ```dart FlutterAccessoryManager.onConnectionStateChanged = (String deviceId, bool connected) { @@ -182,10 +229,15 @@ FlutterAccessoryManager.onConnectionStateChanged = (String deviceId, bool connec }; ``` -> **Platform Note:** Available on Android, macOS, and Windows (HID connections only). Not available on iOS or Linux. +> **Platform Behavior:** +> - **Android/macOS/Windows:** Triggered on HID connection state changes +> - **iOS:** Triggered when External Accessory connects/disconnects +> - **Linux:** Triggered on basic Bluetooth connection state changes ## HID Reports +> **Platform Support:** HID operations are available on Android, macOS, and Windows. Not available on iOS or Linux. + ### Send Report Send a HID report to a connected device: @@ -197,7 +249,7 @@ Uint8List reportData = Uint8List.fromList([0x01, 0x02, 0x03]); await FlutterAccessoryManager.sendReport('00:11:22:33:44:55', reportData); ``` -> **Platform Note:** Available on Android, macOS, and Windows. Not available on iOS or Linux. +> **Platform Support:** Available on Android, macOS, and Windows. Not available on iOS or Linux. ### Get Report @@ -217,10 +269,12 @@ FlutterAccessoryManager.onGetReport = (String deviceId, ReportType type, int buf }; ``` -> **Platform Note:** Available on Android, macOS, and Windows. Not available on iOS or Linux. +> **Platform Support:** Available on Android, macOS, and Windows. Not available on iOS or Linux. ## SDP Service Registration +> **Platform Support:** SDP operations are available on Android, macOS, and Windows. Not available on iOS or Linux. + ### Setup SDP Set up the SDP service registration for Bluetooth HID: @@ -247,6 +301,8 @@ SdpConfig config = SdpConfig( await FlutterAccessoryManager.setupSdp(config: config); ``` +> **Platform Support:** Available on Android, macOS, and Windows. Not available on iOS or Linux. + ### Close SDP Close the SDP service registration: @@ -255,6 +311,8 @@ Close the SDP service registration: await FlutterAccessoryManager.closeSdp(); ``` +> **Platform Support:** Available on Android, macOS, and Windows. Not available on iOS or Linux. + ### SDP Registration Updates Listen to SDP service registration status changes: @@ -265,40 +323,33 @@ FlutterAccessoryManager.onSdpServiceRegistrationUpdate = (bool registered) { }; ``` -> **Platform Note:** Available on Android, macOS, and Windows. Not available on iOS or Linux. +> **Platform Support:** Available on Android, macOS, and Windows. Not available on iOS or Linux. ## iOS External Accessory -> **âš ī¸ iOS Only:** The following APIs are only available on iOS. On other platforms, they will throw `UnimplementedError`. - -### Close EA Session - -Close an External Accessory session. If no protocol string is provided, it will use the first available protocol: - -```dart -await FlutterAccessoryManager.closeEASession('com.mycompany.myprotocol'); -``` +> **â„šī¸ Unified API:** iOS External Accessory functionality is now integrated into the unified API. The following deprecated APIs are still available for backward compatibility but will be removed in a future version. -### Accessory Connected +### Deprecated APIs -Listen to iOS External Accessory connection events: +The following iOS-specific APIs are deprecated. Use the unified APIs instead: -```dart -FlutterAccessoryManager.accessoryConnected = (EAAccessory accessory) { - print('Accessory connected: ${accessory.name}'); - print('Manufacturer: ${accessory.manufacturer}'); - print('Model: ${accessory.modelNumber}'); - print('Protocols: ${accessory.protocolStrings}'); -}; -``` +- `closeEASession()` → Use `disconnect()` +- `accessoryConnected` callback → Use `onConnectionStateChanged` +- `accessoryDisconnected` callback → Use `onDeviceRemoved` or `onConnectionStateChanged` -### Accessory Disconnected +### Accessing iOS-Specific Information -Listen to iOS External Accessory disconnection events: +iOS External Accessories are automatically converted to `BluetoothDevice` objects. Access iOS-specific information through the device properties: ```dart -FlutterAccessoryManager.accessoryDisconnected = (EAAccessory accessory) { - print('Accessory disconnected: ${accessory.name}'); +FlutterAccessoryManager.onDeviceDiscovered = (BluetoothDevice device) { + if (device.isExternalAccessory == true) { + print('iOS External Accessory: ${device.name}'); + print('Manufacturer: ${device.manufacturer}'); + print('Model: ${device.modelNumber}'); + print('Serial: ${device.serialNumber}'); + print('Protocols: ${device.protocolStrings}'); + } }; ``` @@ -306,11 +357,12 @@ FlutterAccessoryManager.accessoryDisconnected = (EAAccessory accessory) { ### BluetoothDevice -Represents a Bluetooth device: +Represents a Bluetooth device. Works on all platforms, including iOS External Accessories: ```dart BluetoothDevice device = ...; +// Common properties (all platforms) print('Address: ${device.address}'); print('Name: ${device.name}'); print('Paired: ${device.paired}'); @@ -318,26 +370,33 @@ print('Connected with HID: ${device.isConnectedWithHid}'); print('RSSI: ${device.rssi}'); print('Device Type: ${device.deviceType}'); // classic, le, dual, unknown print('Device Class: ${device.deviceClass}'); // peripheral, audioVideo, etc. + +// iOS External Accessory properties (null on other platforms) +if (device.isExternalAccessory == true) { + print('Manufacturer: ${device.manufacturer}'); + print('Model: ${device.modelNumber}'); + print('Serial: ${device.serialNumber}'); + print('Protocols: ${device.protocolStrings}'); +} ``` -### EAAccessory (iOS) +**Properties:** +- `address` - Device address/identifier (MAC address on most platforms, connection ID on iOS) +- `name` - Device name +- `paired` - Whether device is paired/connected +- `isConnectedWithHid` - Whether connected via HID (null on iOS/Linux) +- `rssi` - Signal strength (0 on iOS, not available for EA) +- `deviceType` - Bluetooth device type (classic, le, dual, unknown) +- `deviceClass` - Device class (peripheral, audioVideo, etc.) +- `isExternalAccessory` - `true` if iOS External Accessory (null on other platforms) +- `manufacturer` - iOS only: Manufacturer name +- `modelNumber` - iOS only: Model number +- `serialNumber` - iOS only: Serial number +- `protocolStrings` - iOS only: List of supported EA protocol strings -Represents an iOS External Accessory: +### EAAccessory (Deprecated) -```dart -EAAccessory accessory = ...; - -print('Name: ${accessory.name}'); -print('Manufacturer: ${accessory.manufacturer}'); -print('Model: ${accessory.modelNumber}'); -print('Serial: ${accessory.serialNumber}'); -print('Firmware: ${accessory.firmwareRevision}'); -print('Hardware: ${accessory.hardwareRevision}'); -print('Dock Type: ${accessory.dockType}'); -print('Protocols: ${accessory.protocolStrings}'); -print('Connected: ${accessory.isConnected}'); -print('Connection ID: ${accessory.connectionID}'); -``` +> **âš ī¸ Deprecated:** `EAAccessory` is deprecated. iOS External Accessories are now represented as `BluetoothDevice` objects with `isExternalAccessory == true`. Use the unified `BluetoothDevice` API instead. ### SdpConfig @@ -472,52 +531,77 @@ When publishing on Linux as a snap, you need to declare the `bluez` plug in `sna - bluez ``` -## Platform-Specific APIs +## Cross-Platform Usage -### iOS-Only APIs +### Unified API Design -The following APIs are **only available on iOS**: +All APIs work across all platforms. Platform differences are handled transparently: -- `closeEASession([String? protocolString])` - Closes an External Accessory session -- `accessoryConnected` callback - Triggered when an iOS External Accessory is connected -- `accessoryDisconnected` callback - Triggered when an iOS External Accessory is disconnected +- **No platform checks needed** - Write the same code everywhere +- **No capability detection** - APIs gracefully handle unsupported operations +- **Unified callbacks** - Single callback for device discovery, connection state, etc. +- **Consistent behavior** - Same API surface on all platforms -These APIs use the `EAAccessory` type which is iOS-specific. They will only be triggered on iOS when External Accessories are connected or disconnected. +### Platform Implementation Details -### HID APIs (Not Available on iOS or Linux) +While the API is unified, platform implementations differ: -The following HID-related APIs are **not available on iOS** (which uses External Accessory framework instead) and **not available on Linux**: +**Android/macOS/Windows:** +- Full HID support (connect, sendReport, SDP) +- Standard Bluetooth scanning and pairing +- HID connection state callbacks -- `connect(String deviceId)` - Connect to HID device -- `sendReport(String deviceId, Uint8List data)` - Send HID report -- `setupSdp({required SdpConfig config})` - Setup SDP service -- `closeSdp()` - Close SDP service -- `onGetReport` callback - Handle HID get report requests -- `onSdpServiceRegistrationUpdate` callback - SDP registration updates -- `onConnectionStateChanged` callback - HID connection state changes +**iOS:** +- Uses External Accessory framework (MFi required) +- `startScan()` automatically shows picker dialog +- `pair()` and `connect()` show picker if device not found +- External Accessories converted to `BluetoothDevice` automatically +- HID operations not supported -**Available on:** Android, macOS, Windows +**Linux:** +- Basic Bluetooth operations (scan, pair, disconnect) +- HID operations not supported +- No native picker dialog -**Not available on:** iOS, Linux +### Example: Cross-Platform Code -**Note:** Linux does have `disconnect()` but not the other HID methods. +```dart +// Works on all platforms - no platform checks needed! +FlutterAccessoryManager.onDeviceDiscovered = (BluetoothDevice device) { + print('Found: ${device.name}'); +}; -### Linux Limitations +FlutterAccessoryManager.onConnectionStateChanged = (String deviceId, bool connected) { + print('$deviceId: ${connected ? "connected" : "disconnected"}'); +}; + +// Scan - works everywhere +await FlutterAccessoryManager.startScan(); + +// Get devices - works everywhere +List devices = await FlutterAccessoryManager.getPairedDevices(); + +// Pair - works everywhere +bool paired = await FlutterAccessoryManager.pair(device.address); + +// Connect - works everywhere +await FlutterAccessoryManager.connect(device.address); + +// Send data - available on Android/macOS/Windows only +await FlutterAccessoryManager.sendReport(device.address, data); + +// Disconnect - works everywhere +await FlutterAccessoryManager.disconnect(device.address); +``` -On Linux, the following APIs are **not implemented**: +### Deprecated APIs -- `showBluetoothAccessoryPicker()` - Native picker not available -- `connect()` - HID connection not supported -- `sendReport()` - HID reports not supported -- `setupSdp()` - SDP service not supported -- `closeSdp()` - SDP service not supported +The following platform-specific APIs are deprecated and will be removed in a future version: -**Available on Linux:** -- `startScan()`, `stopScan()`, `isScanning()` -- `pair()`, `unpair()` -- `getPairedDevices()` -- `disconnect()` (basic disconnect only) -- `onBluetoothDeviceDiscover`, `onBluetoothDeviceRemoved` callbacks +- `closeEASession()` → Use `disconnect()` +- `accessoryConnected` / `accessoryDisconnected` → Use `onConnectionStateChanged` or `onDeviceRemoved` +- `onBluetoothDeviceDiscover` → Use `onDeviceDiscovered` +- `onBluetoothDeviceRemoved` → Use `onDeviceRemoved` ## Customizing Platform Implementation From 24718addc72d1f0bcd47fbd2b13aae0108d94a76 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 10 Nov 2025 23:21:55 +0100 Subject: [PATCH 3/3] Update readme --- README.md | 120 ++++++++++++++++++++++-------------------------------- 1 file changed, 49 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 47234a2..ae7a7d8 100644 --- a/README.md +++ b/README.md @@ -20,22 +20,22 @@ A cross-platform (Android/iOS/macOS/Windows/Linux) plugin for managing Bluetooth | | Android | iOS | macOS | Windows | Linux | | :------------------- | :-----: | :-: | :---: | :-----: | :---: | -| startScan/stopScan | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| pair/unpair | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| getPairedDevices | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| connect | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸* | +| showBluetoothAccessoryPicker | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | ❌ | +| startScan/stopScan | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| pair/unpair | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| getPairedDevices | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| connect | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸* | | disconnect | âœ”ī¸ | âœ”ī¸* | âœ”ī¸ | âœ”ī¸ | âœ”ī¸* | | sendReport | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | | setupSdp/closeSdp | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | -| showBluetoothAccessoryPicker | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | ❌ | -| onDeviceDiscovered | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| onDeviceRemoved | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | -| onConnectionStateChanged | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| onDeviceDiscovered | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| onDeviceRemoved | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | +| onConnectionStateChanged | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | âœ”ī¸ | | onGetReport | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | | onSdpServiceRegistrationUpdate | âœ”ī¸ | ❌ | âœ”ī¸ | âœ”ī¸ | ❌ | **Platform Implementation Notes:** -- *iOS: Uses External Accessory framework (picker-based discovery/pairing, EA sessions for connection) +- *iOS: `disconnect()` calls `closeEASession()` internally - *Linux: Basic Bluetooth connection (not HID-specific) ## Getting Started @@ -57,15 +57,13 @@ import 'package:flutter_accessory_manager/flutter_accessory_manager.dart'; ### Start Scanning -Start scanning for Bluetooth devices. Works on all platforms: +Start scanning for Bluetooth devices: ```dart await FlutterAccessoryManager.startScan(); ``` -> **Platform Behavior:** -> - **Android/macOS/Windows/Linux:** Starts Bluetooth device discovery -> - **iOS:** Automatically shows the External Accessory picker dialog +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS (throws `UnimplementedError`). ### Stop Scanning @@ -83,11 +81,11 @@ Check if currently scanning: bool isScanning = await FlutterAccessoryManager.isScanning(); ``` -> **iOS:** Returns `true` while the picker dialog is open +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS. ### Device Discovery -Listen to discovered devices. This unified callback works on all platforms: +Listen to discovered devices: ```dart FlutterAccessoryManager.onDeviceDiscovered = (BluetoothDevice device) { @@ -96,23 +94,14 @@ FlutterAccessoryManager.onDeviceDiscovered = (BluetoothDevice device) { print('Paired: ${device.paired}'); print('Device Type: ${device.deviceType}'); print('Device Class: ${device.deviceClass}'); - - // Check if iOS External Accessory - if (device.isExternalAccessory == true) { - print('iOS External Accessory'); - print('Manufacturer: ${device.manufacturer}'); - print('Protocols: ${device.protocolStrings}'); - } }; ``` -> **Platform Behavior:** -> - **Android/macOS/Windows/Linux:** Triggered when devices are discovered during scan -> - **iOS:** Triggered when user selects a device from the picker (automatically shown by `startScan()`) +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS. ### Device Removed -Listen to device removal events. Works on all platforms: +Listen to device removal events: ```dart FlutterAccessoryManager.onDeviceRemoved = (BluetoothDevice device) { @@ -120,28 +109,21 @@ FlutterAccessoryManager.onDeviceRemoved = (BluetoothDevice device) { }; ``` -> **Platform Behavior:** -> - **Android/macOS/Windows/Linux:** Triggered when device is removed from range -> - **iOS:** Triggered when External Accessory disconnects +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS. ### Get Paired Devices -Get a list of all paired/connected devices. Works on all platforms: +Get a list of all paired devices: ```dart List devices = await FlutterAccessoryManager.getPairedDevices(); for (var device in devices) { print('Device: ${device.name} - ${device.address}'); - if (device.isExternalAccessory == true) { - print(' iOS External Accessory'); - } } ``` -> **Platform Behavior:** -> - **Android/macOS/Windows/Linux:** Returns list of paired Bluetooth devices -> - **iOS:** Returns list of connected External Accessories (converted to `BluetoothDevice`) +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS (throws `UnimplementedError`). ### Show Bluetooth Accessory Picker @@ -159,13 +141,13 @@ await FlutterAccessoryManager.showBluetoothAccessoryPicker( ); ``` -> **Note:** Not available on Linux. On iOS, `startScan()` automatically shows the picker, so you typically don't need to call this directly. +> **Platform Support:** Available on Android, iOS, macOS, and Windows. Not available on Linux. ## Pairing & Unpairing ### Pair -Pair with a Bluetooth device by its address. Works on all platforms: +Pair with a Bluetooth device by its address: ```dart bool success = await FlutterAccessoryManager.pair('00:11:22:33:44:55'); @@ -177,34 +159,29 @@ if (success) { } ``` -> **Platform Behavior:** -> - **Android/macOS/Windows/Linux:** Standard Bluetooth pairing -> - **iOS:** If device is already connected via External Accessory, returns `true`. Otherwise, shows picker dialog and waits for user selection +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS (throws `UnimplementedError`). ### Unpair -Unpair a Bluetooth device. Works on all platforms: +Unpair a Bluetooth device: ```dart await FlutterAccessoryManager.unpair('00:11:22:33:44:55'); ``` -> **iOS:** Disconnects the External Accessory if connected +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS (throws `UnimplementedError`). ## Connecting ### Connect -Connect to a Bluetooth device. Works on all platforms: +Connect to a Bluetooth device: ```dart await FlutterAccessoryManager.connect('00:11:22:33:44:55'); ``` -> **Platform Behavior:** -> - **Android/macOS/Windows:** Establishes HID connection -> - **iOS:** Opens External Accessory session (if device not found, shows picker first) -> - **Linux:** Establishes basic Bluetooth connection (if supported) +> **Platform Support:** Available on Android, macOS, Windows (HID connection), and Linux (basic Bluetooth connection). Not available on iOS (throws `UnimplementedError`). ### Disconnect @@ -216,12 +193,12 @@ await FlutterAccessoryManager.disconnect('00:11:22:33:44:55'); > **Platform Behavior:** > - **Android/macOS/Windows:** Disconnects HID connection -> - **iOS:** Closes External Accessory session +> - **iOS:** Closes External Accessory session (calls `closeEASession()` internally) > - **Linux:** Disconnects basic Bluetooth connection ### Connection State Changes -Listen to connection state changes. This unified callback works on all platforms: +Listen to connection state changes: ```dart FlutterAccessoryManager.onConnectionStateChanged = (String deviceId, bool connected) { @@ -229,10 +206,7 @@ FlutterAccessoryManager.onConnectionStateChanged = (String deviceId, bool connec }; ``` -> **Platform Behavior:** -> - **Android/macOS/Windows:** Triggered on HID connection state changes -> - **iOS:** Triggered when External Accessory connects/disconnects -> - **Linux:** Triggered on basic Bluetooth connection state changes +> **Platform Support:** Available on Android, macOS, Windows, and Linux. Not available on iOS. ## HID Reports @@ -327,16 +301,24 @@ FlutterAccessoryManager.onSdpServiceRegistrationUpdate = (bool registered) { ## iOS External Accessory -> **â„šī¸ Unified API:** iOS External Accessory functionality is now integrated into the unified API. The following deprecated APIs are still available for backward compatibility but will be removed in a future version. +> **â„šī¸ Unified API:** iOS External Accessory functionality is integrated into the unified API. + +### Unified APIs + +The following APIs work on iOS through the unified interface: + +- `disconnect()` - Calls `closeEASession()` internally on iOS +- `showBluetoothAccessoryPicker()` - Shows the External Accessory picker dialog ### Deprecated APIs -The following iOS-specific APIs are deprecated. Use the unified APIs instead: +The following iOS-specific callbacks are deprecated. Use the unified callbacks instead: -- `closeEASession()` → Use `disconnect()` - `accessoryConnected` callback → Use `onConnectionStateChanged` - `accessoryDisconnected` callback → Use `onDeviceRemoved` or `onConnectionStateChanged` +> **Note:** `closeEASession()` is still available for direct use if needed, but `disconnect()` is the recommended unified API. + ### Accessing iOS-Specific Information iOS External Accessories are automatically converted to `BluetoothDevice` objects. Access iOS-specific information through the device properties: @@ -553,10 +535,8 @@ While the API is unified, platform implementations differ: **iOS:** - Uses External Accessory framework (MFi required) -- `startScan()` automatically shows picker dialog -- `pair()` and `connect()` show picker if device not found -- External Accessories converted to `BluetoothDevice` automatically -- HID operations not supported +- Only `showBluetoothAccessoryPicker` is supported +- All other APIs throw `UnimplementedError` **Linux:** - Basic Bluetooth operations (scan, pair, disconnect) @@ -566,7 +546,7 @@ While the API is unified, platform implementations differ: ### Example: Cross-Platform Code ```dart -// Works on all platforms - no platform checks needed! +// Works on Android/macOS/Windows/Linux - iOS only supports showBluetoothAccessoryPicker FlutterAccessoryManager.onDeviceDiscovered = (BluetoothDevice device) { print('Found: ${device.name}'); }; @@ -575,22 +555,22 @@ FlutterAccessoryManager.onConnectionStateChanged = (String deviceId, bool connec print('$deviceId: ${connected ? "connected" : "disconnected"}'); }; -// Scan - works everywhere +// Scan - works on Android/macOS/Windows/Linux await FlutterAccessoryManager.startScan(); -// Get devices - works everywhere +// Get devices - works on Android/macOS/Windows/Linux List devices = await FlutterAccessoryManager.getPairedDevices(); -// Pair - works everywhere +// Pair - works on Android/macOS/Windows/Linux bool paired = await FlutterAccessoryManager.pair(device.address); -// Connect - works everywhere +// Connect - works on Android/macOS/Windows/Linux await FlutterAccessoryManager.connect(device.address); // Send data - available on Android/macOS/Windows only await FlutterAccessoryManager.sendReport(device.address, data); -// Disconnect - works everywhere +// Disconnect - works on all platforms (iOS calls closeEASession internally) await FlutterAccessoryManager.disconnect(device.address); ``` @@ -598,11 +578,12 @@ await FlutterAccessoryManager.disconnect(device.address); The following platform-specific APIs are deprecated and will be removed in a future version: -- `closeEASession()` → Use `disconnect()` - `accessoryConnected` / `accessoryDisconnected` → Use `onConnectionStateChanged` or `onDeviceRemoved` - `onBluetoothDeviceDiscover` → Use `onDeviceDiscovered` - `onBluetoothDeviceRemoved` → Use `onDeviceRemoved` +> **Note:** `closeEASession()` is still available on iOS for direct use, but `disconnect()` is the recommended unified API that works across all platforms. + ## Customizing Platform Implementation ```dart @@ -614,7 +595,6 @@ class FlutterAccessoryManagerMock extends FlutterAccessoryManagerInterface { // Set custom platform specific implementation (e.g. for testing) FlutterAccessoryManager.setInstance(FlutterAccessoryManagerMock()); ``` -<<<<<<< HEAD ## 🧩 Apps using Flutter Accessory Manager @@ -625,5 +605,3 @@ Here are some of the apps leveraging the power of `flutter_accessory_manager` in > 💡 **Built something cool with Flutter Accessory Manager?** > We'd love to showcase your app here! > Open a pull request and add it to this section. Please include your app icon in svg! -======= ->>>>>>> 274eb2b (Update readme)