layrz_ble

Pub version Pub Points likes GitHub license

A simple way to interact with BLE devices in Flutter.

Why should I use this library?

Other libraries on the market are either too complex to use, or does not fully support functionalities like reading service data from the advertisement, or crop the manufacturer data, our objective is provide a fully functional library, with all of the ideal capabilities of a BLE library for Flutter.

For example, most of the libraries out there requires services and characteristics discovered before interacting with the device, but we auto-discover that for you, in this way, you will never forget about the services and characteristics of the device.

Functionalities available per platform

Scanning and connecting

Feature Android iOS macOS Windows Web Linux Method(s)
Scan for BLE devices startScan, stopScan and onScan
Connect to BLE devices connect and onEvent
Disconnect from BLE devices disconnect and onEvent
Negotiate a new MTU 🟨 🟨 setMtu
Get services and characteristics discoverServices
Read from characteristics readCharacteristic
Write to characteristics writeCharacteristic
Subscribe to characteristic notifications startNotify, stopNotify and onNotify
Multi-connection support Read below

Advertising and GATT server

Feature Android iOS macOS Windows Web Linux Method(s)
Advertise (On Bluetooth 4 or 5) ✅* startAdvertise and stopAdvertise
Services and characteristics respondReadRequest and respondWriteRequest
Notifications sendNotification
  • On Android, the stop advertisement does not disconnect the connected devices. Be careful with that.

Languages used

Platform Language
Android Kotlin
iOS Swift
macOS Swift
Windows C++
Web Dart
Linux Dart

Multiple connections

We're not expecting to extend the support of multiple connections on this library at the moment, feel free to add it in your platform and send us a pull request, we're happy to review it and merge it.

MTU thing...

🟨 : Well, Windows (Directly on C++) and Linux (through bluez package) does not support the capability to negotiate the MTU, but yes to return the max MTU allowed, so, when you call setMtu you will receive the max allowed from the APIs, not a negotiated value. And why this value is important? Well, you have a size limit of the things that you want to send to your device, knowing the MTU helps to adjusts your packets sizes before sending it to the device.

❌ : Web does not support neither negotiate nor getting the MTU, so, when you call setMtu you will receive a null value. Why a null instead of an error? Well, right now (early 2025) the Web Bluetooth API does not support the MTU, but it's on the roadmap to be implemented, so, we are returning a null value to indicate that the feature is not available yet, hopefully, this will change in the future.

Minimum requirements

Android

6.0 Marshmallow (API Level 23) or later. Be careful with the permissions!.

iOS

iOS 14.0 or later.

macOS

11.0 Big Sur or later.

Windows

Windows 10.0 or later (Like as the versions supported by Flutter).

Web

Chromium-based browsers:

  • Google Chrome 56 or later
  • Microsoft Edge 79 or later
  • Opera 43 or later
  • Google Chrome Android 56 or later
  • Samsung Internet 6.0 or later

Unfortunatelly, neither of these browsers supports Bluetooth API:

  • Mozilla Firefox
  • Apple Safari
  • Google Android WebView
  • Apple iOS WebView

Linux

We think that any Linux distribution supported by Flutter with bluez stack installed should work, but we tested on Ubuntu 24.04 LTS.

Usage

To use this plugin, add layrz_ble as a dependency in your pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter
  layrz_ble: ^latest_version

Then you can import the package in your Dart code:

import 'package:layrz_ble/layrz_ble.dart';

/// ...

final ble = LayrzBle();

/// Listen for events
///
/// `BleEvent` is from this package
ble.onEvent.listen((BleEvent event) {
  debugPrint(event);
});

/// Listen for device discovery
///
/// `BleDevice` is from `layrz_models` package, but we exported it here for convenience
ble.onScan.listen((BleDevice device) {
  debugPrint(device);
});

/// Listen for notifications
///
/// `BleCharacteristicNotification` is from this package
ble.onNotify.listen((BleCharacteristicNotification notification) {
  debugPrint(notification);
});

/// GATT events, only for advertising
///
/// This class is a sealed class, so, you should use `gattUpdate is <class>` to check the type of the event
/// 
/// `GattConnected` triggers when a device is connected to the GATT server
/// `GattDisconnected` triggers when a device is disconnected from the GATT server
/// `GattReadRequest` triggers when a device requested to read a characteristic from the GATT server
/// `GattWriteRequest` triggers when a device requested to write a characteristic from the GATT server
/// `GattMtuChanged` triggers when the devices negotiates new the MTU size
ble.onGattUpdate.listen((BleGattUpdate gattUpdate) {
  debugPrint(gattUpdate);
});

/// Check capabilities returns `true` if the device is capable of BLE, `false` otherwise
final bool capabilities = await ble.checkCapabilities();

/// Check scan permissions
final bool permissions = await ble.checkScanPermissions();

/// Check advertise permissions
final bool permissions = await ble.checkAdvertisePermissions();

/// Scan for BLE devices
final bool startResult = await ble.startScan();

/// Stop scanning
final bool stopResult = await ble.stopScan();

/// Advertise
final bool advertise = await ble.startAdvertise(
  manufacturerData: [ // <- Defines the manufacturer data to be advertised
    const BleManufacturerData(
      companyId: 0xffff,
      data: [0xff],
    ),
  ],
  serviceData: [ // <- Defines the service data to be advertised
    const BleServiceData(
      uuid: 0xffff,
      data: [0xff],
    ),
  ],
  canConnect: true, // <- Indicates that the advertisement is connectable
  allowBluetooth5: true, // <- Indicates that the advertisement can use Bluetooth 5 features if is available
  servicesSpecs: [ // <- Defines the services and characteristics to be advertised
    const BleService(
      uuid: '00000000-0000-0000-0000-000000000001',
      characteristics: [
        BleCharacteristic(
          uuid: '00000000-0000-0000-0000-000000000002',
          properties: [
            BleProperty.read,
            BleProperty.notify,
          ],
        ),
        BleCharacteristic(
          uuid: '00000000-0000-0000-0000-000000000003',
          properties: [BleProperty.write],
        ),
      ],
    )
  ],
);

