This Flutter application transforms your smartphone into a Bluetooth Low Energy (BLE) peripheral, broadcasting real-time orientation sensor data (pitch, roll, and yaw) to any connected BLE central device.
This project serves as a comprehensive example of integrating native platform features (Android and iOS) into a Flutter application using Method Channels, providing a custom implementation for BLE communication without relying on third-party plugins for peripheral mode.
- Real-time Sensor Streaming: Captures live data from the phone's orientation sensor.
- BLE Peripheral Mode: Advertises itself as a BLE peripheral with a custom GATT service.
- Cross-Platform: A single Dart codebase for both Android and iOS, with platform-specific native code for BLE functionality.
- Clean Architecture: Utilizes the BLoC (Business Logic Component) pattern for state management, separating UI from business logic.
- Custom Native Integration: Demonstrates the use of
MethodChannelandEventChannelto communicate between Flutter and native code (Java/Kotlin on Android, Swift/Objective-C on iOS).
- Games: Use the phone's orientation as a controller input.
- see flutter_flame_ble_motion_control_demo
- this app will consume the broadcasted data and move a character in a game.
- see flutter_flame_ble_motion_control_demo
- IoT Applications: Broadcast sensor data to other BLE devices for monitoring or control.
The application is built with a clean, scalable architecture:
-
Flutter (UI & Business Logic):
- UI Layer (
/lib/ui): Contains the widgets that make up the user interface. - BLoC/Cubit Layer (
/lib/cubits): Manages the application's state.OrientationCubit: Manages the state of the phone's orientation sensor.BleCubit: Manages the state of the BLE peripheral (e.g., advertising, connected, subscribed).
- Repository Layer (
/lib/repositories): Abstracts data sources and communication with native platforms.OrientationRepository: Provides a stream of sensor data.BleRepository: Handles all communication with the native BLE implementation via method channels.
- UI Layer (
-
Native Platforms (BLE Implementation):
- Android (
/android): TheMainActivity.javafile contains the full implementation of a BLE GATT server, handling advertising, connections, and characteristic updates. - iOS (
/ios): TheAppDelegate.swiftfile uses theCoreBluetoothframework to manage theCBPeripheralManager, defining services and characteristics to broadcast the sensor data.
- Android (
- Sensor Data:
OrientationCubitlistens to a stream of data from the phone's orientation sensor. - State Update: The Cubit updates its state with the latest pitch, roll, and yaw values.
- UI Reaction: The
HomePagewidget rebuilds to display the new sensor data. - BLE Update: A
BlocListenertriggers theBleCubitto send the new data to the native side. - Method Channel:
BleRepositorysends the data over aMethodChannelto the native Android/iOS code. - Native Broadcast: The native code receives the data and updates the value of the BLE characteristic, notifying any subscribed central devices.
- Native Events: The native code sends events (like connection status, subscription changes, advertising status) back to Flutter using an
EventChannel. - Flutter State Sync: The
BleCubitlistens to these events and updates the app's state accordingly, ensuring the UI always reflects the true state of the BLE peripheral.
flutter_ble_sensor_broadcaster/
├── android/app/src/main/java/.../MainActivity.java # Native Android BLE implementation
├── ios/Runner/AppDelegate.swift # Native iOS BLE implementation
├── lib/
│ ├── constants/
│ │ └── ble_constants.dart # Centralized BLE constants
│ ├── cubit/
│ │ ├── ble_cubit.dart # State management for BLE
│ │ ├── ble_state.dart
│ │ ├── orientation_cubit.dart # State management for sensors
│ │ └── orientation_state.dart
│ ├── repositories/
│ │ ├── ble_repository.dart # Handles Method/Event Channel communication
│ │ └── orientation_repository.dart # Provides sensor data stream
│ ├── ui/
│ │ └── home_page.dart # Main application screen
│ └── main.dart # App entry point
└── pubspec.yaml
| Platform | Supported | Tested |
|---|---|---|
| Android | ✅ | ✅ |
| iOS | ✅ | ❌ |
-
Clone the repository:
git clone https://github.com/IoT-gamer/flutter_ble_sensor_broadcaster.git cd flutter_ble_sensor_broadcaster -
Get Flutter dependencies:
flutter pub get
-
Run the application: Connect a device or start an emulator/simulator and run:
flutter run
The app first requests necessary Bluetooth permissions for the specific platform (BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE on Android; Bluetooth on iOS).
Once permissions are granted, the BleCubit calls initialize on the BleRepository. This invokes the corresponding initialize method on the native side, setting up the CBPeripheralManager (iOS) or BluetoothGattServer (Android).
- Tapping the "Start Broadcasting" button calls
startAdvertising()in theBleCubit. - This command is passed through the
BleRepositoryvia a Method Channel to the native code. - The native code starts advertising a specific BLE Service UUID.
- The native code sends an
advertisingStatusevent back to Flutter via theEventChannel, and the UI updates to show "Stop Broadcasting".
- When a BLE central device connects and subscribes to the characteristic, the native code sends
connectionStateandsubscriptionStateevents to Flutter. - The
BleCubitupdates its state toisSubscribed = true. - Now, every time the
OrientationCubitemits a new sensor reading, theupdateCharacteristicmethod is called, sending the data to the native side to be broadcast to the subscriber.
- Tapping "Stop Broadcasting" calls
stopAdvertising(). - The command is sent to the native platform, which stops the BLE advertisement.
- An
advertisingStatusevent is sent back, and the UI button reverts to "Start Broadcasting".
This robust, event-driven architecture ensures that the Flutter UI and the native BLE stack are always in sync.
- Pairing and bonding are not implemented in this example.
- Sensor data is not encrypted; consider using secure characteristics for sensitive data.
This project is licensed under the MIT License - see the LICENSE file for details.
