Flutter Bluetooth tutorial banner showcasing BLE integration

Integrating Bluetooth Low Energy (BLE) functionality into Flutter apps can be a daunting task, but with the right tools, it becomes a seamless experience. Flutter Blue Plus is a powerful plugin designed to simplify Flutter Bluetooth integration, allowing developers to focus on crafting innovative applications rather than wrestling with complex Bluetooth APIs. By supporting the BLE Central Role, Flutter Blue Plus enables your apps to connect and interact with a wide range of BLE devices, from fitness trackers to smart home gadgets, across both Android and iOS platforms. Whether you’re building a health monitoring app or a smart home controller, Flutter Bluetooth BLE provides the robust and reliable foundation needed to bring your BLE-enabled vision to life. If you’re looking to work with professionals who can expertly handle this integration, partnering with a flutter app development company can ensure a smooth development process. In this blog post, we’ll explore how to leverage Flutter Blue Plus to integrate Bluetooth Low Energy (BLE) functionality into your Flutter apps, covering everything from setup to advanced features like device connection management and data exchange.

For this guide, we will be using the flutter_ble_plus package and we will be creating a virtual peripheral device using the LightBlue simulator.

Let’s dive into how to create virtual peripheral devices using the LightBlue iOS app.

Flutter Bluetooth debugging interface showing error and connection logs

Step 1: Create a Virtual BLE Peripheral Device Using LightBlue iOS App

What is the LightBlue app?

It is designed to simplify the process of discovering, connecting, and interacting with BLE devices, making it an essential tool for developers, engineers, and hobbyists working with Bluetooth Low Energy (BLE) technology.

On iOS, LightBlue can transform the device into a virtual BLE peripheral with customizable services and characteristics. This feature is invaluable for prototyping and testing BLE applications before physical hardware is available. If you are looking for professional help, you can hire Flutter developers to assist you in integrating such advanced features into your app.

List of Bluetooth peripheral devices connected to Flutter app

Use Cases for LightBlue App in BLE Development

1. BLE Development: Developers use LightBlue to test and debug their BLE applications, ensuring compatibility with various Bluetooth Low Energy devices.

2. IoT Prototyping: The virtual device feature allows developers to simulate BLE peripherals and test IoT applications without needing physical hardware.

3. Troubleshooting: LightBlue helps troubleshoot Bluetooth connectivity issues by analyzing connection parameters and inspecting data packets.

4. Education and Learning: It serves as a learning tool for understanding BLE protocols and interactions.

Create Virtual BLE Peripheral with LightBlue iOS App

To create a virtual BLE peripheral using LightBlue, follow these steps:

Step 1: Launch the LightBlue app on your iOS device:
Note: The virtual device simulation is currently only available on iOS.

Step 2: Navigate to Virtual Devices: 
Tap on the “Virtual Devices” tab in the app.

Step 3: Create a New Virtual Device:
Tap the “+” icon in the upper right corner to create a new virtual BLE device.

Step 4: Select Device Type:
Choose the type of virtual device you want to simulate. This could be a generic device or a specific type (e.g., a heart rate monitor). We will be using the “Blank” type. Later you can rename it as per your choice.

Step 5:  Customize Services and Characteristics:

  • Once the device is created, you can customize its services and characteristics to mimic the behavior of a real BLE device.
  • Add custom characteristics and configure them to send notifications or indications as needed.
  • We are going to create AAA0, AAE0, AAF0, and AAC0 as services.
  • AAA1, AAE1, AAF,1 and AAC1 characteristics respectively in these services.

Step 6: Save and Use the Virtual Device: 
After configuring your virtual device, save it and select it from the list to begin testing.

Mobile app using LightBlue as a peripheral device in Flutter

In this guide, the app will be in a central role, and the LightBlue virtual device will be in a peripheral role.

What are central and peripheral roles?

Central:

A central device acts as the client, scanning for and connecting to BLE peripherals. It receives data from peripherals and uses it to perform tasks. Common examples include smartphones or tablets that connect to heart rate monitors or fitness trackers via Flutter Bluetooth.

Peripheral:

