discoverServices method

Future<List<BluetoothService>> discoverServices({
  1. bool subscribeToServicesChanged = true,
  2. int timeout = 15,
})

Discover services, characteristics, and descriptors of the remote device

  • subscribeToServicesChanged Android Only: If true, after discovering services we will subscribe to the Services Changed Characteristic (0x2A05) used for the device.onServicesReset stream. Note: this behavior happens automatically on iOS and cannot be disabled

Implementation

Future<List<BluetoothService>> discoverServices(
    {bool subscribeToServicesChanged = true, int timeout = 15}) async {
  // check connected
  if (isDisconnected) {
    throw FlutterBluePlusException(ErrorPlatform.fbp, "discoverServices",
        FbpErrorCode.deviceIsDisconnected.index, "device is not connected");
  }

  // Only allow a single ble operation to be underway at a time
  _Mutex mtx = _MutexFactory.getMutexForKey("global");
  await mtx.take();
  List<BluetoothService> result = [];
  try {
    var responseStream = FlutterBluePlus._methodStream.stream
        .where((m) => m.method == "OnDiscoveredServices")
        .map((m) => m.arguments)
        .map((args) => BmDiscoverServicesResult.fromMap(args))
        .where((p) => p.remoteId == remoteId);

    // Start listening now, before invokeMethod, to ensure we don't miss the response
    Future<BmDiscoverServicesResult> futureResponse = responseStream.first;
    // invoke
    await FlutterBluePlus._invokeMethod('discoverServices', remoteId.str);
    // wait for response
    BmDiscoverServicesResult response = await futureResponse
        .fbpEnsureAdapterIsOn("discoverServices")
        .fbpEnsureDeviceIsConnected(this, "discoverServices")
        .fbpTimeout(timeout, "discoverServices");
    // failed?
    if (!response.success) {
      throw FlutterBluePlusException(_nativeError, "discoverServices",
          response.errorCode, response.errorString);
    }
    result =
        response.services.map((p) => BluetoothService.fromProto(p)).toList();
  } finally {
    mtx.give();
  }
  // in order to match iOS behavior on all platforms,
  // we always listen to the Services Changed characteristic if it exists.
  if (subscribeToServicesChanged) {
    if (Platform.isIOS == false && Platform.isMacOS == false) {
      BluetoothCharacteristic? c = _servicesChangedCharacteristic;
      if (c != null &&
          (c.properties.notify || c.properties.indicate) &&
          c.isNotifying == false) {
        await c.setNotifyValue(true);
      }
    }
  }
  return result;
}