Learn how to test Bluetooth functionality in your Flutter app with Patrol
Testing Bluetooth functionality is important for apps that rely on device connectivity features. Patrol provides native automation to enable, disable, and test Bluetooth state changes on both Android and iOS devices.
Test that your app properly responds to Bluetooth changes:
patrol_test/bluetooth_app_response_test.dart
import 'package:patrol/patrol.dart';import 'package:flutter_test/flutter_test.dart';void main() { patrolTest( 'app responds to bluetooth state changes', ($) async { await $.pumpWidgetAndSettle(const MyApp()); // Navigate to Bluetooth settings screen await $('Open Bluetooth screen').scrollTo().tap(); await $.pumpAndSettle(); // Verify initial Bluetooth state await $('Bluetooth Status').waitUntilVisible(); // Disable Bluetooth await $.platform.mobile.disableBluetooth(); await $.pump(); // Verify app shows Bluetooth is off await $('Bluetooth: OFF').waitUntilVisible(); expect($('Bluetooth: OFF').exists, true); // Enable Bluetooth await $.platform.mobile.enableBluetooth(); await $.pump(); // Verify app shows Bluetooth is on await $('Bluetooth: ON').waitUntilVisible(); expect($('Bluetooth: ON').exists, true); }, );}
final osVersion = await $.platform.mobile.getOsVersion();if (osVersion >= 31) { // Safe to use Bluetooth toggle methods await $.platform.mobile.disableBluetooth();}
// Opens Control Centerawait $.platform.mobile.openQuickSettings();
Control Center is not available on iOS Simulator. These tests must run on physical iOS devices.
Bluetooth Permissions:
Add to Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key><string>This app needs Bluetooth to connect to devices</string><key>NSBluetoothPeripheralUsageDescription</key><string>This app needs Bluetooth to connect to peripherals</string>
Bluetooth State:
iOS Bluetooth state changes may take a moment to propagate. Add appropriate delays:
await $.platform.mobile.disableBluetooth();// Wait for Bluetooth to actually turn offawait Future<void>.delayed(const Duration(seconds: 2));await $.pump();
Check Android version before toggling
Bluetooth control only works on Android 12+:
if (Platform.isAndroid) { final osVersion = await $.platform.mobile.getOsVersion(); if (osVersion >= 31) { await $.platform.mobile.disableBluetooth(); } else { // Skip Bluetooth toggle or use alternative approach }}
Restore Bluetooth state after test
Leave the device in a known state:
patrolTest('bluetooth test', ($) async { await $.pumpWidgetAndSettle(const MyApp()); try { // Test with Bluetooth off await $.platform.mobile.disableBluetooth(); // Run your tests... } finally { // Always re-enable Bluetooth await $.platform.mobile.enableBluetooth(); }});
Instead of programmatic control, you can manually toggle Bluetooth via Quick Settings:
import 'package:patrol/patrol.dart';patrolTest('manually toggle bluetooth', ($) async { await $.pumpWidgetAndSettle(const MyApp()); // Open Quick Settings/Control Center await $.platform.mobile.openQuickSettings(); // Wait for panel to open await Future<void>.delayed(const Duration(seconds: 2)); // Find and tap Bluetooth toggle await $.native.tap( Selector(textContains: 'Bluetooth'), ); // Wait and toggle again await Future<void>.delayed(const Duration(seconds: 3)); await $.native.tap( Selector(textContains: 'Bluetooth'), ); // Close Quick Settings await $.platform.mobile.pressBack();});
The programmatic enableBluetooth() and disableBluetooth() methods are more reliable than manually tapping UI elements in Quick Settings, as they directly control the Bluetooth adapter.
Check Bluetooth permissions are declared in AndroidManifest.xml
Request runtime permissions for Bluetooth (Android 12+)
Some devices may have manufacturer restrictions
iOS Simulator not supported
Control Center is not available on iOS Simulator
Bluetooth hardware is not emulated on Simulator
Always use physical iOS devices for Bluetooth testing
Bluetooth state not updating in app
Add $.pump() after Bluetooth state changes
Add delays for state to propagate (2-3 seconds)
Verify app is listening to Bluetooth state changes
Check Bluetooth state stream subscriptions
Test flaky or inconsistent
Increase delays between Bluetooth operations
Ensure previous Bluetooth operations completed
Reset Bluetooth state before each test
Avoid running multiple Bluetooth tests in parallel
For more reliable tests, consider mocking Bluetooth functionality for unit/widget tests, and only test actual Bluetooth integration in a small set of critical end-to-end tests on physical devices.