A peripheral device acts as the server, publishing data that can be accessed by central devices. It advertises its services and responds to requests from central devices. Examples include heart rate monitors, fitness trackers, or smart home devices that can be connected through Flutter BLE.

Boost your business growth with a stunning Flutter app for seamless Bluetooth integration

Step 2:  Add flutter_blue_plus as a dependency

Add ‘flutter_blue_plus’to your pubspec.yaml

dependencies:
 flutter:
   sdk: flutter
 flutter_blue_plus: ^1.32.12Code language: CSS (css)

And run pub get command to install the dependencies.

Bluetooth pairing screen displaying devices available for connection

Step 3. Add Permissions for Bluetooth

iOS

In the Info.plist let’s add the Bluetooth usage permission:

Permission settings for iOS Bluetooth integration in Flutter

Android

In the AndroidManifest.xml let’s add:

Permission settings for Android Bluetooth integration in Flutter

Step 4: Scanning Bluetooth Devices

Include the flutter_blue_plus package in the file where you intend to scan for BLE devices and implement the following startScanning function to begin scanning for Bluetooth devices. The app will begin scanning for BLE devices and then display the discovered devices in a ListView. As a first step, let’s add a List to our MyHomePage class to store the device information. And then implement the scanning function.

void startScanning() async {
  _recordList.clear();
  await FlutterBluePlus.startScan(timeout: Duration(seconds: 5));
  FlutterBluePlus.scanResults.listen((results) {
    for (ScanResult result in results) {
      if (!_recordList.contains(result)) {
        _recordList.add(result);
        debugPrint(result.device.advName);
      }
    }
    setState(() {});
  });
}Code language: JavaScript (javascript)

With the help of the FlutterBluePlus instance of the package, we will start scanning. The startScan function offers several options for customizing your scan, such as:

  • Timeout duration: The scan will automatically stop after a specified period. 
  •  Service IDs: By providing a list of service ID GUIDs, the scan will only include BLE devices that advertise those specific service GUIDs.

FlutterBluePlus.scanResults is a stream that emits lists of ScanResult objects. By calling .listen on this stream, you can execute a callback function every time new scan results are available. This allows your app to dynamically update its UI or perform actions based on the discovered devices.

We should now have a list of Bluetooth-enabled devices within range. The next step is to establish a connection with one of these devices and display its available services and characteristics. If you’re interested in enhancing your development skills, you may also find Developing Responsive Web Apps with Flutter: A Comprehensive Guide useful, which covers how to create responsive web apps using Flutter.

Flutter app scanning for nearby Bluetooth devices

Step 5: Connect To A Device & Display Services & Characteristics

Once we tap on any device from the list, we will stop the ongoing scanning process and then connect to the device. Once successfully connected with the device, we will navigate to the new screen displaying all the services and characteristics of the device.

void connectToDevice(BluetoothDevice device) async {
 FlutterBluePlus.stopScan();
 await device.connect();
...
}Code language: JavaScript (javascript)

First, stop the ongoing scanning process. Then call the “connect” method on a selected “BluetoothDevice” with await. Note, we have marked the method async.

On the DeviceScreen page, we will have all the services for the connected device. For each service, we will display its characteristics and include buttons that indicate whether we can read, write, or receive notifications for those specific characteristics.

First of all add the list on DeviceScreen, which will hold the services of the devices. And then discover the services of the devices in the initState.

class DeviceScreen extends StatefulWidget {
. . .
final Map<Guid, List<int>> readValues = <Guid, List<int>>{};
}
class _DeviceScreenState extends State<DeviceScreen> {
. . .
List<BluetoothService> services = [];
@override
void initState() {
 super.initState();
 discoverServices();
}
. . .
void discoverServices() async {
 List<BluetoothService> services = await widget.device.discoverServices();
 setState(() {
   this.services = services;
 });
}
. . .
}Code language: PHP (php)

List the discovered services on the list view. We will add the list builder for each service to show the characteristics. Next, add the buttons, Read, Write, and Notify depending on the characteristics ability.

Now, the DeviceDetails page will look like this.

Connecting to Bluetooth device and displaying services and characteristics in Flutter

Step 6: Read, Write, and Receive Notifications From a Characteristic

