flutter_bluetooth_serial_plus

pub package

Bluetooth Classic serial (RFCOMM/SPP) on Android, plus Zebra printer BLE connections on Android and iOS.

Pairing in system settings is not a connection to the printing channel. Use ZebraBle for a printer in LE controller mode, not BluetoothConnection.toAddress() (which remains Android Classic/SPP). The printer must expose Zebra's BLE parser service; support depends on its hardware and firmware. The standard BLE feature is marketed primarily for configuration: this API checks the actual service instead of assuming printing support from the model name.

On Android request permissions first:

final granted = await FlutterBluetoothSerial.instance.ensurePermissions();
if (!granted) throw StateError('Bluetooth permission denied');

Android 12+ requires Nearby devices (scan/connect) permission; Android 6–11 requires precise location permission and the system location service enabled for scanning. Enable Bluetooth in system settings. The plugin manifest declares the permissions; the host application's merged manifest must retain them.

On iOS add NSBluetoothAlwaysUsageDescription to the host app's Info.plist; also add NSBluetoothPeripheralUsageDescription if targeting iOS 12. The value must describe why the app needs Bluetooth. Authorization is requested by CoreBluetooth. Only the new Zebra BLE API is supported on iOS; generic SPP, bonded-device listing and adapter-control APIs remain Android-only.

// Keep the scan subscription to cancel it when the screen is disposed.
final scan = ZebraBle.instance.scan().listen((device) {
  print('${device.name}: ${device.address}');
});
// After selecting a discovered device:
await scan.cancel();
final printer = await ZebraBle.instance.connect(selectedDevice.address);
try {
  await printer.printZpl('^XA^FO30,30^A0N,30,30^FDPrueba Zebra^FS^XZ');
  // Or reuse the exact bytes that already work over TCP:
  // await printer.write(bytes);
} finally {
  await printer.close();
}

Android identifiers are MAC addresses; iOS uses peripheral UUIDs returned by the BLE scan, not the printer's MAC. Scanning includes all BLE devices because some Zebra firmware does not advertise the parser service. Connection fails with service_not_found / characteristic_not_found if the parser is unavailable.

One BLE connection is supported at a time. Writes are serialized and fragmented with response acknowledgements (conservative 20-byte payloads on Android; platform write-size limits on iOS). Default timeouts are 10 seconds for scanning, 20 seconds for connecting and 60 seconds per write; they are configurable. input receives printer indications when available. A completed write confirms BLE delivery, not a physical printed label. Large labels/images can be slow. On a timeout/disconnection, a job may be partially or fully received: the library does not retry or fall back to another transport automatically.

The example app includes Impresora Zebra (BLE) with scanning, service validation, editable ZPL and a test-label button. On Android it also offers manual MAC connection and bonded-device selection without requiring a scan advertisement. iOS opens this screen directly and also retrieves connected BLE peripherals with known services when available. Test first with a small label, then the same job that works over your network. Physical printing must be verified with the actual printer and mobile device.

Protocol references: Zebra BLE application note and official BLE example.

Features

The first goal of this project, update by @Angelica was making an interface for Serial Port Protocol (HC-05 Adapter). Now the plugin features:

  • Adapter status monitoring,

  • Turning adapter on and off,

  • Opening settings,

  • Discovering devices (and requesting discoverability),

  • Listing bonded devices and pairing new ones,

  • Connecting to multiple devices at the same time,

  • Sending and receiving data (multiple connections).

The plugin (for now) uses Serial Port profile for moving data over RFCOMM, so make sure there is running Service Discovery Protocol that points to SP/RFCOMM channel of the device. There could be max up to 7 Bluetooth connections.

The original serial API supports Android only; Zebra BLE also supports iOS.

Funding

Your contribution will help drive the development of quality tools for the Flutter and Dart developer community. Any amount will be appreciated. Thank you for your continued support!

Getting Started

Depending

# Add dependency to `pubspec.yaml` of your project.
dependencies:
  # ...
  flutter_bluetooth_serial_plus: ^0.5.7

Installing

flutter pub get

Importing

import 'package:flutter_bluetooth_serial_plus/flutter_bluetooth_serial_plus.dart';

Usage

You should look to the Dart code of the library (mostly documented functions) or to the examples code.

// Some simplest connection :F
try {
    BluetoothConnection connection = await BluetoothConnection.toAddress(address);
    print('Connected to the device');

    connection.input.listen((Uint8List data) {
        print('Data incoming: ${ascii.decode(data)}');
        connection.output.add(data); // Sending data

        if (ascii.decode(data).contains('!')) {
            connection.finish(); // Closing connection
            print('Disconnecting by local host');
        }
    }).onDone(() {
        print('Disconnected by remote request');
    });
}
catch (exception) {
    print('Cannot connect, exception occured');
}

Note: Work is underway to make the communication easier than operations on byte streams. See #41 for discussion about the topic.

Examples

Check out example application with connections with both Arduino HC-05 and Raspberry Pi (RFCOMM) Bluetooth interfaces.

Main screen and options Discovery and connecting Simple chat with server Background connection

To-do list

  • Add some utils to easier manage BluetoothConnection (see discussion #41),
  • Allow connection method/protocol/UUID specification,
  • Listening/server mode,
  • Recognizing and displaying BluetoothClass of device,
  • Maybe integration with flutter_blue one day ;

You might also want to check milestones.

Credits