Skip to content

Commit

Permalink
Merge pull request #436 from Polidea/release/2.2.2
Browse files Browse the repository at this point in the history
Release 2.2.2
  • Loading branch information
mikolak authored Feb 27, 2020
2 parents 489c9f4 + b6a9259 commit 76e6fcf
Show file tree
Hide file tree
Showing 31 changed files with 385 additions and 24 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.2.2

* Fix issue with invalid characteristic value base64 coding when performing characteristic operations on iOS
* Improve documentation

## 2.2.1

* Hide private APIs
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The library is organised around a few base entities, which are:
- **Peripheral**
- **Service**
- **Characteristic**
* **Descriptor**
- **Descriptor**

You have to create an instance _BleManager_ and initialise underlying native resources.
Using that instance you then obtain an instance of _Peripheral_,
Expand Down
2 changes: 1 addition & 1 deletion ios/Classes/FlutterBleLibPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ - (Reject)rejectForFlutterResult:(FlutterResult)result {
}

- (NSString *)base64encodedStringFromBytes:(FlutterStandardTypedData *)bytes {
return [bytes.data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return [bytes.data base64EncodedStringWithOptions:0];
}

@end
100 changes: 99 additions & 1 deletion lib/ble_manager.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
part of flutter_ble_lib;

typedef RestoreStateAction = Function(List<Peripheral> restoreStateIdentifier);
/// Callback used to inform about peripherals restored by the system.
///
/// iOS-specific.
typedef RestoreStateAction = Function(List<Peripheral> peripherals);

/// Level of details library is to output in logs.
enum LogLevel { none, verbose, debug, info, warning, error }

/// Entry point for library operations, handling allocation and deallocation
/// of underlying native resources and obtaining [Peripheral] instances.
///
/// The class is a singleton, so there's no need to keep the reference to
/// the object in one's code.
///
/// Initialising/deinitialising native clients:
/// ```dart
/// BleManager bleManager = BleManager();
/// await bleManager.createClient(); //ready to go!
/// //your BLE logic
/// bleManager.destroyClient(); //remember to release native resources when they're no longer needed
/// ```
///
/// Obtaining [Peripheral]:
/// ```dart
/// bleManager.startPeripheralScan().listen((scanResult) {
/// //Scan one peripheral and stop scanning
/// print("Scanned Peripheral ${scanResult.peripheral.name}, RSSI ${scanResult.rssi}");
/// bleManager.stopPeripheralScan(); // stops the scan
///});
///```
abstract class BleManager {
static BleManager _instance;

Expand All @@ -15,41 +41,107 @@ abstract class BleManager {
return _instance;
}

/// Cancels transaction's return, resulting in [BleError] with
/// [BleError.errorCode] set to [BleErrorCode.OperationCancelled] being returned
/// from transaction's Future.
///
/// The operation might be cancelled if it hadn't yet started or be run
/// normally, eg. writing to
/// characteristic, but you can dismiss awaiting for the result if,
/// for example, the result is no longer useful due to user's actions.
Future<void> cancelTransaction(String transactionId);

/// Allocates native resources.
///
/// [restoreStateIdentifier] and [restoreStateAction] are iOS-specific.
///
/// Must return before any other operation can be called.
///
/// ```dart
/// await BleManager().createClient();
/// ```
Future<void> createClient({
String restoreStateIdentifier,
RestoreStateAction restoreStateAction,
});

/// Frees native resources.
///
/// After calling this method you must call again [createClient()] before
/// any BLE operation.
Future<void> destroyClient();

/// Starts scanning for peripherals.
///
/// Arguments [scanMode] and [callbackType] are Android-only,
/// while [allowDuplicates] is iOS-only. Note that [allowDuplicates] set to
/// false will only result in slower refresh rate for unique peripheral's
/// advertisement data, not dismissal of it after receiving the initial one.
/// Refer to each platform's own documentation for more detailed information.
///
/// [uuids] is used to filter scan results to those whose advertised service
/// match either of the specified UUIDs.
///
/// ```dart
/// bleManager.startPeripheralScan().listen((scanResult) {
/// //Scan one peripheral and stop scanning
/// print("Scanned Peripheral ${scanResult.peripheral.name}, RSSI ${scanResult.rssi}");
/// bleManager.stopPeripheralScan();
/// });
/// ```
Stream<ScanResult> startPeripheralScan({
int scanMode = ScanMode.lowPower,
int callbackType = CallbackType.allMatches,
List<String> uuids = const [],
bool allowDuplicates = false,
});

/// Finishes the scan operation on the device.
Future<void> stopPeripheralScan();

/// Sets specified [LogLevel].
///
/// This sets log level for both Dart and native platform.
Future<void> setLogLevel(LogLevel logLevel);

/// Returns current [LogLevel].
Future<LogLevel> logLevel();

/// Enables Bluetooth on Android; NOOP on iOS.
///
/// Passing optional [transactionId] lets you discard the result of this
/// operation before it is finished.
Future<void> enableRadio({String transactionId});

/// Disables Bluetooth on Android; NOOP on iOS.
///
/// Passing optional [transactionId] lets you discard the result of this
/// operation before it is finished.
Future<void> disableRadio({String transactionId});

/// Returns current state of the Bluetooth adapter.
Future<BluetoothState> bluetoothState();

/// Returns a stream of changes to the state of the Bluetooth adapter.
///
/// By default starts the stream with the current state, but this can
/// overridden by passing `false` as [emitCurrentValue].
Stream<BluetoothState> observeBluetoothState({bool emitCurrentValue = true});

/// Returns a list of [Peripheral]: on iOS known to system, on Android
/// known to the library.
///
/// If [peripheralIdentifiers] is empty, this will return an empty list.
Future<List<Peripheral>> knownPeripherals(List<String> peripheralIdentifiers);

/// Returns a list of [Peripheral]: on iOS connected and known to system,
/// on Android connected and known to the library.
///
/// If [serviceUUIDs] is empty, this will return an empty list.
Future<List<Peripheral>> connectedPeripherals(List<String> serviceUUIDs);
}

/// State of the Bluetooth Adapter.
enum BluetoothState {
UNKNOWN,
UNSUPPORTED,
Expand All @@ -59,13 +151,19 @@ enum BluetoothState {
RESETTING,
}

/// Mode of scan for peripherals - Android only.
///
/// See [Android documentation](https://developer.android.com/reference/android/bluetooth/le/ScanSettings) for more information.
abstract class ScanMode {
static const int opportunistic = -1;
static const int lowPower = 0;
static const int balanced = 1;
static const int lowLatency = 2;
}

/// Type of scan for peripherals callback - Android only.
///
/// See [Android documentation](https://developer.android.com/reference/android/bluetooth/le/ScanSettings) for more information.
abstract class CallbackType {
static const int allMatches = 1;
static const int firstMatch = 2;
Expand Down
43 changes: 43 additions & 0 deletions lib/characteristic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,32 @@ abstract class _CharacteristicMetadata {
static const String value = "value";
}

/// Representation of a single GATT Characteristic nested inside a [Service].
///
/// It contains a single value and any number of [Descriptor]s describing that
/// value. The properties of a characteristic determine how you can use
/// a characteristic’s value, and how you access the descriptors.
class Characteristic extends InternalCharacteristic {
/// The [Service] containing this characteristic.
Service service;

ManagerForCharacteristic _manager;

/// The UUID of this characteristic.
String uuid;

/// True if this characteristic can be read.
bool isReadable;

/// True if this characteristic can be written with resposne.
bool isWritableWithResponse;

/// True if this characteristic can be written without resposne.
bool isWritableWithoutResponse;

/// True if this characteristic can be monitored via notifications.
bool isNotifiable;
/// True if this characteristic can be monitored via indications.
bool isIndicatable;

Characteristic.fromJson(Map<String, dynamic> jsonObject, Service service,
Expand All @@ -36,13 +54,21 @@ class Characteristic extends InternalCharacteristic {
isIndicatable = jsonObject[_CharacteristicMetadata.isIndicatable];
}

/// Reads the value of this characteristic.
///
/// The value can be read only if [isReadable] is `true`.
Future<Uint8List> read({String transactionId}) =>
_manager.readCharacteristicForIdentifier(
service.peripheral,
this,
transactionId ?? TransactionIdGenerator.getNextId(),
);

/// Writes to the value of this characteristic.
///
/// The value can be written only if [isWritableWithResponse] or
/// [isWritableWithoutResponse] is `true` and argument [withResponse] is
/// set accordingly.
Future<void> write(
Uint8List bytes,
bool withResponse, {
Expand All @@ -56,16 +82,26 @@ class Characteristic extends InternalCharacteristic {
transactionId ?? TransactionIdGenerator.getNextId(),
);

/// Returns a [Stream] of notifications/indications emitted by this
/// characteristic.
///
/// Library chooses notifications over indications, if both are supported.
///
/// Subscribing to the returned object enables the notifications/indications
/// on the peripheral. Cancelling the last subscription disables the
/// notifications/indications on this characteristic.
Stream<Uint8List> monitor({String transactionId}) =>
_manager.monitorCharacteristicForIdentifier(
service.peripheral,
this,
transactionId ?? TransactionIdGenerator.getNextId(),
);

/// Returns a list of [Descriptor]s of this characteristic.
Future<List<Descriptor>> descriptors() =>
_manager.descriptorsForCharacteristic(this);

/// Reads the value of a [Descriptor] identified by [descriptorUuid].
Future<DescriptorWithValue> readDescriptor(
String descriptorUuid, {
String transactionId,
Expand All @@ -76,6 +112,7 @@ class Characteristic extends InternalCharacteristic {
transactionId ?? TransactionIdGenerator.getNextId(),
);

/// Writes the [value] of a [Descriptor] identified by [descriptorUuid].
Future<Descriptor> writeDescriptor(
String descriptorUuid,
Uint8List value, {
Expand Down Expand Up @@ -113,6 +150,8 @@ class Characteristic extends InternalCharacteristic {
isNotifiable.hashCode ^
isIndicatable.hashCode;

/// Returns a string representation of this characteristic in a format that
/// contains all its properties and [Service].
@override
String toString() {
return 'Characteristic{service: $service,'
Expand All @@ -126,6 +165,10 @@ class Characteristic extends InternalCharacteristic {
}
}

/// [Characteristic] extended with [value] property.
///
/// This type is created to support chaining of operations on the characteristic
/// when it was first read from [Peripheral] or [Service].
class CharacteristicWithValue extends Characteristic with WithValue {
CharacteristicWithValue.fromJson(
Map<String, dynamic> jsonObject,
Expand Down
46 changes: 43 additions & 3 deletions lib/flutter_ble_lib.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,58 @@
/// Library for handling Bluetooth Low Energy functionality.
///
/// The library is organised around a few base entities, which are:
/// - [BleManager]
/// - [Peripheral]
/// - [Service]
/// - [Characteristic]
/// - [Descriptor]
///
/// You have to create an instance of [BleManager] and initialise underlying
/// native resources. Using that instance you then obtain an instance of
/// [Peripheral], which can be used to run operations on the corresponding
/// peripheral.
///
/// All operations passing the Dart-native bridge are asynchronous,
/// hence all operations in the plugin return either [Future] or [Stream].
///
/// The library handles scanning for peripherals, connecting to peripherals,
/// service discovery process on peripherals, manipulating characteristics
/// and descriptors.
///
/// Bonding is handled transparently by the platform's operating system.
///
/// You can also listen to changes of Bluetooth adapter's state.
///
/// ```dart
/// BleManager bleManager = BleManager();
/// await bleManager.createClient(); //ready to go!
/// //your BLE logic
/// bleManager.destroyClient(); //remember to release native resources when you're done!
/// ```
///
/// For more samples refer to specific classes.
library flutter_ble_lib;

import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter_ble_lib/internal/_internal.dart';
import 'package:flutter_ble_lib/internal/util/_transaction_id_generator.dart';
import 'package:flutter_ble_lib/src/_internal.dart';
import 'package:flutter_ble_lib/src/_managers_for_classes.dart';
import 'package:flutter_ble_lib/src/util/_transaction_id_generator.dart';

import 'internal/_managers_for_classes.dart';
import 'src/_managers_for_classes.dart';

part 'error/ble_error.dart';

part 'ble_manager.dart';

part 'characteristic.dart';

part 'descriptor.dart';

part 'peripheral.dart';

part 'scan_result.dart';

part 'service.dart';
Loading

0 comments on commit 76e6fcf

Please sign in to comment.