In this step, we will add logic to read, write, and notify buttons. We will first add a Map to store our values by characteristic to be able to display them.

class DeviceScreen extends StatefulWidget {
  final BluetoothDevice device;
  final Map<Guid, List<int>> readValues = <Guid, List<int>>{};
}Code language: PHP (php)

6.1 Let’s add read logic.

void readValueOfCharacteristic(BluetoothCharacteristic characteristic) async {
 var sub = characteristic.lastValueStream.listen((value) {
   setState(() {
     widget.readValues[characteristic.uuid] = value;
   });
 });
 await characteristic.read();
 sub.cancel();
}Code language: JavaScript (javascript)

Here we first listen to characteristic changes and store its new value in our previously created Map. It will then update our view and display the updated value of the BLE characteristic.

6.2 We will implement the logic for when the write button is pressed.

To transmit data to the device, we will implement the following solution:

1. Create a TextField within a dialog box.

2. Link a controller to the TextField.

3. Send the content of the TextField.

So let’s add a controller instance.

class _DeviceScreenState extends State<DeviceScreen> {
  final _writeController = TextEditingController();
  List<BluetoothService> services = [];
}Code language: PHP (php)

And create our dialog with the logic inside the onPressed method of the write button:

void writeValueToCharacteristic(BluetoothCharacteristic characteristic) async {
 await showDialog(
     context: context,
     builder: (BuildContext context) {
       return AlertDialog(
         title: Text("Write"),
         content: Row(
           children: <Widget>[
             Expanded(
               child: TextField(
                 controller: _writeController,
               ),
             ),
           ],
         ),
         actions: <Widget>[
           ElevatedButton(
             child: Text("Send"),
             onPressed: () {
               characteristic.write(utf8 .encode(_writeController.value.text));
               Navigator.pop(context);
             },
           ),
           ElevatedButton(
             child: Text("Cancel"),
             onPressed: () {
               Navigator.pop(context);
             },
           ),
         ],
       );
     });
}Code language: JavaScript (javascript)

To update the characteristic’s value, we can simply call its write function. The input value should be converted to a byte array using the ‘dart:convert’ library before passing it to the write function.

Updating Bluetooth characteristic’s value in Flutter app

6.3 Let’s implement Notify

In essence, Notify functions as a callback that is automatically triggered whenever the value of the characteristic responsible for handling notifications is updated.

void setNotifyToCharacteristic(BluetoothCharacteristic characteristic) async {
 characteristic.lastValueStream.listen((value) {
   widget.readValues[characteristic.uuid] = value;
 });
 await characteristic.setNotifyValue(true);
}Code language: JavaScript (javascript)

We’ve implemented a notification system that alerts us whenever the value of the specified characteristic changes. This update also ensures that the corresponding value in our UI is automatically updated.

The DeviceDetails page after the Read, Write, and Notify implementation will look like below:

DeviceDetails page showing read, write, and notify functionality in Flutter

We’ve successfully developed a comprehensive application with the following capabilities:

  • Scan and Connect to nearby BLE devices.
  • Discover services and show their characteristics.
  • Implement Read, Write, and Notify functions for a specific Bluetooth characteristic.

Additionally, if you’re interested in adding Flutter screens to your existing Android app, be sure to check out How to Add Flutter Screens into Your Android App (Part 2). This guide walks you through the process of seamlessly integrating Flutter screens into an Android application, providing a great way to enhance your app’s functionality.

For better understanding, we’ve included a video that provides a detailed walkthrough of the Flutter BLE implementation.

Summing It Up

I hope you found this tutorial on Flutter Bluetooth Tutorial: How to implement Flutter BLE support helpful. You can download the complete source code from here.

Turn your next big idea into reality with Flutter and Bluetooth integration"

Author's Bio

Tushar Jadhav
Tushar Jadhav

Tushar Jadhav is a seasoned Mobile Technology expert with 14 years of extensive experience, currently working in Mobisoft Infotech as Principal Software Engineer. His expertise spans across diverse platforms, where he have successfully designed and implemented user-centric applications that enhance user engagement and drive business growth. Committed to staying ahead of industry trends, he thrive on transforming ideas into impactful mobile experiences that resonate with users.