[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-9490":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":15,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":16,"starSnapshotCount":16,"syncStatus":26,"lastSyncTime":27,"discoverSource":28},9490,"flutter_blue_plus","chipweinberger\u002Fflutter_blue_plus","chipweinberger","Flutter plugin for connecting and communicationg with Bluetooth Low Energy devices, on Android, iOS, macOS, Web, Linux, Windows.","",null,"Dart",992,612,15,5,0,12.36,"Other",false,"master",true,[],"2026-06-12 02:02:08","[![pub package](https:\u002F\u002Fimg.shields.io\u002Fpub\u002Fv\u002Fflutter_blue_plus.svg)](https:\u002F\u002Fpub.dartlang.org\u002Fpackages\u002Fflutter_blue_plus)\n[![Chat](https:\u002F\u002Fimg.shields.io\u002Fdiscord\u002F634853295160033301.svg?style=flat-square&colorB=758ED3)](https:\u002F\u002Fdiscord.gg\u002FYk5Efra)\n\n\u003Cbr>\n\u003Cp align=\"center\">\n\u003Cimg alt=\"FlutterBlue\" src=\"https:\u002F\u002Fgithub.com\u002Fchipweinberger\u002Fflutter_blue_plus\u002Fblob\u002Fmaster\u002Fsite\u002Fflutterblueplus.png?raw=true\" \u002F>\n\u003C\u002Fp>\n\u003Cbr>\u003Cbr>\n\n## Sponsor\n\n\u003Cp align=\"left\">\n\u003Cimg width=\"250px\" alt=\"FlutterBlue\" src=\"https:\u002F\u002Fgithub.com\u002Fchipweinberger\u002Fflutter_blue_plus\u002Fblob\u002Fmaster\u002Fsite\u002Fjamcorder.png?raw=true\" \u002F>\n\u003C\u002Fp>\n\nFlutterBluePlus is sponsored by [Jamcorder](https:\u002F\u002Fwww.jamcorder.com\u002F). \n\n## License\n\nFlutterBluePlus is licensed under the **[FlutterBluePlus License](.\u002FLICENSE.md)**.\n\n* **Free use**: For personal use, nonprofits, and educational institutions.  \n* **Commercial use**: For for-profit use, by for-profit organizations or individuals, a [Commercial License](https:\u002F\u002Fjamcorder.myshopify.com\u002Fproducts\u002Fflutterblueplus-commercial-license) is required. This license grants *lifetime use*, covers all FlutterBluePlus packages, and includes *lifetime updates*.\n\n---\n\n**Note: this plugin is continuous work from [FlutterBlue](https:\u002F\u002Fgithub.com\u002Fpauldemarco\u002Fflutter_blue).**\n\nMigrating from [FlutterBlue](https:\u002F\u002Fgithub.com\u002Fpauldemarco\u002Fflutter_blue)? See [Migration Guide](.\u002FMIGRATION.md)\n\n## Contents\n\n- [Introduction](#introduction)\n- [Usage](#usage)\n- [Getting Started](#getting-started)\n- [Using Ble in App Background](#using-ble-in-app-background)\n- [API Reference](#api-reference)\n- [Debugging](#debugging)\n- [Mocking](#mocking)\n- [Common Problems](#common-problems)\n\n## Introduction\n\nFlutterBluePlus is a Bluetooth Low Energy plugin for [Flutter](https:\u002F\u002Fflutter.dev). \n\nIt supports BLE Central Role only (most common). \n\nIf you need BLE Peripheral Role, you should check out [FlutterBlePeripheral](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fflutter_ble_peripheral), or [bluetooth_low_energy](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fbluetooth_low_energy).\n\n\n## Tutorial\n\nIf you are new to Bluetooth, you should start by reading BLE tutorials.\n* [Novel Bits BLE Tutorial](https:\u002F\u002Fnovelbits.io\u002Fbluetooth-low-energy-ble-complete-guide\u002F)\n* [All About Circuits BLE Tutorial](https:\u002F\u002Fwww.allaboutcircuits.com\u002Ftechnical-articles\u002Fexploring-the-basics-of-bluetooth-low-energy-a-beginners-guide-to-ble\u002F)\n* [Embetronicx BLE Tutorial](https:\u002F\u002Fembetronicx.com\u002Ftutorials\u002Ftech_devices\u002Fbluetooth-low-energy-ble-introduction-part-1\u002F)\n\n## ❗ Bluetooth Classic is not supported ❗\n\n i.e. **Arduino HC-05 & HC-06,** speakers, headphones, mice, keyboards, gamepads, and more are **not** supported. These all use Bluetooth Classic.\n\n Also, iBeacons are **_not_** supported on iOS. Apple requires you to use CoreLocation.\n\n## Cross-Platform Bluetooth Low Energy\n\nFlutterBluePlus supports nearly every feature on all supported platforms: iOS, macOS, Android, Linux, Web.\n\n## No Dependencies\n\nFlutterBluePlus has zero dependencies besides Flutter, Android, iOS, and macOS themselves.\n\nThis makes FlutterBluePlus very stable, and easy to maintain.\n\n## Windows Support\n\nUse [flutter_blue_plus_winrt](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fflutter_blue_plus_winrt) if you need Windows support.\n\nIt is maintained by [@chan150](https:\u002F\u002Fgithub.com\u002Fchan150).\n\n## ⭐ Stars ⭐\n\nPlease star this repo & on [pub.dev](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fflutter_blue_plus). We all benefit from having a larger community.\n\n## Discord 💬\n\n[![Chat](https:\u002F\u002Fimg.shields.io\u002Fdiscord\u002F634853295160033301.svg?style=flat-square&colorB=758ED3)](https:\u002F\u002Fdiscord.gg\u002FYk5Efra) There is a community Discord server. ([Link](https:\u002F\u002Fdiscord.gg\u002FYk5Efra))\n\n## Example\n\nFlutterBluePlus has a beautiful example app, useful to debug issues.\n\n```\ncd .\u002Fexample\nflutter run\n```\n\n\u003Cp align=\"center\">\n\u003Cimg alt=\"FlutterBlue\" src=\"https:\u002F\u002Fgithub.com\u002Fchipweinberger\u002Fflutter_blue_plus\u002Fblob\u002Fmaster\u002Fsite\u002Fexample.png?raw=true\" \u002F>\n\u003C\u002Fp>\n\n## Versioning\n\n`flutter_blue_plus` uses Traditional Versioning\n\n`BIG.MEDIUM.SMALL`:\n* `BIG` : Significant overhauls. e.g. `1.0.0` -> `2.0.0`.\n* `MEDIUM` : Moderate improvements, feature updates, breaking chages. e.g. `1.0.0` -> `1.1.0`.\n* `SMALL` : Small fixes, patches, or refinements. `1.0.0` -> `1.0.1`.\n  \n---\n\n`flutter_blue_plus_android`, `flutter_blue_plus_darwin`, `flutter_blue_plus_linux`, `flutter_blue_plus_platform_interface`, `flutter_blue_plus_web` use [Semantic Versioning](https:\u002F\u002Fsemver.org). \n\n`MAJOR.MINOR.PATCH`:\n* `MAJOR` : Breaking API changes. e.g. `1.0.0` -> `2.0.0`.\n* `MINOR` : New features. e.g. `1.0.0` -> `1.1.0`.\n* `PATCH` : Bug fixes. e.g. `1.0.0` -> `1.0.1`.\n\n\n## Usage\n\n### 🔥 Error Handling 🔥\n\nFlutter Blue Plus takes error handling seriously. \n\nEvery error returned by the native platform is checked and thrown as an exception where appropriate.\n\n**Streams:** Streams returned by FlutterBluePlus never emit any errors and never close. There's no need to handle `onError` or `onDone` for  `stream.listen(...)`. The one exception is `FlutterBluePlus.scanResults`, which you should handle `onError`.\n\n---\n\n### Set Log Level\n\n```dart\n\u002F\u002F if your terminal doesn't support color you'll see annoying logs like `\\x1B[1;35m`\nFlutterBluePlus.setLogLevel(LogLevel.verbose, color:false);\n\n\u002F\u002F optional\nFlutterBluePlus.logs.listen((String s){\n    \u002F\u002F send logs anywhere you want\n});\n```\n\nSetting `LogLevel.verbose` shows *all* data in and out.\n\n⚫ = function name\n\n🟣 = args to platform\n\n🟡 = data from platform\n\n\u003Cimg width=\"600\" alt=\"Screenshot 2023-07-27 at 4 53 08 AM\" src=\"https:\u002F\u002Fgithub.com\u002Fchipweinberger\u002Fflutter_blue_plus\u002Fassets\u002F1863934\u002Fee37d702-2752-4402-bf26-fc661728c1c3\">\n\n\n### Bluetooth On & Off\n\n**Note:** On iOS, a \"*This app would like to use Bluetooth*\" system dialogue appears on first call to any FlutterBluePlus method. \n \n```dart\n\u002F\u002F first, check if bluetooth is supported by your hardware\n\u002F\u002F Note: The platform is initialized on the first call to any FlutterBluePlus method.\nif (await FlutterBluePlus.isSupported == false) {\n    print(\"Bluetooth not supported by this device\");\n    return;\n}\n\n\u002F\u002F handle bluetooth on & off\n\u002F\u002F note: for iOS the initial state is typically BluetoothAdapterState.unknown\n\u002F\u002F note: if you have permissions issues you will get stuck at BluetoothAdapterState.unauthorized\nvar subscription = FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {\n    print(state);\n    if (state == BluetoothAdapterState.on) {\n        \u002F\u002F usually start scanning, connecting, etc\n    } else {\n        \u002F\u002F show an error to the user, etc\n    }\n});\n\n\u002F\u002F turn on bluetooth ourself if we can\n\u002F\u002F for iOS, the user controls bluetooth enable\u002Fdisable\nif (!kIsWeb && Platform.isAndroid) {\n    await FlutterBluePlus.turnOn();\n}\n\n\u002F\u002F cancel to prevent duplicate listeners\nsubscription.cancel();\n```\n\n### Scan for devices\n\nIf your device is not found, see [Common Problems](#common-problems).\n\n**Note:** It is recommended to set scan filters to reduce main thread & platform channel usage.\n\n```dart\n\u002F\u002F listen to scan results\n\u002F\u002F Note: `onScanResults` clears the results between scans. You should use\n\u002F\u002F  `scanResults` if you want the current scan results *or* the results from the previous scan.\nvar subscription = FlutterBluePlus.onScanResults.listen((results) {\n        if (results.isNotEmpty) {\n            ScanResult r = results.last; \u002F\u002F the most recently found device\n            print('${r.device.remoteId}: \"${r.advertisementData.advName}\" found!');\n        }\n    },\n    onError: (e) => print(e),\n);\n\n\u002F\u002F cleanup: cancel subscription when scanning stops\nFlutterBluePlus.cancelWhenScanComplete(subscription);\n\n\u002F\u002F Wait for Bluetooth enabled & permission granted\n\u002F\u002F In your real app you should use `FlutterBluePlus.adapterState.listen` to handle all states\nawait FlutterBluePlus.adapterState.where((val) => val == BluetoothAdapterState.on).first;\n\n\u002F\u002F Start scanning w\u002F timeout\n\u002F\u002F Optional: use `stopScan()` as an alternative to timeout\nawait FlutterBluePlus.startScan(\n  withServices:[Guid(\"180D\")], \u002F\u002F match any of the specified services\n  withNames:[\"Bluno\"], \u002F\u002F *or* any of the specified names\n  timeout: Duration(seconds:15));\n\n\u002F\u002F wait for scanning to stop\nawait FlutterBluePlus.isScanning.where((val) => val == false).first;\n```\n\n### Connect to a device\n\n```dart\n\u002F\u002F listen for disconnection\nvar subscription = device.connectionState.listen((BluetoothConnectionState state) async {\n    if (state == BluetoothConnectionState.disconnected) {\n        \u002F\u002F 1. typically, start a periodic timer that tries to \n        \u002F\u002F    reconnect, or just call connect() again right now\n        \u002F\u002F 2. you must always re-discover services after disconnection!\n        print(\"${device.disconnectReason?.code} ${device.disconnectReason?.description}\");\n    }\n});\n\n\u002F\u002F cleanup: cancel subscription when disconnected\n\u002F\u002F   - [delayed] This option is only meant for `connectionState` subscriptions.  \n\u002F\u002F     When `true`, we cancel after a small delay. This ensures the `connectionState` \n\u002F\u002F     listener receives the `disconnected` event.\n\u002F\u002F   - [next] if true, the the stream will be canceled only on the *next* disconnection,\n\u002F\u002F     not the current disconnection. This is useful if you setup your subscriptions\n\u002F\u002F     before you connect.\ndevice.cancelWhenDisconnected(subscription, delayed:true, next:true);\n\n\u002F\u002F Connect to the device\nawait device.connect();\n\n\u002F\u002F Disconnect from device\nawait device.disconnect();\n\n\u002F\u002F cancel to prevent duplicate listeners\nsubscription.cancel();\n```\n\n### Auto Connect\n\nConnects whenever your device is found.\n\n```dart\n\u002F\u002F enable auto connect\n\u002F\u002F  - note: autoConnect is incompatible with mtu argument, so you must call requestMtu yourself\nawait device.connect(autoConnect:true, mtu:null)\n\n\u002F\u002F wait until connection\n\u002F\u002F  - when using autoConnect, connect() always returns immediately, so we must\n\u002F\u002F    explicity listen to `device.connectionState` to know when connection occurs \nawait device.connectionState.where((val) => val == BluetoothConnectionState.connected).first;\n\n\u002F\u002F disable auto connect\nawait device.disconnect()\n```\n\n### Save Device\n\nTo save a device between app restarts, just write the `remoteId` to a file.\n\nNow you can connect without needing to scan again, like so:\n\n```dart\nfinal String remoteId = await File('\u002FremoteId.txt').readAsString();\nvar device = BluetoothDevice.fromId(remoteId);\n\u002F\u002F AutoConnect is convenient because it does not \"time out\"\n\u002F\u002F even if the device is not available \u002F turned off.\nawait device.connect(autoConnect: true);\n\n```\n\n\n### MTU\n\nOn Android, we request an mtu of 512 by default during connection (see: `connect` function arguments).\n\nOn iOS & macOS, the mtu is negotiated automatically, typically 135 to 255.\n\n```dart\nfinal subscription = device.mtu.listen((int mtu) {\n    \u002F\u002F iOS: initial value is always 23, but iOS will quickly negotiate a higher value\n    print(\"mtu $mtu\");\n});\n\n\u002F\u002F cleanup: cancel subscription when disconnected\ndevice.cancelWhenDisconnected(subscription);\n\n\u002F\u002F You can also manually change the mtu yourself.\nif (!kIsWeb && Platform.isAndroid) {\n    await device.requestMtu(512);\n}\n```\n\n### Discover services\n\n```dart\n\u002F\u002F Note: You must call discoverServices after every re-connection!\nList\u003CBluetoothService> services = await device.discoverServices();\nservices.forEach((service) {\n    \u002F\u002F do something with service\n});\n```\n\n### Read Characteristics\n\n```dart\n\u002F\u002F Reads all characteristics\nvar characteristics = service.characteristics;\nfor(BluetoothCharacteristic c in characteristics) {\n    if (c.properties.read) {\n        List\u003Cint> value = await c.read();\n        print(value);\n    }\n}\n```\n\n### Write Characteristic\n\n```dart\n\u002F\u002F Writes to a characteristic\nawait c.write([0x12, 0x34]);\n```\n\n**allowLongWrite**: To write large characteristics (up to 512 bytes) regardless of mtu, use `allowLongWrite`:\n\n```dart\n\u002F\u002F\u002F allowLongWrite should be used with caution. \n\u002F\u002F\u002F   1. it can only be used *with* response to avoid data loss\n\u002F\u002F\u002F   2. the peripheral device must support the 'long write' ble protocol.\n\u002F\u002F\u002F   3. Interrupted transfers can leave the characteristic in a partially written state\n\u002F\u002F\u002F   4. If the mtu is small, it is very very slow.\nawait c.write(data, allowLongWrite:true);\n```\n\n**splitWrite**: To write lots of data (unlimited), you can define the `splitWrite` function. \n\n```dart\nimport 'dart:math';\n\u002F\u002F split write should be used with caution.\n\u002F\u002F    1. due to splitting, `characteristic.read()` will return partial data.\n\u002F\u002F    2. it can only be used *with* response to avoid data loss\n\u002F\u002F    3. The characteristic must be designed to support split data\nextension splitWrite on BluetoothCharacteristic {\n  Future\u003Cvoid> splitWrite(List\u003Cint> value, {int timeout = 15}) async {\n    int chunk = min(device.mtuNow - 3, 512); \u002F\u002F 3 bytes BLE overhead, 512 bytes max\n    for (int i = 0; i \u003C value.length; i += chunk) {\n      List\u003Cint> subvalue = value.sublist(i, min(i + chunk, value.length));\n      await write(subvalue, withoutResponse:false, timeout: timeout);\n    }\n  }\n}\n```\n\n### Subscribe to a characteristic\n\nIf `onValueReceived` is never called, see [Common Problems](#common-problems) in the README.\n\n```dart\nfinal subscription = characteristic.onValueReceived.listen((value) {\n    \u002F\u002F onValueReceived is updated:\n    \u002F\u002F   - anytime read() is called\n    \u002F\u002F   - anytime a notification arrives (if subscribed)\n});\n\n\u002F\u002F cleanup: cancel subscription when disconnected\ndevice.cancelWhenDisconnected(subscription);\n\n\u002F\u002F subscribe\n\u002F\u002F Note: If a characteristic supports both **notifications** and **indications**,\n\u002F\u002F it will default to **notifications**. This matches how CoreBluetooth works on iOS.\nawait characteristic.setNotifyValue(true);\n```\n\n### Last Value Stream\n\n`lastValueStream` is an alternative to `onValueReceived`. It emits a value any time the characteristic changes, **including writes.**\n\nIt is very convenient for simple characteristics that support both WRITE and READ (and\u002For NOTIFY). **e.g.** a \"light switch toggle\" characteristic. \n\n```dart\nfinal subscription = characteristic.lastValueStream.listen((value) {\n    \u002F\u002F lastValueStream` is updated:\n    \u002F\u002F   - anytime read() is called\n    \u002F\u002F   - anytime write() is called\n    \u002F\u002F   - anytime a notification arrives (if subscribed)\n    \u002F\u002F   - also when first listened to, it re-emits the last value for convenience.\n});\n\n\u002F\u002F cleanup: cancel subscription when disconnected\ndevice.cancelWhenDisconnected(subscription);\n\n\u002F\u002F enable notifications\nawait characteristic.setNotifyValue(true);\n```\n\n### Read and write descriptors\n\n```dart\n\u002F\u002F Reads all descriptors\nvar descriptors = characteristic.descriptors;\nfor(BluetoothDescriptor d in descriptors) {\n    List\u003Cint> value = await d.read();\n    print(value);\n}\n\n\u002F\u002F Writes to a descriptor\nawait d.write([0x12, 0x34])\n```\n\n### Services Changed Characteristic\n\nFlutterBluePlus automatically listens to the Services Changed Characteristic (0x2A05)\n\nIn FlutterBluePlus, we call it `onServicesReset` because you must re-discover services.\n\n```dart\n\u002F\u002F - uses the GAP Services Changed characteristic (0x2A05)\n\u002F\u002F - you must call discoverServices() again\ndevice.onServicesReset.listen(() async {\n    print(\"Services Reset\");\n    await device.discoverServices();\n});\n```\n\n### Get Connected Devices\n\nGet devices currently connected to your app.\n\n```dart\nList\u003CBluetoothDevice> devs = FlutterBluePlus.connectedDevices;\nfor (var d in devs) {\n    print(d);\n}\n```\n\n### Get System Devices\n\nGet devices connected to the system by *any* app.\n\n**Note:** before you can communicate, you must connect *your app* to these devices \n\n```dart\n\u002F\u002F `withServices` required on iOS, ignored on android\nList\u003CGuid> withServices = [Guid(\"180F\")]; \u002F\u002F e.g. Battery Service\nList\u003CBluetoothDevice> devs = await FlutterBluePlus.systemDevices(withServices);\nfor (var d in devs) {\n    await d.connect(); \u002F\u002F Must connect *our* app to the device\n    await d.discoverServices();\n}\n```\n\n### Create Bond (Android Only)\n\n**Note:** calling this is usually not necessary!! The platform will do it automatically. \n\nHowever, you can force the popup to show sooner.\n\n```dart\nfinal bsSubscription = device.bondState.listen((value) {\n    print(\"$value prev:{$device.prevBondState}\");\n});\n\n\u002F\u002F cleanup: cancel subscription when disconnected\ndevice.cancelWhenDisconnected(bsSubscription);\n\n\u002F\u002F Force the bonding popup to show now (Android Only) \nawait device.createBond();\n\n\u002F\u002F remove bond\nawait device.removeBond();\n```\n\n### Events API\n\nAccess streams from all devices simultaneously.\n\nThere are streams for:\n* events.onConnectionStateChanged\n* events.onMtuChanged\n* events.onReadRssi\n* events.onServicesReset\n* events.onDiscoveredServices\n* events.onCharacteristicReceived\n* events.onCharacteristicWritten\n* events.onDescriptorRead\n* events.onDescriptorWritten\n* events.onNameChanged (iOS Only)\n* events.onBondStateChanged (Android Only)\n\n```dart\n\u002F\u002F listen to *any device* connection state changes \nFlutterBluePlus.events.onConnectionStateChanged.listen((event)) {\n    print('${event.device} ${event.connectionState}');\n}\n```\n\n### Multi Device Performance\n\nWe recommend using per-device queueing.\n\nSet this when your application starts, before starting any other FBP work:\n\n```dart\nFlutterBluePlus.setOperationQueueMode(OperationQueueMode.perDevice);\n```\n\nThis allows FlutterBluePlus to talk to multiple devices at the same time.\n\n## Mocking\n\nTo mock `FlutterBluePlus` for development, refer to the [Mocking Guide](MOCKING.md).\n\n## Getting Started\n\n### Add the `flutter_blue_plus` plugin\n\nWe recommend that you pin to a specific version of the `flutter_blue_plus` plugin for maximum stability and to avoid small breaking changes.\n\n```shell\nflutter pub add flutter_blue_plus:x.y.z\n```\n\n`flutter_blue_plus` is a [federated plugin](https:\u002F\u002Fdocs.flutter.dev\u002Fpackages-and-plugins\u002Fdeveloping-packages#federated-plugins) with endorsed platform implementations therefore you only need to add the \"app-facing package\" to your `pubspec.yaml` file.\n\n### Change the minSdkVersion for Android\n\nflutter_blue_plus is compatible only from version 21 of Android SDK so you should change this in **android\u002Fapp\u002Fbuild.gradle**:\n\n```dart\nandroid {\n  defaultConfig {\n     minSdkVersion: 21\n```\n\n### Add permissions for Android (No Location)\n\nIn the **android\u002Fapp\u002Fsrc\u002Fmain\u002FAndroidManifest.xml** add:\n\n```xml\n\u003C!-- Tell Google Play Store that your app uses Bluetooth LE\n     Set android:required=\"true\" if bluetooth is necessary -->\n\u003Cuses-feature android:name=\"android.hardware.bluetooth_le\" android:required=\"false\" \u002F>\n\n\u003C!-- New Bluetooth permissions in Android 12\nhttps:\u002F\u002Fdeveloper.android.com\u002Fabout\u002Fversions\u002F12\u002Ffeatures\u002Fbluetooth-permissions -->\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH_SCAN\" android:usesPermissionFlags=\"neverForLocation\" \u002F>\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\" \u002F>\n\n\u003C!-- legacy for Android 11 or lower -->\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH\" android:maxSdkVersion=\"30\" \u002F>\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" android:maxSdkVersion=\"30\" \u002F>\n\u003Cuses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" android:maxSdkVersion=\"30\"\u002F>\n\n\u003C!-- legacy for Android 9 or lower -->\n\u003Cuses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" android:maxSdkVersion=\"28\" \u002F>\n```\n\n### Add permissions for Android (With Fine Location)\n\nIf you want to use Bluetooth to determine location, or support iBeacons.\n\nIn the **android\u002Fapp\u002Fsrc\u002Fmain\u002FAndroidManifest.xml** add:\n\n```xml\n\u003C!-- Tell Google Play Store that your app uses Bluetooth LE\n     Set android:required=\"true\" if bluetooth is necessary -->\n\u003Cuses-feature android:name=\"android.hardware.bluetooth_le\" android:required=\"false\" \u002F>\n\n\u003C!-- New Bluetooth permissions in Android 12\nhttps:\u002F\u002Fdeveloper.android.com\u002Fabout\u002Fversions\u002F12\u002Ffeatures\u002Fbluetooth-permissions -->\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH_SCAN\"\u002F>\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\" \u002F>\n\u003Cuses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" \u002F>\n\n\u003C!-- legacy for Android 11 or lower -->\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH\" android:maxSdkVersion=\"30\" \u002F>\n\u003Cuses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" android:maxSdkVersion=\"30\" \u002F>\n\n\u003C!-- legacy for Android 9 or lower -->\n\u003Cuses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" android:maxSdkVersion=\"28\" \u002F>\n```\n\nAnd set **androidUsesFineLocation** when scanning:\n```dart\n\u002F\u002F Start scanning\nflutterBlue.startScan(timeout: Duration(seconds: 4), androidUsesFineLocation: true);\n```\n\n### Android Proguard\n\nAdd the following line in your `project\u002Fandroid\u002Fapp\u002Fproguard-rules.pro` file:\n\n```\n-keep class com.lib.flutter_blue_plus.* { *; }\n```\n\nto avoid seeing the following kind errors in your `release` builds:\n\n```\nPlatformException(startScan, Field androidScanMode_ for m0.e0 not found. Known fields are\n [private int m0.e0.q, private b3.b0$i m0.e0.r, private boolean m0.e0.s, private static final m0.e0 m0.e0.t,\n private static volatile b3.a1 m0.e0.u], java.lang.RuntimeException: Field androidScanMode_ for m0.e0 not found\n```\n\n### Add permissions for iOS\n\nIn the **ios\u002FRunner\u002FInfo.plist** let’s add:\n\n```dart\n\u003Cdict>\n...\n    \u003Ckey>NSBluetoothAlwaysUsageDescription\u003C\u002Fkey>\n    \u003Cstring>This app needs Bluetooth to function\u003C\u002Fstring>\n...\n\u003C\u002Fdict>\n```\n\nFor location permissions on iOS see more at: [https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fcorelocation\u002Frequesting_authorization_for_location_services](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fcorelocation\u002Frequesting_authorization_for_location_services)\n\n### Add permissions for macOS \n\nMake sure you have granted access to the Bluetooth hardware:\n\n`Xcode -> Runners -> Targets -> Runner-> Signing & Capabilities -> App Sandbox -> Hardware -> Enable Bluetooth`\n\n\u003Cimg width=\"528\" alt=\"Screenshot 2023-12-11 at 10 32 04 AM\" src=\"https:\u002F\u002Fgithub.com\u002Fchipweinberger\u002Fflutter_blue_plus\u002Fassets\u002F1863934\u002F554079ef-4627-4dfc-97e3-1f07f84a0f3c\">\n\n## Using Ble in App Background\n\n**This is an advanced use case**. FlutterBluePlus does not support everything. You may have to fork it. PRs are welcome.\n\n### iOS\n\nDocumentation: https:\u002F\u002Fdeveloper.apple.com\u002Flibrary\u002Farchive\u002Fdocumentation\u002FNetworkingInternetWeb\u002FConceptual\u002FCoreBluetooth_concepts\u002FCoreBluetoothBackgroundProcessingForIOSApps\u002FPerformingTasksWhileYourAppIsInTheBackground.html\n\nAdd the following to your `Info.plist`\n\n```\n\u003Ckey>UIBackgroundModes\u003C\u002Fkey>\n\u003Carray>\n    \u003Cstring>bluetooth-central\u003C\u002Fstring>\n\u003C\u002Farray>\n```\n\nWhen this key-value pair is included in the app’s Info.plist file, the system wakes up your app to process ble `read`, `write`, and `subscription` events.\n\nTo wake up your app even after it is killed by the OS, set the `restoreState` option to true **before** starting any FBP work**:\n\n```\nFlutterBluePlus.setOptions(restoreState: true);\n```\n\n**Note**: Upon being woken up, an app has around 10 seconds to complete a task. Apps that spend too much time executing in the background can be throttled back by the system or killed.\n\n### Multi-Device Communication\n\nWe recommend setting per-device queueing.\n\n```dart\nFlutterBluePlus.setOperationQueueMode(OperationQueueMode.perDevice);\n```\n\nThis allows BLE operations on different devices to run at the same time.\n`OperationQueueMode.global` remains the default only for backward compatibility.\nChanging it after BLE work has started throws an error.\n\n### Android\n\nYou can try using https:\u002F\u002Fpub.dev\u002Fpackages\u002Fflutter_foreground_task or possibly https:\u002F\u002Fpub.dev\u002Fpackages\u002Fworkmanager\n\n## API Reference\n\nNote: When functionality is unsupported on a platform, sensible defaults are returned instead of an error.\n\n* 🌀 = Stream\n* ⚡ = Synchronous\n* 🔥 = Can fail\n\n|                     | Android | iOS | Linux | macOS | Web | Description                                                 |\n|---------------------|---------|-----|-------|-------|-----|-------------------------------------------------------------|\n| setLogLevel         | ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Configure plugin log level                                  |\n| setOptions          | ✔️      | ✔️  | ❌     | ✔️    | ❌   | Set configurable bluetooth options                          |\n| setOperationQueueMode ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Configure whether BLE operations queue globally or per-device |\n| isSupported         | ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Checks whether the device supports Bluetooth                |\n| turnOn            🔥| ✔️      | ❌   | ✔️    | ❌     | ❌   | Turns on the bluetooth adapter                              |\n| turnOff           🔥| ✔️      | ❌   | ✔️    | ❌     | ❌   | Turns off the bluetooth adapter                             |\n| adapterStateNow    ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Current state of the bluetooth adapter                      |\n| adapterState      🌀| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Stream of on & off states of the bluetooth adapter          |\n| startScan         🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Starts a scan for Ble devices                               |\n| stopScan          🔥| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Stop an existing scan for Ble devices                       |\n| onScanResults   🌀🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of live scan results                                 |\n| scanResults     🌀🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of live scan results or previous results             |\n| lastScanResults    ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The most recent scan results                                |\n| isScanning        🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of current scanning state                            |\n| isScanningNow      ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Is a scan currently running?                                |\n| connectedDevices   ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | List of devices connected to *your app*                     |\n| systemDevices     🔥| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | List of devices connected to the system, even by other apps |\n| getPhySupport       | ✔️      | ❌   | ❌     | ❌     | ❌   | Get supported bluetooth phy codings                         |\n\n### FlutterBluePlus Events API\n\n|                            | Android | iOS | Linux | macOS | Web | Description                                            |\n|----------------------------|---------|-----|-------|-------|-----|--------------------------------------------------------|\n| onConnectionStateChanged 🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of connection changes of *all devices*          |\n| onMtuChanged             🌀| ✔️      | ✔️  | ❌     | ✔️    | ❌   | Stream of mtu changes of *all devices*                 |\n| onReadRssi               🌀| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Stream of rssi reads of *all devices*                  |\n| onServicesReset          🌀| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Stream of services resets of *all devices*             |\n| onDiscoveredServices     🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of services discovered of *all devices*         |\n| onCharacteristicReceived 🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of characteristic value reads of *all devices*  |\n| onCharacteristicWritten  🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of characteristic value writes of *all devices* |\n| onDescriptorRead         🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of descriptor value reads of *all devices*      |\n| onDescriptorWritten      🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of descriptor value writes of *all devices*     |\n| onBondStateChanged       🌀| ✔️      | ❌   | ✔️    | ❌     | ❌   | Stream of bond state changes of *all devices*          |\n| onNameChanged            🌀| ❌       | ✔️  | ✔️    | ✔️    | ❌   | Stream of name changes of *all devices*                |\n\n### BluetoothDevice API\n\n|                             | Android | iOS | Linux | macOS | Web | Description                                                |\n|-----------------------------|---------|-----|-------|-------|-----|------------------------------------------------------------|\n| platformName               ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The platform preferred name of the device                  |\n| advName                    ⚡| ✔️      | ✔️  | ❌     | ✔️    | ❌   | The advertised name of the device found during scanning    |\n| connect                   🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Establishes a connection to the device                     |\n| disconnect                🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Cancels an active or pending connection to the device      |\n| isConnected                ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Is this device currently connected to *your app*?          |\n| isDisconnected             ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Is this device currently disconnected from *your app*?     |\n| connectionState           🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of connection changes for the Bluetooth Device      |\n| discoverServices          🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Discover services                                          |\n| servicesList               ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The current list of available services                     |\n| onServicesReset           🌀| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | The services changed & must be rediscovered                |\n| mtu                       🌀| ✔️      | ✔️  | ❌     | ✔️    | ❌   | Stream of current mtu value + changes                      |\n| mtuNow                     ⚡| ✔️      | ✔️  | ❌     | ✔️    | ❌   | The current mtu value                                      |\n| readRssi                  🔥| ✔️      | ✔️  | ✔️    | ✔️    | ❌   | Read RSSI from a connected device                          |\n| requestMtu                🔥| ✔️      | ❌   | ❌     | ❌     | ❌   | Request to change the MTU for the device                   |\n| requestConnectionPriority 🔥| ✔️      | ❌   | ❌     | ❌     | ❌   | Request to update a high priority, low latency connection  |\n| bondState                 🌀| ✔️      | ❌   | ✔️    | ❌     | ❌   | Stream of device bond state. Can be useful on Android      |\n| createBond                🔥| ✔️      | ❌   | ✔️    | ❌     | ❌   | Force a system pairing dialogue to show, if needed         |\n| removeBond                  | ✔️      | ❌   | ✔️    | ❌     | ❌   | Remove Bluetooth Bond of device                            |\n| setPreferredPhy             | ✔️      | ❌   | ❌     | ❌     | ❌   | Set preferred RX and TX phy for connection and phy options |\n| clearGattCache              | ✔️      | ❌   | ❌     | ❌     | ❌   | Clear android cache of service discovery results           |\n\n### BluetoothCharacteristic API\n\n|                   | Android | iOS | Linux | macOS | Web | Description                                                     |\n|-------------------|---------|-----|-------|-------|-----|-----------------------------------------------------------------|\n| uuid             ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The uuid of characteristic                                      |\n| read            🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Retrieves the value of the characteristic                       |\n| write           🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Writes the value of the characteristic                          |\n| setNotifyValue  🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Sets notifications or indications on the characteristic         |\n| isNotifying      ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Are notifications or indications currently enabled              |\n| onValueReceived 🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of characteristic value updates received from the device |\n| lastValue        ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The most recent value of the characteristic                     |\n| lastValueStream 🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of onValueReceived + writes                              |\n\n### BluetoothDescriptor API\n\n|                   | Android | iOS | Linux | macOS | Web | Description                               |\n|-------------------|---------|-----|-------|-------|-----|-------------------------------------------|\n| uuid             ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The uuid of descriptor                    |\n| read            🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Retrieves the value of the descriptor     |\n| write           🔥| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Writes the value of the descriptor        |\n| onValueReceived 🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of descriptor value reads & writes |\n| lastValue        ⚡| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | The most recent value of the descriptor   |\n| lastValueStream 🌀| ✔️      | ✔️  | ✔️    | ✔️    | ✔️  | Stream of onValueReceived + writes        |\n\n## Debugging\n\nThe easiest way to debug issues in FlutterBluePlus is to make your own local copy.\n\n```\ncd \u002Fuser\u002Fdownloads\ngit clone https:\u002F\u002Fgithub.com\u002Fchipweinberger\u002Fflutter_blue_plus.git\n```\n\nthen in `pubspec.yaml` add the repo by path:\n\n```\n  flutter_blue_plus:\n    path: \u002Fuser\u002Fdownloads\u002Fflutter_blue_plus\n```\n\nNow you can edit the FlutterBluePlus code yourself.\n\n## Common Problems\n\nMany common problems are easily solved.\n\nAdapter:\n- [bluetooth must be turned on](#bluetooth-must-be-turned-on)\n- [adapterState is not 'on' but my Bluetooth is on](#adapterstate-is-not-on-but-my-bluetooth-is-on)\n- [adapterState is called multiple times](#adapterstate-is-called-multiple-times)\n\nScanning:\n- [Scanning does not find my device](#scanning-does-not-find-my-device)\n- [Scanned device never goes away](#scanned-device-never-goes-away)\n- [iBeacons not showing](#ibeacons-not-showing)\n\nConnecting:\n- [Connection fails](#connection-fails)\n- [connectionState is called multiple times](#connectionstate-is-called-multiple-times)\n- [remoteId is different on Android vs iOS](#the-remoteid-is-different-on-android-versus-ios--macos)\n- [iOS: \"[Error] The connection has timed out unexpectedly.\"](#ios-error-the-connection-has-timed-out-unexpectedly)\n\nReading & Writing:\n- [List of Bluetooth GATT Errors](#list-of-bluetooth-gatt-errors)\n- [Characteristic write fails](#characteristic-write-fails)\n- [Characteristic read fails](#characteristic-read-fails)\n\nSubscriptions:\n- [onValueReceived is never called (or lastValueStream)](#onvaluereceived-is-never-called-or-lastvaluestream)\n- [onValueReceived data is split up (or lastValueStream)](#onvaluereceived-data-is-split-up-or-lastvaluestream)\n- [onValueReceived is called with duplicate data (or lastValueStream)](#onvaluereceived-is-called-with-duplicate-data-or-lastvaluestream)\n\nAndroid Errors:\n- [ANDROID_SPECIFIC_ERROR](#android_specific_error)\n- [android pairing popup appears twice](#android-pairing-popup-appears-twice)\n\nFlutter Errors:\n- [MissingPluginException(No implementation found for method XXXX ...)](#missingpluginexceptionno-implementation-found-for-method-xxxx-)\n\n---\n\n### \"bluetooth must be turned on\"\n\nYou need to wait for the bluetooth adapter to fully turn on. \n\n`await FlutterBluePlus.adapterState.where((state) => state == BluetoothAdapterState.on).first;`\n\nYou can also use `FlutterBluePlus.adapterState.listen(...)`. See [Usage](#usage).\n\n---\n\n### adapterState is not 'on' but my Bluetooth is on\n\n**For iOS:**\n\n`adapterState` always starts as `unknown`. You need to wait longer for the service to initialize. As simple as:\n\n```\nif (await FlutterBluePlus.adapterState.first == BluetoothAdapterState.unknown) {\n    await Future.delayed(const Duration(seconds: 1));\n}\n```\n\nIf `adapterState` is `unavailable`, you must add access to Bluetooth Hardware in the app's Xcode settings. See [Getting Started](#getting-started).\n\n**For Android:**\n\nCheck that your device supports Bluetooth & has permissions.\n\n---\n\n### adapterState is called multiple times\n\nYou are forgetting to cancel the original `FlutterBluePlus.adapterState.listen` resulting in multiple listeners.\n\n```dart\n\u002F\u002F tip: using ??= makes it easy to only make new listener when currently null\nfinal subscription ??= FlutterBluePlus.adapterState.listen((value) {\n    \u002F\u002F ...\n});\n\n\u002F\u002F also, make sure you cancel the subscription when done!\nsubscription.cancel()\n```\n\n---\n\n### Scanning does not find my device\n\n**1. you're using an emulator**\n\nUse a physical device.\n\n**2. try using another ble scanner app**\n\n* **iOS**: [nRF Connect](https:\u002F\u002Fapps.apple.com\u002Fus\u002Fapp\u002Fnrf-connect-for-mobile\u002Fid1054362403)\n* **Android**: [BLE Scanner](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.macdom.ble.blescanner)\n\nInstall a BLE scanner app on your phone. Can it find your device?\n\n**3. your device uses bluetooth classic, not BLE.**\n\nHeadphones, speakers, keyboards, mice, gamepads, & printers all use Bluetooth Classic. \n\nThese devices may be found in System Settings, but they cannot be connected to by FlutterBluePlus. FlutterBluePlus only supports Bluetooth Low Energy.\n\n**4. your device stopped advertising.**\n\n- you might need to reboot your device\n- you might need to put your device in \"discovery mode\"\n- your phone may have already connected automatically\n- another app may have already connected to your device\n- another phone may have already connected to your device\n\nTry looking through system devices:\n\n```dart\n\u002F\u002F search system devices. i.e. any device connected to by *any* app\nList\u003CBluetoothDevice> system = await FlutterBluePlus.systemDevices;\nfor (var d in system) {\n    print('${r.device.platformName} already connected to! ${r.device.remoteId}');\n    if (d.platformName == \"myBleDevice\") {\n         await r.connect(); \u002F\u002F must connect our app\n    }\n}\n```\n\n**5. your scan filters are wrong.**\n\n- try removing all scan filters\n- for `withServices` to work, your device must actively advertise the serviceUUIDs it supports\n\n**6. Android: you're calling startScan too often**\n\nOn Adroid you can only call `startScan` 5 times per 30 second period. This is a platform restriction.\n\n**7. Android: make sure location services are enabled**\n\nAndroid requires location services to allow bluetooth scanning.\n\n---\n\n### Scanned device never goes away\n\nThis is expected.\n\nYou must set the `removeIfGone` scan option if you want the device to go away when no longer available.\n\n---\n\n### iBeacons Not Showing\n\n**iOS:**\n\niOS does not support iBeacons using CoreBluetooth. You must find a plugin meant for CoreLocation.\n\n**Android:**\n\n1. you need to enable location permissions, see [Getting Started](#getting-started)\n2. you must pass `androidUsesFineLocation:true` to the `startScan` method.\n\n---\n\n### Connection fails\n\n**1. Your ble device may be low battery**\n\nBluetooth can become erratic when your peripheral device is low on battery.\n\n**2. Your ble device may have refused the connection or have a bug**\n\nConnection is a two-way process. Your ble device may be misconfigured.\n\n**3. You may be on the edge of the Bluetooth range.**\n\nThe signal is too weak, or there are a lot of devices causing radio interference.\n\n**4. Some phones have an issue connecting while scanning.**\n\nThe Huawei P8 Lite is one of the reported phones to have this issue. Try stopping your scanner before connecting.\n\n**5. Try restarting your phone**\n\nBluetooth is a complicated system service, and can enter a bad state.\n\n---\n\n### connectionState is called multiple times\n\nYou are forgetting to cancel the original `device.connectionState.listen` resulting in multiple listeners.\n\n```dart\n\u002F\u002F tip: using ??= makes it easy to only make new listener when currently null\nfinal subscription ??= FlutterBluePlus.device.connectionState.listen((value) {\n    \u002F\u002F ...\n});\n\n\u002F\u002F also, make sure you cancel the subscription when done!\nsubscription.cancel()\n```\n\n---\n\n### The remoteId is different on Android versus iOS & macOS\n\nThis is expected. There is no way to avoid it.\n\nFor privacy, iOS & macOS use a randomly generated uuid. This uuid will periodically change.\n\ne.g. `6920a902-ba0e-4a13-a35f-6bc91161c517`\n\nAndroid uses the mac address of the bluetooth device. It never changes.\n\ne.g. `05:A4:22:31:F7:ED`\n\n---\n\n### iOS: \"[Error] The connection has timed out unexpectedly.\"\n\nYou can google this error. It is a common iOS ble error code.\n\nIt means your device stopped working. FlutterBluePlus cannot fix it.\n\n---\n\n### List of Bluetooth GATT Errors\n\nThese GATT error codes are part of the BLE Specification. \n\n**These are *responses* from your ble device because you are sending an invalid request.**\n\nFlutterBluePlus cannot fix these errors. You are doing something wrong & your device is responding with an error.\n\n**GATT errors as they appear on iOS**:\n```\napple-code: 1  | The handle is invalid.\napple-code: 2  | Reading is not permitted.\napple-code: 3  | Writing is not permitted.\napple-code: 4  | The command is invalid.\napple-code: 6  | The request is not supported.\napple-code: 7  | The offset is invalid.\napple-code: 8  | Authorization is insufficient.\napple-code: 9  | The prepare queue is full.\napple-code: 10 | The attribute could not be found.\napple-code: 11 | The attribute is not long.\napple-code: 12 | The encryption key size is insufficient.\napple-code: 13 | The value's length is invalid.\napple-code: 14 | Unlikely error.\napple-code: 15 | Encryption is insufficient.\napple-code: 16 | The group type is unsupported.\napple-code: 17 | Resources are insufficient.\napple-code: 18 | Unknown ATT error.\n```\n\n**GATT errors as they appear on Android**:\n```\nandroid-code: 1  | GATT_INVALID_HANDLE\nandroid-code: 2  | GATT_READ_NOT_PERMITTED\nandroid-code: 3  | GATT_WRITE_NOT_PERMITTED\nandroid-code: 4  | GATT_INVALID_PDU\nandroid-code: 5  | GATT_INSUFFICIENT_AUTHENTICATION\nandroid-code: 6  | GATT_REQUEST_NOT_SUPPORTED\nandroid-code: 7  | GATT_INVALID_OFFSET\nandroid-code: 8  | GATT_INSUFFICIENT_AUTHORIZATION\nandroid-code: 9  | GATT_PREPARE_QUEUE_FULL\nandroid-code: 10 | GATT_ATTR_NOT_FOUND\nandroid-code: 11 | GATT_ATTR_NOT_LONG\nandroid-code: 12 | GATT_INSUFFICIENT_KEY_SIZE\nandroid-code: 13 | GATT_INVALID_ATTRIBUTE_LENGTH\nandroid-code: 14 | GATT_UNLIKELY\nandroid-code: 15 | GATT_INSUFFICIENT_ENCRYPTION\nandroid-code: 16 | GATT_UNSUPPORTED_GROUP\nandroid-code: 17 | GATT_INSUFFICIENT_RESOURCES\n```\n\n**Descriptions**:\n```\n1   | Invalid Handle                 | The attribute handle given was not valid on this server.\n2   | Read Not Permitted             | The attribute cannot be read.\n3   | Write Not Permitted            | The attribute cannot be written.\n4   | Invalid PDU                    | The attribute PDU was invalid.\n5   | Insufficient Authentication    | The attribute requires authentication before it can be read or written.\n6   | Request Not Supported          | Attribute server does not support the request received from the client.\n7   | Invalid Offset                 | Offset specified was past the end of the attribute.\n8   | Insufficient Authorization     | The attribute requires an authorization before it can be read or written.\n9   | Prepare Queue Full             | Too many prepare writes have been queued.\n10  | Attribute Not Found            | No attribute found within the given attribute handle range.\n11  | Attribute Not Long             | The attribute cannot be read or written using the Read Blob or Write Blob requests.\n12  | Insufficient Key Size          | The Encryption Key Size used for encrypting this link is insufficient.\n13  | Invalid Attribute Value Length | The attribute value length is invalid for the operation.\n14  | Unlikely Error                 | The request has encountered an unlikely error and cannot be completed.\n15  | Insufficient Encryption        | The attribute requires encryption before it can be read or written.\n16  | Unsupported Group Type         | The attribute type is not a supported grouping as defined by a higher layer.\n17  | Insufficient Resources         | Insufficient Resources to complete the request.\n```\n\n---\n\n### characteristic write fails\n\nFirst, check the [List of Bluetooth GATT Errors](#list-of-bluetooth-gatt-errors) for your error.\n\n**1. your bluetooth device turned off, or is out of range**\n\nIf your device turns off or crashes during a write, it will cause a failure.\n\n**2. Your Bluetooth device has bugs**\n\nMaybe your device crashed, or is not sending a response due to software bugs.\n\n**3. there is radio interference**\n\nBluetooth is wireless and will not always work.\n\n---\n\n### Characteristic read fails\n\nFirst, check the [List of Bluetooth GATT Errors](#list-of-bluetooth-gatt-errors) for your error.\n\n**1. your bluetooth device turned off, or is out of range**\n\nIf your device turns off or crashes during a read, it will cause a failure.\n\n**2. Your Bluetooth device has bugs**\n\nMaybe your device crashed, or is not sending a response due to software bugs.\n\n**3. there is radio interference**\n\nBluetooth is wireless and will not always work.\n\n---\n\n### onValueReceived is never called (or lastValueStream)\n\n**1. you are not calling the right function**\n\n`lastValueStream` will receive data for `chr.read()` & `chr.write()` & `chr.setNotifyValue(true)` \n\n`onValueReceived` will receive data for `chr.read()` & `chr.setNotifyValue(true)` \n\n**2. your device has nothing to send**\n\nIf you are using `chr.setNotifyValue(true)`, your _device_ chooses when to send data.\n\nTry interacting with your device to get it to send new data.\n\n**3. your device has bugs**\n\nTry rebooting your ble device. \n\nSome ble devices have buggy software and stop sending data\n\n---\n\n### onValueReceived data is split up (or lastValueStream)\n\nVerify that the mtu is large enough to hold your message.\n\n```dart\ndevice.mtu\n```\n\nIf it still happens, it is a problem with your peripheral device.\n\n---\n\n### onValueReceived is called with duplicate data (or lastValueStream)\n\nYou are probably forgetting to cancel the original `chr.onValueReceived.listen` resulting in multiple listens.\n\nThe easiest solution is to use `device.cancelWhenDisconnected(subscription)` to cancel device subscriptions.\n\n```dart\nfinal subscription = chr.onValueReceived.listen((value) {\n    \u002F\u002F ...\n});\n\n\u002F\u002F make sure you have this line!\ndevice.cancelWhenDisconnected(subscription);\n\nawait characteristic.setNotifyValue(true);\n```\n\n---\n\n### ANDROID_SPECIFIC_ERROR\n\nThere is no 100% solution.  \n\nFBP already has mitigations for this error, but Android will still fail with this code randomly. \n\nThe recommended solution is to `catch` the error, and retry.\n\n---\n\n### android pairing popup appears twice\n\nThis is a bug in android itself.\n\nYou can call `createBond()` yourself just after connecting and this will resolve the issue.\n\n---\n\n### MissingPluginException(No implementation found for method XXXX ...)\n\nIf you just added flutter_blue_plus to your pubspec.yaml, a hot reload \u002F hot restart is not enough.\n\nYou need to fully stop your app and run again so that the native plugins are loaded.\n\nAlso try `flutter clean`.\n\n\n\n\n","FlutterBluePlus 是一个用于 Flutter 的插件，支持在 Android、iOS、macOS、Web、Linux 和 Windows 平台上与低功耗蓝牙设备进行连接和通信。其核心功能包括全面的跨平台支持，涵盖几乎所有 BLE 中央角色的功能，并且不依赖于任何外部库，只需 Flutter 及其基础平台的支持即可运行。适用于需要实现蓝牙低能耗设备交互的各种应用场景，如智能家居控制、健康监测设备数据收集等。该项目由 Jamcorder 赞助，对于个人、非营利组织及教育机构免费使用；商业用途则需购买商业许可证。",2,"2026-06-11 03:23:06","top_language"]