Disclaimer about some classes used on this library

Part of the classes used on this library are from the layrz_models package.

BleDevice         // Defines the BLE device itself, and of course the packet data separated on manufacturer and service data
BleService        // Defines the service, with the UUID and the characteristics
BleCharacteristic // Defines the characteristic, with the UUID and the properties (In a enum format to be easy to use)
BleProperty       // Defines the properties of the characteristic, with the most common properties defined.

Of course, if you think that you need more attributes, or do you want to add other, feel free to request it on layrz_ble repository or in the layrz_models repository if you already has the changes done on the layrz_ble package. We are open to contributions and suggestions.

Permissions and requirements

Before getting into the platform specific permissions, always raises the question "How can I handle the permissions on my Flutter app?". Well, you can use the permission_handler package to handle the permissions on your Flutter app, or you can handle them manually with native code, the choice is yours.

Android

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <!-- Location is required for BLE scan, required since Android 10 (API Level 29) -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Of course, Bluetooth -->
  <uses-permission android:name="android.permission.BLUETOOTH" />

  <!--
  Required for BLE scan 
  
  Uses or BLUETOOTH_SCAN or BLUETOOTH_ADMIN permission depending on the API level.
  If your app has a minSdkVersion of 31 or above, you should use BLUETOOTH_SCAN permission only,
  otherwise we strongly recommend using both as shown below.
  -->

  <!-- android:usesPermissionFlags="neverForLocation" is for tell Android that you dont want location,
       but if you want to scan iBeacons or smart tags, you need to enable this -->
  <uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation"
    android:minSdkVersion="31" /> <!-- This permission is only for API level 31 or above -->
    
  <uses-permission
    android:name="android.permission.BLUETOOTH_ADMIN"
    android:maxSdkVersion="30" /> <!-- This permission is only for API level 30 or below -->

  <!-- Required for BLE connection, in all API Levels -->
  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

  <!-- If you want to advertise and create a GATT server, you'll need to add this lines -->
  <!-- Required for BLE advertising -->
  <uses-permission
    android:name="android.permission.BLUETOOTH_ADVERTISE"
    android:minSdkVersion="23" />

  <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

  <!-- ... -->
</manifest>

iOS

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <!-- ... -->
  <!-- Required for BLE -->
  <key>NSBluetoothAlwaysUsageDescription</key>
  <string>The app need access to the Bluetooth to extract sensor values and diagnostics of the devices</string>
  <key>NSBluetoothPeripheralUsageDescription</key>
  <string>The app need access to the Bluetooth to do a remote configuration of the devices compatible with</string>
  <!-- ... -->
</dict>
</plist>

macOS

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <!-- ... -->
  <!-- Required for BLE -->
  <key>NSBluetoothAlwaysUsageDescription</key>
  <string>This app uses Bluetooth to connect to your device.</string>
  <!-- ... -->
</dict>
</plist>

Windows

If you use msix package to build your Windows app, you need to declare the permission for Bluetooth, this is an example of how to do it on your pubspec.yaml

msix_config:
  capabilities: bluetooth,radios

More information about the capabilities on Windows can be found on Microsoft documentation

Web

Nothing to do here :)

Linux

Your platform should have bluez stack installed to work, otherwise the lib will not work.

Roadmap

⬜ Permission support for each platform

FAQ

Why on some platforms I'm getting an UUID instead of a Mac Address?

On web, Bluetooth API does not allow developers to access the MAC Address of the devices, instead, it returns a randomly generated string for the device. Be careful with this string, is not an unique identifier along the time and devices. More information on mdn BluetoothDevice id property.

On Apple ecosystem (aka, iOS, iPadOS and macOS), Apple privacy policies are very strict, and they don't allow developers to access the MAC Address of the devices, instead, Apple OSs return a UUID for the device. Be careful with this UUID, is not an unique identifier along the time and devices. More information on Apple Developer CBPeripheral entity documentation

In Web, why I need to supply the services and characteristics?

This is a limitation of the Web Bluetooth API, you need to supply the services and characteristics to interact with the device. This is a security measure to prevent malicious websites to interact with your devices.

What's the target of the advertisement segment of this library?

We are targeting to provide support for Android at the moment, later maybe we will add support for other platforms, but right now, we are focusing on Android.

Why is this package called layrz_ble?

All packages developed by Layrz are prefixed with layrz_, check out our other packages on pub.dev.

I need to pay to use this package?

No! This library is free and open source, you can use it in your projects without any cost, but if you want to support us, give us a thumbs up here in pub.dev and star our Repository!

Can I contribute to this package?

Yes! We are open to contributions, feel free to open a pull request or an issue on the Repository!

I have a question, how can I contact you?

If you need more assistance, you open an issue on the Repository and we're happy to help you :)

License

This project is licensed under the MIT License - see the LICENSE file for details.

This project is maintained by Golden M with authorization of Layrz LTD.

Who are you? / Want to work with us?

Golden M is a software and hardware development company what is working on a new, innovative and disruptive technologies. For more information, contact us at sales@goldenm.com or via WhatsApp at +(507)-6979-3073.