diff --git a/.travis.yml b/.travis.yml index 57fcd558..3ad2bb2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,11 +21,11 @@ _android_job_template: &android_job_template android: components: - tools - - build-tools-28.0.3 - android-28 + - android-29 + - build-tools-28.0.3 + - build-tools-29.0.5 - extra-android-m2repository - licenses: - - 'android-sdk-license-.+' env: global: - GRADLE_OPTS="-Xms128m" diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..7c763edf --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Example (debug)", + "request": "launch", + "type": "dart", + "flutterMode": "debug" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff99a0b..2235d846 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.2.0 + +* **NEW** operations on descriptors +* **BREAKING FOR BLEMULATOR** BLEmulator versions lower than 1.1.0 are not supported from this release +* Support for AndroidX +* Support for Swift 5 +* Lower iOS deployment target to 8.0 + ## 2.1.0 * **BREAKING** ScanResult.AdvertisementData.ManufacturerData has changed type from Int8List to Uint8List diff --git a/README.md b/README.md index d8d9d369..4b5b7b3d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ For more informations, see [REFERENCE](https://github.com/Polidea/FlutterBleLib/ ### Initialising ```dart BleManager bleManager = BleManager(); -bleManager.createClient(); //ready to go! +await bleManager.createClient(); //ready to go! // your peripheral logic bleManager.destroyClient(); //remember to release native resources when you're done! ``` @@ -81,6 +81,8 @@ bleManager.startPeripheralScan( The snippet above starts peripheral scan and stops it after receiving first result. It filters the scan results to those that advertise a service with specified UUID. +**NOTE:** `isConnectable` and `overflowServiceUuids` fields of `ScanResult` are iOS-only and remain `null` on Android. + ### Connecting to peripheral First you must obtain a _ScanResult_ from _BleManager.startPeripheralScan()_. ```dart diff --git a/REFERENCE.md b/REFERENCE.md index a53f7e54..cb73d6c1 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -34,11 +34,12 @@ Releases native resources. Should be called once there's no further need for BLE bool allowDuplicates, }); ``` -Returns a stream of objects containing advertisement data of the peripheral and the peripheral itself. `scanMode` and `callbackType` are Android-specific. [More information in Android documentation](https://developer.android.com/reference/android/bluetooth/le/ScanSettings) `allowDuplicates` is iOS-specific. [More information in iOS documentation](https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerscanoptionallowduplicateskey) `uuids` is used to filter peripherals to only return those containing services with specified UUIDs. +Returns a stream of objects containing advertisement data of the peripheral and the peripheral itself called `ScanResult`. The object has two iOS-only fields: `isConnectable` and `overflowServiceUuids`. + ```dart Future stopDeviceScan(); ``` diff --git a/android/build.gradle b/android/build.gradle index 1991387c..67811ed2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group 'com.polidea.flutter_ble_lib' -version '1.0' +version '2.2.0' buildscript { repositories { @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.3' } } @@ -35,6 +35,6 @@ android { } dependencies { - implementation 'com.android.support:support-annotations:28.0.0' - implementation 'com.github.Polidea:MultiPlatformBleAdapter:0.1.0' + implementation 'androidx.annotation:annotation:1.1.0' + implementation 'com.github.Polidea:MultiPlatformBleAdapter:0.1.4' } diff --git a/android/gradle.properties b/android/gradle.properties index d3fd86c6..755300e3 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=false -android.enableJetifier=false +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 019065d1..01a286e9 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/CharacteristicsResponse.java b/android/src/main/java/com/polidea/flutter_ble_lib/CharacteristicsResponse.java index 83fc917d..151d75ce 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/CharacteristicsResponse.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/CharacteristicsResponse.java @@ -3,16 +3,18 @@ import com.polidea.multiplatformbleadapter.Characteristic; import com.polidea.multiplatformbleadapter.Service; +import java.util.List; + public class CharacteristicsResponse { - private final Characteristic[] characteristics; + private final List characteristics; private final Service service; - public CharacteristicsResponse(Characteristic[] characteristics, Service service) { + public CharacteristicsResponse(List characteristics, Service service) { this.characteristics = characteristics; this.service = service; } - public Characteristic[] getCharacteristics() { + public List getCharacteristics() { return characteristics; } diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/FlutterBleLibPlugin.java b/android/src/main/java/com/polidea/flutter_ble_lib/FlutterBleLibPlugin.java index b0ad3305..e2007224 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/FlutterBleLibPlugin.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/FlutterBleLibPlugin.java @@ -1,7 +1,6 @@ package com.polidea.flutter_ble_lib; import android.content.Context; -import android.support.annotation.NonNull; import android.util.Log; import com.polidea.flutter_ble_lib.constant.ArgumentKey; @@ -10,6 +9,7 @@ import com.polidea.flutter_ble_lib.delegate.BluetoothStateDelegate; import com.polidea.flutter_ble_lib.delegate.CallDelegate; import com.polidea.flutter_ble_lib.delegate.CharacteristicsDelegate; +import com.polidea.flutter_ble_lib.delegate.DescriptorsDelegate; import com.polidea.flutter_ble_lib.delegate.DeviceConnectionDelegate; import com.polidea.flutter_ble_lib.delegate.DevicesDelegate; import com.polidea.flutter_ble_lib.delegate.LogLevelDelegate; @@ -31,6 +31,7 @@ import java.util.LinkedList; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -86,6 +87,7 @@ private void setupAdapter(Context context) { delegates.add(new MtuDelegate(bleAdapter)); delegates.add(new CharacteristicsDelegate(bleAdapter, characteristicsMonitorStreamHandler)); delegates.add(new DevicesDelegate(bleAdapter)); + delegates.add(new DescriptorsDelegate(bleAdapter)); } @Override diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/MultiCharacteristicsResponse.java b/android/src/main/java/com/polidea/flutter_ble_lib/MultiCharacteristicsResponse.java index b5f70ffe..a83c454f 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/MultiCharacteristicsResponse.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/MultiCharacteristicsResponse.java @@ -3,22 +3,35 @@ import com.polidea.multiplatformbleadapter.Characteristic; import com.polidea.multiplatformbleadapter.Service; +import java.util.List; import java.util.UUID; public class MultiCharacteristicsResponse { - private final Characteristic[] characteristics; - private Service service; + private final List characteristics; + private int serviceId; + private UUID serviceUuid; - public MultiCharacteristicsResponse(Characteristic[] characteristics, Service service) { + public MultiCharacteristicsResponse(List characteristics, Service service) { this.characteristics = characteristics; - this.service = service; + this.serviceId = service.getId(); + this.serviceUuid = service.getUuid(); } - public Characteristic[] getCharacteristics() { + public MultiCharacteristicsResponse(List characteristics, int serviceId, UUID serviceUuid) { + this.characteristics = characteristics; + this.serviceId = serviceId; + this.serviceUuid = serviceUuid; + } + + public List getCharacteristics() { return characteristics; } - public Service getService() { - return service; + public int getServiceId() { + return serviceId; + } + + public UUID getServiceUuid() { + return serviceUuid; } } diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/SafeMainThreadResolver.java b/android/src/main/java/com/polidea/flutter_ble_lib/SafeMainThreadResolver.java index d1d7e323..e9b09369 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/SafeMainThreadResolver.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/SafeMainThreadResolver.java @@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicBoolean; -public class SafeMainThreadResolver { +public class SafeMainThreadResolver implements OnSuccessCallback, OnErrorCallback { private OnErrorCallback onErrorCallback = null; private OnSuccessCallback onSuccessCallback = null; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/constant/ArgumentKey.java b/android/src/main/java/com/polidea/flutter_ble_lib/constant/ArgumentKey.java index a345bdbf..1dd8937b 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/constant/ArgumentKey.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/constant/ArgumentKey.java @@ -21,6 +21,8 @@ public interface ArgumentKey { String SERVICE_IDENTIFIER = "serviceId"; String CHARACTERISTIC_UUID = "characteristicUuid"; String CHARACTERISTIC_IDENTIFIER = "characteristicIdentifier"; + String DESCRIPTOR_UUID = "descriptorUuid"; + String DESCRIPTOR_IDENTIFIER = "descriptorIdentifier"; String VALUE = "value"; String WITH_RESPONSE = "withResponse"; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/constant/MethodName.java b/android/src/main/java/com/polidea/flutter_ble_lib/constant/MethodName.java index 124ffbc1..845585f4 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/constant/MethodName.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/constant/MethodName.java @@ -23,6 +23,9 @@ public interface MethodName { String GET_SERVICES = "services"; String GET_CHARACTERISTICS = "characteristics"; String GET_CHARACTERISTICS_FOR_SERVICE = "characteristicsForService"; + String GET_DESCRIPTORS_FOR_DEVICE = "descriptorsForDevice"; + String GET_DESCRIPTORS_FOR_CHARACTERISTIC = "descriptorsForCharacteristic"; + String GET_DESCRIPTORS_FOR_SERVICE = "descriptorsForService"; String LOG_LEVEL = "logLevel"; String SET_LOG_LEVEL = "setLogLevel"; @@ -45,4 +48,14 @@ public interface MethodName { String MONITOR_CHARACTERISTIC_FOR_IDENTIFIER = "monitorCharacteristicForIdentifier"; String MONITOR_CHARACTERISTIC_FOR_DEVICE = "monitorCharacteristicForDevice"; String MONITOR_CHARACTERISTIC_FOR_SERVICE = "monitorCharacteristicForService"; + + String READ_DESCRIPTOR_FOR_IDENTIFIER = "readDescriptorForIdentifier"; + String READ_DESCRIPTOR_FOR_CHARACTERISTIC = "readDescriptorForCharacteristic"; + String READ_DESCRIPTOR_FOR_SERVICE = "readDescriptorForService"; + String READ_DESCRIPTOR_FOR_DEVICE = "readDescriptorForDevice"; + + String WRITE_DESCRIPTOR_FOR_IDENTIFIER = "writeDescriptorForIdentifier"; + String WRITE_DESCRIPTOR_FOR_CHARACTERISTIC = "writeDescriptorForCharacteristic"; + String WRITE_DESCRIPTOR_FOR_SERVICE = "writeDescriptorForService"; + String WRITE_DESCRIPTOR_FOR_DEVICE = "writeDescriptorForDevice"; } diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/BleErrorJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/BleErrorJsonConverter.java index 5218f8e6..293f3591 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/BleErrorJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/BleErrorJsonConverter.java @@ -1,12 +1,13 @@ package com.polidea.flutter_ble_lib.converter; -import android.support.annotation.Nullable; import com.polidea.multiplatformbleadapter.errors.BleError; import org.json.JSONException; import org.json.JSONObject; +import androidx.annotation.Nullable; + public class BleErrorJsonConverter implements JsonConverter { public static final int MAX_ATT_ERROR = 0x80; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicJsonConverter.java index a4ea4f21..d42e3b40 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicJsonConverter.java @@ -7,6 +7,8 @@ import org.json.JSONException; import org.json.JSONObject; +import java.util.List; + public class CharacteristicJsonConverter implements JsonConverter { private interface Metadata { @@ -25,11 +27,11 @@ public String toJson(Characteristic characteristic) throws JSONException { return toJsonObject(characteristic).toString(); } - public String toJson(Characteristic[] characteristics) throws JSONException { + public String toJson(List characteristics) throws JSONException { return toJsonArray(characteristics).toString(); } - public JSONArray toJsonArray(Characteristic[] characteristics) throws JSONException { + public JSONArray toJsonArray(List characteristics) throws JSONException { JSONArray jsonArray = new JSONArray(); for (Characteristic characteristic : characteristics) { jsonArray.put(toJsonObject(characteristic)); diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicsResponseJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicsResponseJsonConverter.java deleted file mode 100644 index 16cddc12..00000000 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/CharacteristicsResponseJsonConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.polidea.flutter_ble_lib.converter; - -import com.polidea.flutter_ble_lib.CharacteristicsResponse; -import com.polidea.multiplatformbleadapter.Characteristic; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -public class CharacteristicsResponseJsonConverter implements JsonConverter { - - private interface Metadata { - String UUID = "serviceUuid"; - String ID = "serviceId"; - String CHARACTERISTICS = "characteristics"; - } - - @Override - public String toJson(CharacteristicsResponse characteristicsResponse) throws JSONException { - JSONObject jsonObject = new JSONObject(); - - jsonObject.put(Metadata.UUID, characteristicsResponse.getService().getUuid()); - jsonObject.put(Metadata.ID, characteristicsResponse.getService().getId()); - - JSONArray jsonArray = new CharacteristicJsonConverter().toJsonArray(characteristicsResponse.getCharacteristics()); - - jsonObject.put(Metadata.CHARACTERISTICS, jsonArray); - return jsonObject.toString(); - } -} diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/ConnectionStateChangeJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/ConnectionStateChangeJsonConverter.java index bd0a6fee..a1861b22 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/ConnectionStateChangeJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/ConnectionStateChangeJsonConverter.java @@ -1,12 +1,13 @@ package com.polidea.flutter_ble_lib.converter; -import android.support.annotation.Nullable; import com.polidea.flutter_ble_lib.ConnectionStateChange; import org.json.JSONException; import org.json.JSONObject; +import androidx.annotation.Nullable; + public class ConnectionStateChangeJsonConverter implements JsonConverter { private interface Metadata { diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/DescriptorJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/DescriptorJsonConverter.java new file mode 100644 index 00000000..8eb5a611 --- /dev/null +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/DescriptorJsonConverter.java @@ -0,0 +1,47 @@ +package com.polidea.flutter_ble_lib.converter; + +import com.polidea.multiplatformbleadapter.Descriptor; +import com.polidea.multiplatformbleadapter.utils.Base64Converter; + +import org.json.JSONException; +import org.json.JSONObject; + +public class DescriptorJsonConverter implements JsonConverter { + + + private interface Metadata { + String SERVICE_UUID = "serviceUuid"; + String SERVICE_ID = "serviceId"; + String CHARACTERISTIC_UUID = "characteristicUuid"; + String CHARACTERISTIC_ID = "id"; + String DESCRIPTOR_UUID = "descriptorUuid"; + String DESCRIPTOR_ID = "descriptorId"; + String DESCRIPTOR_VALUE = "value"; + } + + @Override + public String toJson(Descriptor descriptor) throws JSONException { + JSONObject jsonObject = toJsonObject(descriptor); + + jsonObject.put(Metadata.SERVICE_ID, descriptor.getServiceId()); + jsonObject.put(Metadata.SERVICE_UUID, descriptor.getServiceUuid()); + jsonObject.put(Metadata.CHARACTERISTIC_ID, descriptor.getCharacteristicId()); + jsonObject.put(Metadata.CHARACTERISTIC_UUID, descriptor.getCharacteristicUuid()); + + return jsonObject.toString(); + } + + public JSONObject toJsonObject(Descriptor descriptor) throws JSONException { + JSONObject jsonObject = new JSONObject(); + + + jsonObject.put(Metadata.DESCRIPTOR_ID, descriptor.getId()); + jsonObject.put(Metadata.DESCRIPTOR_UUID, descriptor.getUuid()); + jsonObject.put(Metadata.DESCRIPTOR_VALUE, + descriptor.getValue() != null ? + Base64Converter.encode(descriptor.getValue()) + : JSONObject.NULL); + + return jsonObject; + } +} diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/DevicesResultJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/DevicesResultJsonConverter.java index 6f533c11..47fd7ad3 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/DevicesResultJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/DevicesResultJsonConverter.java @@ -1,6 +1,5 @@ package com.polidea.flutter_ble_lib.converter; -import android.support.annotation.Nullable; import android.util.Log; import com.polidea.multiplatformbleadapter.Device; @@ -9,6 +8,8 @@ import org.json.JSONException; import org.json.JSONObject; +import androidx.annotation.Nullable; + public class DevicesResultJsonConverter implements JsonConverter { public static String TAG = DevicesResultJsonConverter.class.getName(); diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/JsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/JsonConverter.java index c1037422..0720af9d 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/JsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/JsonConverter.java @@ -1,9 +1,9 @@ package com.polidea.flutter_ble_lib.converter; -import android.support.annotation.Nullable; - import org.json.JSONException; +import androidx.annotation.Nullable; + public interface JsonConverter { @Nullable diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiCharacteristicsResponseJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiCharacteristicsResponseJsonConverter.java index faa81a36..29341c12 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiCharacteristicsResponseJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiCharacteristicsResponseJsonConverter.java @@ -18,8 +18,8 @@ private interface Metadata { public String toJson(MultiCharacteristicsResponse characteristicsResponse) throws JSONException { JSONObject jsonObject = new JSONObject(); - jsonObject.put(Metadata.UUID, characteristicsResponse.getService().getUuid()); - jsonObject.put(Metadata.ID, characteristicsResponse.getService().getId()); + jsonObject.put(Metadata.UUID, characteristicsResponse.getServiceUuid()); + jsonObject.put(Metadata.ID, characteristicsResponse.getServiceId()); JSONArray jsonArray = new CharacteristicJsonConverter().toJsonArray(characteristicsResponse.getCharacteristics()); diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiDescriptorsResponseJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiDescriptorsResponseJsonConverter.java new file mode 100644 index 00000000..c1d2ba52 --- /dev/null +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/MultiDescriptorsResponseJsonConverter.java @@ -0,0 +1,42 @@ +package com.polidea.flutter_ble_lib.converter; + +import com.polidea.multiplatformbleadapter.Descriptor; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; + +public class MultiDescriptorsResponseJsonConverter implements JsonConverter> { + + private DescriptorJsonConverter descriptorJsonConverter = new DescriptorJsonConverter(); + + private interface Metadata { + String SERVICE_UUID = "serviceUuid"; + String SERVICE_ID = "serviceId"; + String CHARACTERISTIC_UUID = "characteristicUuid"; + String CHARACTERISTIC_ID = "id"; + String DESCRIPTORS = "descriptors"; + } + + @Override + public String toJson(List descriptors) throws JSONException { + JSONObject root = new JSONObject(); + JSONArray array = new JSONArray(); + if (descriptors.size() > 0) { + root.put(Metadata.SERVICE_ID, descriptors.get(0).getServiceId()); + root.put(Metadata.SERVICE_UUID, descriptors.get(0).getServiceUuid()); + root.put(Metadata.CHARACTERISTIC_ID, descriptors.get(0).getCharacteristicId()); + root.put(Metadata.CHARACTERISTIC_UUID, descriptors.get(0).getCharacteristicUuid()); + + for (Descriptor descriptor : descriptors) { + array.put(descriptorJsonConverter.toJsonObject(descriptor)); + } + + } + root.put(Metadata.DESCRIPTORS, array); + + return root.toString(); + } +} diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/ScanResultJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/ScanResultJsonConverter.java index c6087375..eb921849 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/ScanResultJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/ScanResultJsonConverter.java @@ -1,8 +1,5 @@ package com.polidea.flutter_ble_lib.converter; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - import com.polidea.multiplatformbleadapter.AdvertisementData; import com.polidea.multiplatformbleadapter.ScanResult; import com.polidea.multiplatformbleadapter.utils.Base64Converter; @@ -18,6 +15,9 @@ import java.util.Map; import java.util.UUID; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + public class ScanResultJsonConverter implements JsonConverter { private interface Metadata { diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/ServiceJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/ServiceJsonConverter.java index a107bf50..d2ffac86 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/ServiceJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/ServiceJsonConverter.java @@ -6,6 +6,8 @@ import org.json.JSONException; import org.json.JSONObject; +import java.util.List; + public class ServiceJsonConverter implements JsonConverter { private interface Metadata { @@ -18,7 +20,7 @@ public String toJson(Service service) throws JSONException { return toJsonObject(service).toString(); } - public String toJson(Service[] services) throws JSONException { + public String toJson(List services) throws JSONException { JSONArray array = new JSONArray(); for (Service service : services) { array.put(toJsonObject(service)); diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/converter/SingleCharacteristicResponseJsonConverter.java b/android/src/main/java/com/polidea/flutter_ble_lib/converter/SingleCharacteristicResponseJsonConverter.java index 528a6106..dacd8c9d 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/converter/SingleCharacteristicResponseJsonConverter.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/converter/SingleCharacteristicResponseJsonConverter.java @@ -1,12 +1,12 @@ package com.polidea.flutter_ble_lib.converter; -import android.support.annotation.Nullable; - import com.polidea.flutter_ble_lib.SingleCharacteristicResponse; import org.json.JSONException; import org.json.JSONObject; +import androidx.annotation.Nullable; + public class SingleCharacteristicResponseJsonConverter implements JsonConverter { private interface Metadata { diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/BluetoothStateDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/BluetoothStateDelegate.java index ab090911..63724750 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/BluetoothStateDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/BluetoothStateDelegate.java @@ -1,7 +1,5 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; - import com.polidea.flutter_ble_lib.constant.ArgumentKey; import com.polidea.flutter_ble_lib.constant.MethodName; import com.polidea.flutter_ble_lib.converter.BleErrorJsonConverter; @@ -13,6 +11,7 @@ import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/CharacteristicsDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/CharacteristicsDelegate.java index 7e0982d4..2e1e5aba 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/CharacteristicsDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/CharacteristicsDelegate.java @@ -2,7 +2,6 @@ import android.os.Handler; import android.os.Looper; -import android.support.annotation.NonNull; import com.polidea.flutter_ble_lib.BleErrorFactory; import com.polidea.flutter_ble_lib.SafeMainThreadResolver; @@ -25,6 +24,7 @@ import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DescriptorsDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DescriptorsDelegate.java new file mode 100644 index 00000000..38e21d47 --- /dev/null +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DescriptorsDelegate.java @@ -0,0 +1,297 @@ +package com.polidea.flutter_ble_lib.delegate; + + +import com.polidea.flutter_ble_lib.SafeMainThreadResolver; +import com.polidea.flutter_ble_lib.constant.ArgumentKey; +import com.polidea.flutter_ble_lib.constant.MethodName; +import com.polidea.flutter_ble_lib.converter.BleErrorJsonConverter; +import com.polidea.flutter_ble_lib.converter.DescriptorJsonConverter; +import com.polidea.multiplatformbleadapter.BleAdapter; +import com.polidea.multiplatformbleadapter.Descriptor; +import com.polidea.multiplatformbleadapter.OnErrorCallback; +import com.polidea.multiplatformbleadapter.OnSuccessCallback; +import com.polidea.multiplatformbleadapter.errors.BleError; +import com.polidea.multiplatformbleadapter.utils.Base64Converter; + +import org.json.JSONException; + +import java.util.Arrays; +import java.util.List; + +import androidx.annotation.NonNull; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; + +public class DescriptorsDelegate extends CallDelegate { + + private static List supportedMethods = Arrays.asList( + MethodName.READ_DESCRIPTOR_FOR_IDENTIFIER, + MethodName.READ_DESCRIPTOR_FOR_CHARACTERISTIC, + MethodName.READ_DESCRIPTOR_FOR_SERVICE, + MethodName.READ_DESCRIPTOR_FOR_DEVICE, + + MethodName.WRITE_DESCRIPTOR_FOR_IDENTIFIER, + MethodName.WRITE_DESCRIPTOR_FOR_CHARACTERISTIC, + MethodName.WRITE_DESCRIPTOR_FOR_SERVICE, + MethodName.WRITE_DESCRIPTOR_FOR_DEVICE + ); + + private BleAdapter bleAdapter; + private BleErrorJsonConverter errorConverter = new BleErrorJsonConverter(); + private DescriptorJsonConverter descriptorJsonConverter = new DescriptorJsonConverter(); + + public DescriptorsDelegate(BleAdapter bleAdapter) { + super(supportedMethods); + this.bleAdapter = bleAdapter; + } + + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + switch (call.method) { + case MethodName.READ_DESCRIPTOR_FOR_IDENTIFIER: + readDescriptorForIdentifier( + call.argument(ArgumentKey.DESCRIPTOR_IDENTIFIER), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.READ_DESCRIPTOR_FOR_CHARACTERISTIC: + readDescriptorForCharacteristic( + call.argument(ArgumentKey.CHARACTERISTIC_IDENTIFIER), + call.argument(ArgumentKey.DESCRIPTOR_UUID), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.READ_DESCRIPTOR_FOR_SERVICE: + readDescriptorForService( + call.argument(ArgumentKey.SERVICE_IDENTIFIER), + call.argument(ArgumentKey.CHARACTERISTIC_UUID), + call.argument(ArgumentKey.DESCRIPTOR_UUID), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.READ_DESCRIPTOR_FOR_DEVICE: + readDescriptorForDevice( + call.argument(ArgumentKey.DEVICE_IDENTIFIER), + call.argument(ArgumentKey.SERVICE_UUID), + call.argument(ArgumentKey.CHARACTERISTIC_UUID), + call.argument(ArgumentKey.DESCRIPTOR_UUID), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.WRITE_DESCRIPTOR_FOR_IDENTIFIER: + writeDescriptorForIdentifier( + call.argument(ArgumentKey.DESCRIPTOR_IDENTIFIER), + call.argument(ArgumentKey.VALUE), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.WRITE_DESCRIPTOR_FOR_CHARACTERISTIC: + writeDescriptorForCharacteristic( + call.argument(ArgumentKey.CHARACTERISTIC_IDENTIFIER), + call.argument(ArgumentKey.DESCRIPTOR_UUID), + call.argument(ArgumentKey.VALUE), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.WRITE_DESCRIPTOR_FOR_SERVICE: + writeDescriptorForService( + call.argument(ArgumentKey.SERVICE_IDENTIFIER), + call.argument(ArgumentKey.CHARACTERISTIC_UUID), + call.argument(ArgumentKey.DESCRIPTOR_UUID), + call.argument(ArgumentKey.VALUE), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + case MethodName.WRITE_DESCRIPTOR_FOR_DEVICE: + writeDescriptorForDevice( + call.argument(ArgumentKey.DEVICE_IDENTIFIER), + call.argument(ArgumentKey.SERVICE_UUID), + call.argument(ArgumentKey.CHARACTERISTIC_UUID), + call.argument(ArgumentKey.DESCRIPTOR_UUID), + call.argument(ArgumentKey.VALUE), + call.argument(ArgumentKey.TRANSACTION_ID), + result + ); + return; + default: + throw new IllegalArgumentException(call.method + " cannot be handled by this delegate"); + } + } + + private SafeMainThreadResolver createMainThreadResolverForResult(final MethodChannel.Result result, final String transactionId) { + return new SafeMainThreadResolver<>( + new OnSuccessCallback() { + @Override + public void onSuccess(Descriptor descriptor) { + try { + result.success(descriptorJsonConverter.toJson(descriptor)); + } catch (JSONException e) { + e.printStackTrace(); + result.error(null, e.getMessage(), null); + } + } + }, + new OnErrorCallback() { + @Override + public void onError(BleError error) { + result.error( + String.valueOf(error.errorCode.code), + error.reason, + errorConverter.toJson(error, transactionId) + ); + } + } + ); + } + + private void readDescriptorForIdentifier( + final int descriptorId, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.readDescriptor( + descriptorId, + transactionId, + safeMainThreadResolver, //onSuccess + safeMainThreadResolver //onError + ); + } + + private void readDescriptorForCharacteristic( + final int characteristicId, + final String descriptorUuid, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.readDescriptorForCharacteristic( + characteristicId, + descriptorUuid, + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } + + private void readDescriptorForService( + final int serviceId, + final String characteristicUuid, + final String descriptorUuid, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.readDescriptorForService( + serviceId, + characteristicUuid, + descriptorUuid, + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } + + private void readDescriptorForDevice( + final String deviceId, + final String serviceUuid, + final String characteristicUuid, + final String descriptorUuid, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.readDescriptorForDevice( + deviceId, + serviceUuid, + characteristicUuid, + descriptorUuid, + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } + + private void writeDescriptorForIdentifier( + final int descriptorId, + final byte[] value, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.writeDescriptor( + descriptorId, + Base64Converter.encode(value), + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } + + private void writeDescriptorForCharacteristic( + final int characteristicId, + final String descriptorUuid, + final byte[] value, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.writeDescriptorForCharacteristic( + characteristicId, + descriptorUuid, + Base64Converter.encode(value), + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } + + private void writeDescriptorForService( + final int serviceId, + final String characteristicUuid, + final String descriptorUuid, + final byte[] value, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.writeDescriptorForService( + serviceId, + characteristicUuid, + descriptorUuid, + Base64Converter.encode(value), + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } + + private void writeDescriptorForDevice( + final String deviceId, + final String serviceUuid, + final String characteristicUuid, + final String descriptorUuid, + final byte[] value, + final String transactionId, + final MethodChannel.Result result) { + final SafeMainThreadResolver safeMainThreadResolver = createMainThreadResolverForResult(result, transactionId); + + bleAdapter.writeDescriptorForDevice( + deviceId, + serviceUuid, + characteristicUuid, + descriptorUuid, + Base64Converter.encode(value), + transactionId, + safeMainThreadResolver, //success + safeMainThreadResolver //error + ); + } +} diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DeviceConnectionDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DeviceConnectionDelegate.java index 3582e0ff..8bef58d1 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DeviceConnectionDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DeviceConnectionDelegate.java @@ -1,7 +1,5 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; - import com.polidea.flutter_ble_lib.ConnectionStateChange; import com.polidea.flutter_ble_lib.SafeMainThreadResolver; import com.polidea.flutter_ble_lib.constant.ArgumentKey; @@ -21,6 +19,7 @@ import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DevicesDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DevicesDelegate.java index b8ef24ee..8073d50f 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DevicesDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DevicesDelegate.java @@ -1,6 +1,5 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; import android.util.Log; import com.polidea.flutter_ble_lib.SafeMainThreadResolver; @@ -19,6 +18,7 @@ import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DiscoveryDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DiscoveryDelegate.java index ea74af4e..88a23555 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DiscoveryDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/DiscoveryDelegate.java @@ -1,7 +1,5 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; - import com.polidea.flutter_ble_lib.MultiCharacteristicsResponse; import com.polidea.flutter_ble_lib.SafeMainThreadResolver; import com.polidea.flutter_ble_lib.constant.ArgumentKey; @@ -9,9 +7,11 @@ import com.polidea.flutter_ble_lib.converter.BleErrorJsonConverter; import com.polidea.flutter_ble_lib.converter.CharacteristicJsonConverter; import com.polidea.flutter_ble_lib.converter.MultiCharacteristicsResponseJsonConverter; +import com.polidea.flutter_ble_lib.converter.MultiDescriptorsResponseJsonConverter; import com.polidea.flutter_ble_lib.converter.ServiceJsonConverter; import com.polidea.multiplatformbleadapter.BleAdapter; import com.polidea.multiplatformbleadapter.Characteristic; +import com.polidea.multiplatformbleadapter.Descriptor; import com.polidea.multiplatformbleadapter.Device; import com.polidea.multiplatformbleadapter.OnErrorCallback; import com.polidea.multiplatformbleadapter.OnSuccessCallback; @@ -24,6 +24,7 @@ import java.util.List; import java.util.UUID; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -33,13 +34,18 @@ public class DiscoveryDelegate extends CallDelegate { private CharacteristicJsonConverter characteristicJsonConverter = new CharacteristicJsonConverter(); private ServiceJsonConverter serviceJsonConverter = new ServiceJsonConverter(); private MultiCharacteristicsResponseJsonConverter multiCharacteristicsResponseJsonConverter = new MultiCharacteristicsResponseJsonConverter(); + private MultiDescriptorsResponseJsonConverter multiDescriptorsResponseJsonConverter = new MultiDescriptorsResponseJsonConverter(); private static List supportedMethods = Arrays.asList( MethodName.DISCOVER_ALL_SERVICES_AND_CHARACTERISTICS, MethodName.GET_CHARACTERISTICS, MethodName.GET_SERVICES, - MethodName.GET_CHARACTERISTICS_FOR_SERVICE - ); + MethodName.GET_CHARACTERISTICS_FOR_SERVICE, + + MethodName.GET_DESCRIPTORS_FOR_CHARACTERISTIC, + MethodName.GET_DESCRIPTORS_FOR_SERVICE, + MethodName.GET_DESCRIPTORS_FOR_DEVICE + ); public DiscoveryDelegate(BleAdapter adapter) { super(supportedMethods); @@ -71,6 +77,27 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result case MethodName.GET_CHARACTERISTICS_FOR_SERVICE: getCharacteristicsForService(call.argument(ArgumentKey.SERVICE_IDENTIFIER), result); return; + case MethodName.GET_DESCRIPTORS_FOR_CHARACTERISTIC: + getDescriptorsForCharacteristic( + call.argument(ArgumentKey.CHARACTERISTIC_IDENTIFIER), + result + ); + return; + case MethodName.GET_DESCRIPTORS_FOR_SERVICE: + getDescriptorsForService( + call.argument(ArgumentKey.SERVICE_IDENTIFIER), + call.argument(ArgumentKey.CHARACTERISTIC_UUID), + result + ); + return; + case MethodName.GET_DESCRIPTORS_FOR_DEVICE: + getDescriptorsForDevice( + call.argument(ArgumentKey.DEVICE_IDENTIFIER), + call.argument(ArgumentKey.SERVICE_UUID), + call.argument(ArgumentKey.CHARACTERISTIC_UUID), + result + ); + return; default: throw new IllegalArgumentException(call.method + " cannot be handled by this delegate"); } @@ -87,7 +114,7 @@ public void onSuccess(Object data) { new OnErrorCallback() { @Override public void onError(BleError error) { - result.error(String.valueOf(error.errorCode.code), error.reason, bleErrorJsonConverter.toJson(error)); + failWithError(result, error); } }); @@ -107,27 +134,29 @@ public void onError(BleError error) { private void getCharacteristics(String deviceId, final String serviceUuid, final MethodChannel.Result result) { try { - Service[] services = adapter.getServicesForDevice(deviceId); - Service foundService = null; - for (final Service service : services) { - if (service.getUuid().equals(UUID.fromString(serviceUuid))) { - foundService = service; - break; - } - } + List characteristics = adapter.getCharacteristicsForDevice(deviceId, serviceUuid); - if (foundService == null) { - result.error("UnknownServiceException", "Service not found", "Unknown service UUID " + serviceUuid); - return; + MultiCharacteristicsResponse characteristicsResponse; + + if (characteristics.size() == 0) { + characteristicsResponse = new MultiCharacteristicsResponse( + characteristics, + -1, + null + ); + } else { + characteristicsResponse = new MultiCharacteristicsResponse( + characteristics, + characteristics.get(0).getServiceID(), + characteristics.get(0).getServiceUUID() + ); } - Characteristic[] characteristics = adapter.getCharacteristicsForService(foundService.getId()); - MultiCharacteristicsResponse characteristicsResponse = new MultiCharacteristicsResponse(characteristics, foundService); String json = multiCharacteristicsResponseJsonConverter.toJson(characteristicsResponse); result.success(json); } catch (BleError error) { error.printStackTrace(); - result.error(String.valueOf(error.errorCode.code), error.reason, bleErrorJsonConverter.toJson(error)); + failWithError(result, error); } catch (JSONException e) { e.printStackTrace(); result.error(null, e.getMessage(), null); @@ -136,11 +165,11 @@ private void getCharacteristics(String deviceId, final String serviceUuid, final private void getServices(String deviceId, final MethodChannel.Result result) { try { - Service[] services = adapter.getServicesForDevice(deviceId); + List services = adapter.getServicesForDevice(deviceId); result.success(serviceJsonConverter.toJson(services)); } catch (BleError error) { error.printStackTrace(); - result.error(String.valueOf(error.errorCode.code), error.reason, bleErrorJsonConverter.toJson(error)); + failWithError(result, error); } catch (JSONException e) { e.printStackTrace(); result.error(null, e.getMessage(), null); @@ -149,14 +178,62 @@ private void getServices(String deviceId, final MethodChannel.Result result) { private void getCharacteristicsForService(Integer serviceId, final MethodChannel.Result result) { try { - Characteristic[] characteristics = adapter.getCharacteristicsForService(serviceId); + List characteristics = adapter.getCharacteristicsForService(serviceId); result.success(characteristicJsonConverter.toJson(characteristics)); } catch (BleError error) { error.printStackTrace(); - result.error(String.valueOf(error.errorCode.code), error.reason, bleErrorJsonConverter.toJson(error)); + failWithError(result, error); + } catch (JSONException e) { + e.printStackTrace(); + result.error(null, e.getMessage(), null); + } + } + + private void getDescriptorsForCharacteristic( + final int characteristicId, + final MethodChannel.Result result) { + try { + List descriptors = adapter.descriptorsForCharacteristic(characteristicId); + result.success(multiDescriptorsResponseJsonConverter.toJson(descriptors)); + } catch (BleError error) { + failWithError(result, error); + } catch (JSONException e) { + e.printStackTrace(); + result.error(null, e.getMessage(), null); + } + } + + private void getDescriptorsForService( + final int serviceId, + final String characteristicUuid, + final MethodChannel.Result result) { + try { + List descriptors = adapter.descriptorsForService(serviceId, characteristicUuid); + result.success(multiDescriptorsResponseJsonConverter.toJson(descriptors)); + } catch (BleError error) { + failWithError(result, error); } catch (JSONException e) { e.printStackTrace(); result.error(null, e.getMessage(), null); } } + + private void getDescriptorsForDevice(final String deviceId, + final String serviceUuid, + final String characteristicUuid, + final MethodChannel.Result result) { + try { + List descriptors = adapter.descriptorsForDevice(deviceId, serviceUuid, characteristicUuid); + result.success(multiDescriptorsResponseJsonConverter.toJson(descriptors)); + } catch (BleError error) { + failWithError(result, error); + } catch (JSONException e) { + e.printStackTrace(); + result.error(null, e.getMessage(), null); + } + } + + private void failWithError(MethodChannel.Result result, BleError error) { + result.error(String.valueOf(error.errorCode.code), error.reason, bleErrorJsonConverter.toJson(error)); + } } \ No newline at end of file diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/LogLevelDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/LogLevelDelegate.java index 87183121..fb2de6a2 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/LogLevelDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/LogLevelDelegate.java @@ -1,23 +1,16 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; import android.util.Log; -import com.polidea.flutter_ble_lib.SafeMainThreadResolver; import com.polidea.flutter_ble_lib.constant.ArgumentKey; import com.polidea.flutter_ble_lib.constant.MethodName; -import com.polidea.flutter_ble_lib.converter.BleErrorJsonConverter; -import com.polidea.flutter_ble_lib.event.ConnectionStateStreamHandler; import com.polidea.multiplatformbleadapter.BleAdapter; -import com.polidea.multiplatformbleadapter.OnErrorCallback; -import com.polidea.multiplatformbleadapter.OnSuccessCallback; -import com.polidea.multiplatformbleadapter.errors.BleError; import com.polidea.multiplatformbleadapter.errors.BleErrorCode; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/MtuDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/MtuDelegate.java index 3eabf688..86bfe490 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/MtuDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/MtuDelegate.java @@ -1,6 +1,5 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; import android.util.Log; import com.polidea.flutter_ble_lib.SafeMainThreadResolver; @@ -16,6 +15,7 @@ import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/RssiDelegate.java b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/RssiDelegate.java index 62f3d51a..362f17f7 100644 --- a/android/src/main/java/com/polidea/flutter_ble_lib/delegate/RssiDelegate.java +++ b/android/src/main/java/com/polidea/flutter_ble_lib/delegate/RssiDelegate.java @@ -1,6 +1,5 @@ package com.polidea.flutter_ble_lib.delegate; -import android.support.annotation.NonNull; import android.util.Log; import com.polidea.flutter_ble_lib.SafeMainThreadResolver; @@ -12,11 +11,11 @@ import com.polidea.multiplatformbleadapter.OnErrorCallback; import com.polidea.multiplatformbleadapter.OnSuccessCallback; import com.polidea.multiplatformbleadapter.errors.BleError; -import com.polidea.multiplatformbleadapter.errors.BleErrorCode; import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index d6e57eb1..815cfd65 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -65,6 +65,6 @@ flutter { dependencies { testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/example/android/build.gradle b/example/android/build.gradle index 96400621..e0d7ae2c 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.0' } } @@ -13,7 +13,6 @@ allprojects { repositories { google() jcenter() - maven { url "https://jitpack.io" } } } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index d3fd86c6..a6738207 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536M - -android.useAndroidX=false -android.enableJetifier=false +android.useAndroidX=true +android.enableJetifier=true +android.enableR8=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 2819f022..296b146b 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 7a6d8bbc..f2df8e8e 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,16 +1,19 @@ PODS: - Flutter (1.0.0) - - flutter_ble_lib (0.0.1): + - flutter_ble_lib (2.1.0): + - Flutter + - MultiplatformBleAdapter (= 0.1.4) + - MultiplatformBleAdapter (0.1.4) + - "permission_handler (4.2.0+hotfix.3)": - Flutter - - MultiplatformBleAdapter (= 0.0.4) - - MultiplatformBleAdapter (0.0.4) DEPENDENCIES: - Flutter (from `.symlinks/flutter/ios`) - flutter_ble_lib (from `.symlinks/plugins/flutter_ble_lib/ios`) + - permission_handler (from `.symlinks/plugins/permission_handler/ios`) SPEC REPOS: - https://github.com/CocoaPods/Specs.git: + trunk: - MultiplatformBleAdapter EXTERNAL SOURCES: @@ -18,11 +21,14 @@ EXTERNAL SOURCES: :path: ".symlinks/flutter/ios" flutter_ble_lib: :path: ".symlinks/plugins/flutter_ble_lib/ios" + permission_handler: + :path: ".symlinks/plugins/permission_handler/ios" SPEC CHECKSUMS: Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_ble_lib: 9b0fcef11a0cb8432317e445c4cd413f9cab3b08 - MultiplatformBleAdapter: 1beec49bbd1585505a73d4bbf649e05a55dbd85e + flutter_ble_lib: b2cf6d76a88368075db66966d782630318c6e67d + MultiplatformBleAdapter: 1ef6e0c8d11f753c56cbad1654b36c8e24142648 + permission_handler: 40520ab8ad1bb78a282b832464e995ec87f77ec6 PODFILE CHECKSUM: 7fb83752f59ead6285236625b82473f90b1cb932 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index fa437b6c..61909646 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -376,7 +376,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -462,7 +462,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -512,7 +512,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/example/lib/device_details/device_details_bloc.dart b/example/lib/device_details/device_details_bloc.dart index fd805713..693de732 100644 --- a/example/lib/device_details/device_details_bloc.dart +++ b/example/lib/device_details/device_details_bloc.dart @@ -24,8 +24,6 @@ class DeviceDetailsBloc { Observable> get logs => _logsController.stream; - StreamSubscription connectionSubscription; - Stream get disconnectedDevice => _deviceRepository.pickedDevice .skipWhile((bleDevice) => bleDevice != null); @@ -38,22 +36,25 @@ class DeviceDetailsBloc { _deviceController = BehaviorSubject.seeded(device); _connectionStateController = - BehaviorSubject.seeded(device.isConnected - ? PeripheralConnectionState.connected - : PeripheralConnectionState.disconnected); + BehaviorSubject.seeded( + PeripheralConnectionState.disconnected); _logsController = PublishSubject>(); log = (text) { var now = DateTime.now(); - _logs.insert(0, DebugLog('${now.hour}:${now.minute}:${now.second}.${now.millisecond}', text)); + _logs.insert( + 0, + DebugLog( + '${now.hour}:${now.minute}:${now.second}.${now.millisecond}', + text, + )); Fimber.d(text); _logsController.add(_logs); }; logError = (text) { - _logs.insert(0, - DebugLog(DateTime.now().toString(), "ERROR: $text")); + _logs.insert(0, DebugLog(DateTime.now().toString(), "ERROR: $text")); Fimber.e(text); _logsController.add(_logs); }; @@ -112,7 +113,6 @@ class DeviceDetailsBloc { }); } - void readCharacteristicForPeripheral() { _clearLogs(); _deviceController.stream.listen((bleDevice) async { @@ -215,7 +215,8 @@ class DeviceDetailsBloc { var peripheral = bleDevice.peripheral; peripheral - .observeConnectionState(emitCurrentValue: true, completeOnDisconnect: true) + .observeConnectionState( + emitCurrentValue: true, completeOnDisconnect: true) .listen((connectionState) { log('Observed new connection state: \n$connectionState'); _connectionStateController.add(connectionState); @@ -232,7 +233,6 @@ class DeviceDetailsBloc { } void dispose() async { - _deviceController.value?.abandon(); await _deviceController.drain(); _deviceController.close(); diff --git a/example/lib/device_details/devices_details_bloc_provider.dart b/example/lib/device_details/devices_details_bloc_provider.dart index 2271f071..72952eaa 100644 --- a/example/lib/device_details/devices_details_bloc_provider.dart +++ b/example/lib/device_details/devices_details_bloc_provider.dart @@ -4,7 +4,6 @@ import 'package:flutter_ble_lib/flutter_ble_lib.dart'; import 'device_details_bloc.dart'; - class DeviceDetailsBlocProvider extends InheritedWidget { final DeviceDetailsBloc deviceDetailsBloc; @@ -12,14 +11,14 @@ class DeviceDetailsBlocProvider extends InheritedWidget { Key key, DeviceDetailsBloc deviceDetailsBloc, Widget child, - }) : deviceDetailsBloc = deviceDetailsBloc ?? DeviceDetailsBloc(DeviceRepository(), BleManager()), + }) : deviceDetailsBloc = deviceDetailsBloc ?? + DeviceDetailsBloc(DeviceRepository(), BleManager()), super(key: key, child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) => true; - static DeviceDetailsBloc of(BuildContext context) => - (context.inheritFromWidgetOfExactType(DeviceDetailsBlocProvider) - as DeviceDetailsBlocProvider) - .deviceDetailsBloc; + static DeviceDetailsBloc of(BuildContext context) => context + .dependOnInheritedWidgetOfExactType() + .deviceDetailsBloc; } diff --git a/example/lib/devices_list/devices_bloc.dart b/example/lib/devices_list/devices_bloc.dart index b35a251f..7544407a 100644 --- a/example/lib/devices_list/devices_bloc.dart +++ b/example/lib/devices_list/devices_bloc.dart @@ -1,10 +1,12 @@ import 'dart:async'; +import 'dart:io'; import 'package:fimber/fimber.dart'; import 'package:flutter_ble_lib_example/model/ble_device.dart'; import 'package:flutter_ble_lib_example/repository/device_repository.dart'; -import 'package:rxdart/rxdart.dart'; import 'package:flutter_ble_lib/flutter_ble_lib.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:rxdart/rxdart.dart'; class DevicesBloc { final List bleDevices = []; @@ -12,7 +14,8 @@ class DevicesBloc { BehaviorSubject> _visibleDevicesController = BehaviorSubject>.seeded([]); - StreamController _devicePickerController = StreamController(); + StreamController _devicePickerController = + StreamController(); StreamSubscription _scanSubscription; StreamSubscription _devicePickerSubscription; @@ -24,8 +27,10 @@ class DevicesBloc { DeviceRepository _deviceRepository; BleManager _bleManager; + PermissionStatus _locationPermissionStatus = PermissionStatus.unknown; - Stream get pickedDevice => _deviceRepository.pickedDevice.skipWhile((bleDevice) => bleDevice == null); + Stream get pickedDevice => _deviceRepository.pickedDevice + .skipWhile((bleDevice) => bleDevice == null); DevicesBloc(this._deviceRepository, this._bleManager); @@ -44,34 +49,51 @@ class DevicesBloc { void init() { Fimber.d("Init devices bloc"); bleDevices.clear(); - _bleManager.createClient( - restoreStateIdentifier: "example-restore-state-identifier", - restoreStateAction: (peripherals) { - peripherals?.forEach((peripheral) { - Fimber.d("Restored peripheral: ${peripheral.name}"); - }); - } - ) - .then((it) => startScan()) - .catchError((e) => Fimber.d("Couldn't create BLE client", ex: e)); + _bleManager + .createClient( + restoreStateIdentifier: "example-restore-state-identifier", + restoreStateAction: (peripherals) { + peripherals?.forEach((peripheral) { + Fimber.d("Restored peripheral: ${peripheral.name}"); + }); + }) + .catchError((e) => Fimber.d("Couldn't create BLE client", ex: e)) + .then((_) => _checkPermissions()) + .catchError((e) => Fimber.d("Permission check error", ex: e)) + .then((_) => _startScan()); if (_visibleDevicesController.isClosed) { - _visibleDevicesController = BehaviorSubject>.seeded([]); + _visibleDevicesController = + BehaviorSubject>.seeded([]); } if (_devicePickerController.isClosed) { _devicePickerController = StreamController(); } - Fimber.d(" listen to _devicePickerController.stream"); - _devicePickerSubscription = _devicePickerController.stream.listen(_handlePickedDevice); + _devicePickerSubscription = + _devicePickerController.stream.listen(_handlePickedDevice); + } + + Future _checkPermissions() async { + if (Platform.isAndroid) { + var permissionStatus = await PermissionHandler() + .requestPermissions([PermissionGroup.location]); + + _locationPermissionStatus = permissionStatus[PermissionGroup.location]; + + if (_locationPermissionStatus != PermissionStatus.granted) { + return Future.error(Exception("Location permission not granted")); + } + } } - void startScan() { + void _startScan() { Fimber.d("Ble client created"); - _scanSubscription = _bleManager.startPeripheralScan().listen((ScanResult scanResult) { - var bleDevice = BleDevice.notConnected(scanResult.peripheral.name, scanResult.peripheral.identifier, scanResult.peripheral); + _scanSubscription = + _bleManager.startPeripheralScan().listen((ScanResult scanResult) { + var bleDevice = BleDevice(scanResult); if (scanResult.advertisementData.localName != null && !bleDevices.contains(bleDevice)) { Fimber.d( @@ -87,6 +109,8 @@ class DevicesBloc { await _bleManager.stopPeripheralScan(); bleDevices.clear(); _visibleDevicesController.add(bleDevices.sublist(0)); - startScan(); + await _checkPermissions() + .then((_) => _startScan()) + .catchError((e) => Fimber.d("Couldn't refresh", ex: e)); } } diff --git a/example/lib/devices_list/devices_bloc_provider.dart b/example/lib/devices_list/devices_bloc_provider.dart index 59fce417..61156c86 100644 --- a/example/lib/devices_list/devices_bloc_provider.dart +++ b/example/lib/devices_list/devices_bloc_provider.dart @@ -3,7 +3,6 @@ import 'package:flutter_ble_lib_example/devices_list/devices_bloc.dart'; import 'package:flutter_ble_lib_example/repository/device_repository.dart'; import 'package:flutter_ble_lib/flutter_ble_lib.dart'; - class DevicesBlocProvider extends InheritedWidget { final DevicesBloc devicesBloc; @@ -11,14 +10,14 @@ class DevicesBlocProvider extends InheritedWidget { Key key, DevicesBloc devicesBloc, Widget child, - }) : devicesBloc = devicesBloc ?? DevicesBloc(DeviceRepository(), BleManager()), + }) : devicesBloc = + devicesBloc ?? DevicesBloc(DeviceRepository(), BleManager()), super(key: key, child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) => true; - static DevicesBloc of(BuildContext context) => - (context.inheritFromWidgetOfExactType(DevicesBlocProvider) - as DevicesBlocProvider) - .devicesBloc; + static DevicesBloc of(BuildContext context) => context + .dependOnInheritedWidgetOfExactType() + .devicesBloc; } diff --git a/example/lib/devices_list/devices_list_view.dart b/example/lib/devices_list/devices_list_view.dart index 9aa25b8d..ff4177a0 100644 --- a/example/lib/devices_list/devices_list_view.dart +++ b/example/lib/devices_list/devices_list_view.dart @@ -2,13 +2,12 @@ import 'dart:async'; import 'package:fimber/fimber.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_ble_lib_example/devices_list/hex_painter.dart'; + import 'package:flutter_ble_lib_example/model/ble_device.dart'; import 'devices_bloc.dart'; import 'devices_bloc_provider.dart'; - +import 'hex_painter.dart'; typedef DeviceTapListener = void Function(); @@ -74,11 +73,10 @@ class DeviceListScreenState extends State { body: StreamBuilder>( initialData: _devicesBloc.visibleDevices.value, stream: _devicesBloc.visibleDevices, - builder: (context, snapshot) => - RefreshIndicator( - onRefresh: _devicesBloc.refresh, - child: DevicesList(_devicesBloc, snapshot.data), - ), + builder: (context, snapshot) => RefreshIndicator( + onRefresh: _devicesBloc.refresh, + child: DevicesList(_devicesBloc, snapshot.data), + ), ), ); } diff --git a/example/lib/model/ble_device.dart b/example/lib/model/ble_device.dart index 6a9a60d3..eb8c1d7a 100644 --- a/example/lib/model/ble_device.dart +++ b/example/lib/model/ble_device.dart @@ -1,89 +1,48 @@ -import 'dart:async'; - import 'package:collection/collection.dart'; import 'package:flutter_ble_lib/flutter_ble_lib.dart'; -abstract class BleDevice { - String id; - int counter = 0; +class BleDevice { + final Peripheral peripheral; final String name; - DeviceCategory _category; - bool _isConnected = false; - Peripheral peripheral; - - bool get isConnected => - _isConnected; - - DeviceCategory get category => _category; - - BleDevice(this.name, this.id, this.peripheral) { - _category = _nameToCategory(name); - if(this.name == null) { - - } - } + final DeviceCategory category; - factory BleDevice.connected(BleDevice bleDevice) { - return ConnectedBleDevice(bleDevice.name, bleDevice.id, bleDevice.peripheral); - } + String get id => peripheral.identifier; - factory BleDevice.notConnected(String name, String id, Peripheral peripheral) { - return DisconnectedBleDevice(name, id, peripheral); - } - - DeviceCategory _nameToCategory(String name) { - if (name == "SensorTag") { - return DeviceCategory.sensorTag; - } else if (name!= null && name.startsWith("Hex")) { - return DeviceCategory.hex; - } else { - return DeviceCategory.other; - } - } + BleDevice(ScanResult scanResult) + : peripheral = scanResult.peripheral, + name = scanResult.name, + category = scanResult.category; @override - int get hashCode => 123; + int get hashCode => id.hashCode; @override bool operator ==(other) => - other is BleDevice - && this.name != null - && other.name != null - && compareAsciiLowerCase(this.name, other.name) == 0 - && this.id == other.id; + other is BleDevice && + this.name != null && + other.name != null && + compareAsciiLowerCase(this.name, other.name) == 0 && + this.id == other.id; @override String toString() { - return 'BleDevice{counter: $counter, name: $name}'; + return 'BleDevice{name: $name}'; } - - void abandon(); } -class DisconnectedBleDevice extends BleDevice { - StreamController _devicesInConnectingProcess; - - DisconnectedBleDevice(String name, String id, Peripheral peripheral) - : super(name ?? "", id, peripheral); - - @override - String toString() { - return 'DisconnectedBleDevice{} ${super.toString()}'; - } - - void abandon() { - _devicesInConnectingProcess?.close(); - } -} - -class ConnectedBleDevice extends BleDevice { +enum DeviceCategory { sensorTag, hex, other } - ConnectedBleDevice(String name, String id, Peripheral peripheral) - : super(name ?? "", id, peripheral); +extension on ScanResult { + String get name => + peripheral.name ?? advertisementData.localName ?? "Unknown"; - @override - void abandon() { + DeviceCategory get category { + if (name == "SensorTag") { + return DeviceCategory.sensorTag; + } else if (name != null && name.startsWith("Hex")) { + return DeviceCategory.hex; + } else { + return DeviceCategory.other; + } } } - -enum DeviceCategory { sensorTag, hex, other } diff --git a/example/lib/sensor_tag_config.dart b/example/lib/sensor_tag_config.dart index 780fdddc..c44ed09f 100644 --- a/example/lib/sensor_tag_config.dart +++ b/example/lib/sensor_tag_config.dart @@ -1,7 +1,12 @@ abstract class SensorTagTemperatureUuids { static const String temperatureService = "F000AA00-0451-4000-B000-000000000000"; - static const String temperatureDataCharacteristic = "F000AA01-0451-4000-B000-000000000000"; + static const String temperatureDataCharacteristic = + "F000AA01-0451-4000-B000-000000000000"; static const String temperatureConfigCharacteristic = "F000AA02-0451-4000-B000-000000000000"; + static const String characteristicUserDescriptionDescriptor = + "00002901-0000-1000-8000-00805f9b34fb"; + static const String clientCharacteristicConfigurationDescriptor = + "00002902-0000-1000-8000-00805f9b34fb"; } diff --git a/example/lib/test_scenarios/peripheral_test_operations.dart b/example/lib/test_scenarios/peripheral_test_operations.dart index dd514d33..dffe5d65 100644 --- a/example/lib/test_scenarios/peripheral_test_operations.dart +++ b/example/lib/test_scenarios/peripheral_test_operations.dart @@ -40,28 +40,64 @@ class PeripheralTestOperations { }); } - Future discovery() async { - await _runWithErrorHandling(() async { - await peripheral.discoverAllServicesAndCharacteristics(); - List services = await peripheral.services(); - log("PRINTING SERVICES for \n${peripheral.name}"); - services.forEach((service) => log("Found service \n${service.uuid}")); - Service service = services.first; - log("PRINTING CHARACTERISTICS FOR SERVICE \n${service.uuid}"); - - List characteristics = await service.characteristics(); - characteristics.forEach((characteristic) { - log("${characteristic.uuid}"); + Future discovery() async => await _runWithErrorHandling(() async { + await peripheral.discoverAllServicesAndCharacteristics(); + List services = await peripheral.services(); + log("PRINTING SERVICES for \n${peripheral.name}"); + services.forEach((service) => log("Found service \n${service.uuid}")); + Service service = services.first; + log("PRINTING CHARACTERISTICS FOR SERVICE \n${service.uuid}"); + + List characteristics = await service.characteristics(); + characteristics.forEach((characteristic) { + log("${characteristic.uuid}"); + }); + + log("PRINTING CHARACTERISTICS FROM \nPERIPHERAL for the same service"); + List characteristicFromPeripheral = + await peripheral.characteristics(service.uuid); + characteristicFromPeripheral.forEach((characteristic) => + log("Found characteristic \n ${characteristic.uuid}")); + + //------------ descriptors + List descriptors; + + var printDescriptors = () => descriptors.forEach((descriptor) { + log("Descriptor: ${descriptor.uuid}"); + }); + + log("Using IR Temperature service/IR Temperature Data " + "characteristic for following descriptor tests"); + log("PRINTING DESCRIPTORS FOR PERIPHERAL"); + + descriptors = await peripheral.descriptorsForCharacteristic( + SensorTagTemperatureUuids.temperatureService, + SensorTagTemperatureUuids.temperatureDataCharacteristic); + + printDescriptors(); + descriptors = null; + + log("PRINTING DESCRIPTORS FOR SERVICE"); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + descriptors = await chosenService.descriptorsForCharacteristic( + SensorTagTemperatureUuids.temperatureDataCharacteristic); + + printDescriptors(); + descriptors = null; + + List temperatureCharacteristics = + await chosenService.characteristics(); + Characteristic chosenCharacteristic = temperatureCharacteristics.first; + + log("PRINTING DESCRIPTORS FOR CHARACTERISTIC"); + descriptors = await chosenCharacteristic.descriptors(); + + printDescriptors(); }); - log("PRINTING CHARACTERISTICS FROM \nPERIPHERAL for the same service"); - List characteristicFromPeripheral = - await peripheral.characteristics(service.uuid); - characteristicFromPeripheral.forEach((characteristic) => - log("Found characteristic \n ${characteristic.uuid}")); - }); - } - Future testReadingRssi() async { await _runWithErrorHandling(() async { int rssi = await peripheral.rssi(); @@ -456,6 +492,223 @@ class PeripheralTestOperations { }); } + Future readDescriptorForPeripheral() async => + _runWithErrorHandling(() async { + log("READ DESCRIPTOR FOR PERIPHERAL"); + log("Reading value..."); + Uint8List value = await peripheral + .readDescriptor( + SensorTagTemperatureUuids.temperatureService, + SensorTagTemperatureUuids.temperatureDataCharacteristic, + SensorTagTemperatureUuids + .clientCharacteristicConfigurationDescriptor, + ) + .then((descriptorWithValue) => descriptorWithValue.value); + log("Value $value read!"); + }); + + Future readDescriptorForService() async => + _runWithErrorHandling(() async { + log("READ DESCRIPTOR FOR SERVICE"); + + log("Fetching service"); + List services = await peripheral.services(); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + log("Reading value..."); + Uint8List value = await chosenService + .readDescriptor( + SensorTagTemperatureUuids.temperatureDataCharacteristic, + SensorTagTemperatureUuids + .clientCharacteristicConfigurationDescriptor, + ) + .then((descriptorWithValue) => descriptorWithValue.value); + log("Value $value read!"); + }); + + Future readDescriptorForCharacteristic() async => + _runWithErrorHandling(() async { + log("READ DESCRIPTOR FOR CHARACTERISTIC"); + + log("Fetching service"); + List services = await peripheral.services(); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + log("Fetching characteristic"); + List temperatureCharacteristics = + await chosenService.characteristics(); + Characteristic chosenCharacteristic = temperatureCharacteristics.first; + + log("Reading value..."); + Uint8List value = await chosenCharacteristic + .readDescriptor( + SensorTagTemperatureUuids + .clientCharacteristicConfigurationDescriptor, + ) + .then((descriptorWithValue) => descriptorWithValue.value); + log("Value $value read!"); + }); + + Future readDescriptor() async => _runWithErrorHandling(() async { + log("READ DESCRIPTOR FOR DESCRIPTOR"); + + log("Fetching service"); + List services = await peripheral.services(); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + log("Fetching characteristic"); + List temperatureCharacteristics = + await chosenService.characteristics(); + Characteristic chosenCharacteristic = temperatureCharacteristics.first; + + log("Fetching descriptor"); + List descriptors = await chosenCharacteristic.descriptors(); + Descriptor chosenDescriptor = descriptors.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids + .clientCharacteristicConfigurationDescriptor); + + log("Reading value..."); + Uint8List value = await chosenDescriptor.read(); + log("Value $value read!"); + }); + + Future writeDescriptorForPeripheral({bool enable = false}) async => + _runWithErrorHandling(() async { + log("WRITE DESCRIPTOR FOR PERIPHERAL"); + log("Writing value..."); + Descriptor value = await peripheral.writeDescriptor( + SensorTagTemperatureUuids.temperatureService, + SensorTagTemperatureUuids.temperatureDataCharacteristic, + SensorTagTemperatureUuids.clientCharacteristicConfigurationDescriptor, + Uint8List.fromList([enable ? 1 : 0, 0]), + ); + log("Descriptor $value written to!"); + }); + + Future writeDescriptorForService({bool enable = false}) async => + _runWithErrorHandling(() async { + log("WRITE DESCRIPTOR FOR SERVICE"); + + log("Fetching service"); + List services = await peripheral.services(); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + log("Writing value..."); + Descriptor value = await chosenService.writeDescriptor( + SensorTagTemperatureUuids.temperatureDataCharacteristic, + SensorTagTemperatureUuids.clientCharacteristicConfigurationDescriptor, + Uint8List.fromList([enable ? 1 : 0, 0]), + ); + log("Descriptor $value written to!"); + }); + + Future writeDescriptorForCharacteristic({bool enable = false}) async => + _runWithErrorHandling(() async { + log("WRITE DESCRIPTOR FOR CHARACTERISTIC"); + + log("Fetching service"); + List services = await peripheral.services(); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + log("Fetching characteristic"); + List temperatureCharacteristics = + await chosenService.characteristics(); + Characteristic chosenCharacteristic = temperatureCharacteristics.first; + + log("Writing value..."); + Descriptor value = await chosenCharacteristic.writeDescriptor( + SensorTagTemperatureUuids.clientCharacteristicConfigurationDescriptor, + Uint8List.fromList([enable ? 1 : 0, 0]), + ); + log("Descriptor $value written to!"); + }); + + Future writeDescriptor({bool enable = false}) async => + _runWithErrorHandling(() async { + log("WRITE DESCRIPTOR FOR DESCRIPTOR"); + + log("Fetching service"); + List services = await peripheral.services(); + Service chosenService = services.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids.temperatureService.toLowerCase()); + + log("Fetching characteristic"); + List temperatureCharacteristics = + await chosenService.characteristics(); + Characteristic chosenCharacteristic = temperatureCharacteristics.first; + + log("Fetching descriptor"); + List descriptors = await chosenCharacteristic.descriptors(); + Descriptor chosenDescriptor = descriptors.firstWhere((elem) => + elem.uuid == + SensorTagTemperatureUuids + .clientCharacteristicConfigurationDescriptor); + + log("Writing value..."); + await chosenDescriptor.write( + Uint8List.fromList([enable ? 1 : 0, 0]), + ); + log("Descriptor $chosenDescriptor written to!"); + }); + + Future readWriteDescriptorForPeripheral() async => + _runWithErrorHandling( + () async { + log("READ/WRITE TEST FOR PERIPHERAL"); + await readDescriptorForPeripheral(); + await writeDescriptorForPeripheral(enable: true); + await readDescriptorForPeripheral(); + await writeDescriptorForPeripheral(enable: false); + await readDescriptorForPeripheral(); + }, + ); + + Future readWriteDescriptorForService() async => _runWithErrorHandling( + () async { + log("READ/WRITE TEST FOR SERVICE"); + await readDescriptorForService(); + await writeDescriptorForService(enable: true); + await readDescriptorForService(); + await writeDescriptorForService(enable: false); + await readDescriptorForService(); + }, + ); + + Future readWriteDescriptorForCharacteristic() async => + _runWithErrorHandling( + () async { + log("READ/WRITE TEST FOR CHARACTERISTIC"); + await readDescriptorForCharacteristic(); + await writeDescriptorForCharacteristic(enable: true); + await readDescriptorForCharacteristic(); + await writeDescriptorForCharacteristic(enable: false); + await readDescriptorForCharacteristic(); + }, + ); + + Future readWriteDescriptor() async => _runWithErrorHandling( + () async { + log("READ/WRITE TEST FOR DESCRIPTOR"); + await readDescriptor(); + await writeDescriptor(enable: true); + await readDescriptor(); + await writeDescriptor(enable: false); + await readDescriptor(); + }, + ); + void _startMonitoringTemperature( Stream characteristicUpdates, Function log) async { await monitoringStreamSubscription?.cancel(); @@ -504,6 +757,9 @@ class PeripheralTestOperations { } on BleError catch (e) { logError("BleError caught: ${e.errorCode.value} ${e.reason}"); } catch (e) { + if (e is Error) { + debugPrintStack(stackTrace: e.stackTrace); + } logError("${e.runtimeType}: $e"); } } diff --git a/example/lib/test_scenarios/sensor_tag_test_scenario.dart b/example/lib/test_scenarios/sensor_tag_test_scenario.dart index f9a629e6..c1151c28 100644 --- a/example/lib/test_scenarios/sensor_tag_test_scenario.dart +++ b/example/lib/test_scenarios/sensor_tag_test_scenario.dart @@ -14,11 +14,16 @@ class SensorTagTestScenario { _peripheralTestOperations.connect() .then((_) => _peripheralTestOperations.cancelTransaction()) .then((_) => _peripheralTestOperations.discovery()) -// .then((_) => _peripheralTestOperations.testRequestingMtu()) + .then((_) => _peripheralTestOperations.testRequestingMtu()) .then((_) => _peripheralTestOperations.testReadingRssi()) .then((_) => _peripheralTestOperations.readWriteMonitorCharacteristicForPeripheral()) .then((_) => _peripheralTestOperations.readWriteMonitorCharacteristicForService()) .then((_) => _peripheralTestOperations.readWriteMonitorCharacteristic()) + .then((_) => Future.delayed(Duration(milliseconds: 100))) + .then((_) => _peripheralTestOperations.readWriteDescriptorForPeripheral()) + .then((_) => _peripheralTestOperations.readWriteDescriptorForService()) + .then((_) => _peripheralTestOperations.readWriteDescriptorForCharacteristic()) + .then((_) => _peripheralTestOperations.readWriteDescriptor()) .then((_) => _peripheralTestOperations.fetchConnectedDevice()) .then((_) => _peripheralTestOperations.fetchKnownDevice()) .then((_) => _peripheralTestOperations.disconnect()) diff --git a/example/lib/test_scenarios/test_scenarios.dart b/example/lib/test_scenarios/test_scenarios.dart index e12709d8..076b4bfe 100644 --- a/example/lib/test_scenarios/test_scenarios.dart +++ b/example/lib/test_scenarios/test_scenarios.dart @@ -1,13 +1,12 @@ library test_scenarios; import 'dart:async'; -import 'dart:math'; import 'dart:typed_data'; +import 'package:flutter/widgets.dart'; import 'package:flutter_ble_lib/flutter_ble_lib.dart'; import '../sensor_tag_config.dart'; -import 'package:flutter_ble_lib/internal/constants.dart'; part 'base.dart'; part 'sensor_tag_test_with_scan_and_connection_scenario.dart'; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a18ece8c..7c04cabd 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,10 +1,10 @@ name: flutter_ble_lib_example description: Demonstrates how to use the flutter_ble_lib plugin. version: 0.0.1+1 -publish_to: 'none' +publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" dependencies: flutter: @@ -29,7 +29,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. @@ -39,13 +38,10 @@ flutter: assets: - assets/ti_logo.png # - images/a_dot_ham.jpeg - # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. - # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a diff --git a/ios/Classes/Constants/ArgumentKey.h b/ios/Classes/Constants/ArgumentKey.h index 086f2bc0..56981d17 100644 --- a/ios/Classes/Constants/ArgumentKey.h +++ b/ios/Classes/Constants/ArgumentKey.h @@ -22,6 +22,9 @@ extern NSString * const ARGUMENT_KEY_CHARACTERISTIC_IDENTIFIER; extern NSString * const ARGUMENT_KEY_VALUE; extern NSString * const ARGUMENT_KEY_WITH_RESPONSE; +extern NSString * const ARGUMENT_KEY_DESCRIPTOR_UUID; +extern NSString * const ARGUMENT_KEY_DESCRIPTOR_IDENTIFIER; + extern NSString * const ARGUMENT_KEY_MTU; extern NSString * const ARGUMENT_KEY_DEVICE_IDENTIFIERS; diff --git a/ios/Classes/Constants/ArgumentKey.m b/ios/Classes/Constants/ArgumentKey.m index 96cabe3c..590a4df8 100644 --- a/ios/Classes/Constants/ArgumentKey.m +++ b/ios/Classes/Constants/ArgumentKey.m @@ -22,6 +22,9 @@ NSString * const ARGUMENT_KEY_VALUE = @"value"; NSString * const ARGUMENT_KEY_WITH_RESPONSE = @"withResponse"; +NSString * const ARGUMENT_KEY_DESCRIPTOR_UUID = @"descriptorUuid"; +NSString * const ARGUMENT_KEY_DESCRIPTOR_IDENTIFIER = @"descriptorIdentifier"; + NSString * const ARGUMENT_KEY_MTU = @"mtu"; NSString * const ARGUMENT_KEY_DEVICE_IDENTIFIERS = @"deviceIdentifiers"; diff --git a/ios/Classes/Constants/MethodName.h b/ios/Classes/Constants/MethodName.h index 19c4569b..71d34776 100644 --- a/ios/Classes/Constants/MethodName.h +++ b/ios/Classes/Constants/MethodName.h @@ -21,6 +21,10 @@ extern NSString * const METHOD_NAME_GET_SERVICES; extern NSString * const METHOD_NAME_GET_CHARACTERISTICS; extern NSString * const METHOD_NAME_GET_CHARACTERISTICS_FOR_SERVICE; +extern NSString * const METHOD_NAME_GET_DESCRIPTORS_FOR_DEVICE; +extern NSString * const METHOD_NAME_GET_DESCRIPTORS_FOR_SERVICE; +extern NSString * const METHOD_NAME_GET_DESCRIPTORS_FOR_CHARACTERISTIC; + extern NSString * const METHOD_NAME_LOG_LEVEL; extern NSString * const METHOD_NAME_SET_LOG_LEVEL; @@ -42,3 +46,13 @@ extern NSString * const METHOD_NAME_WRITE_CHARACTERISTIC_FOR_SERVICE; extern NSString * const METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_IDENTIFIER; extern NSString * const METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_DEVICE; extern NSString * const METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_SERVICE; + +extern NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_IDENTIFIER; +extern NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_CHARACTERISTIC; +extern NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_SERVICE; +extern NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_DEVICE; + +extern NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_IDENTIFIER; +extern NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_CHARACTERISTIC; +extern NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_SERVICE; +extern NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_DEVICE; diff --git a/ios/Classes/Constants/MethodName.m b/ios/Classes/Constants/MethodName.m index 737ceb8f..eed61449 100644 --- a/ios/Classes/Constants/MethodName.m +++ b/ios/Classes/Constants/MethodName.m @@ -20,6 +20,9 @@ NSString * const METHOD_NAME_GET_SERVICES = @"services"; NSString * const METHOD_NAME_GET_CHARACTERISTICS = @"characteristics"; NSString * const METHOD_NAME_GET_CHARACTERISTICS_FOR_SERVICE = @"characteristicsForService"; +NSString * const METHOD_NAME_GET_DESCRIPTORS_FOR_DEVICE = @"descriptorsForDevice"; +NSString * const METHOD_NAME_GET_DESCRIPTORS_FOR_SERVICE = @"descriptorsForService"; +NSString * const METHOD_NAME_GET_DESCRIPTORS_FOR_CHARACTERISTIC = @"descriptorsForCharacteristic"; NSString * const METHOD_NAME_LOG_LEVEL = @"logLevel"; NSString * const METHOD_NAME_SET_LOG_LEVEL = @"setLogLevel"; @@ -42,3 +45,13 @@ NSString * const METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_IDENTIFIER = @"monitorCharacteristicForIdentifier"; NSString * const METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_DEVICE = @"monitorCharacteristicForDevice"; NSString * const METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_SERVICE = @"monitorCharacteristicForService"; + +NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_IDENTIFIER = @"readDescriptorForIdentifier"; +NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_CHARACTERISTIC = @"readDescriptorForCharacteristic"; +NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_SERVICE = @"readDescriptorForService"; +NSString * const METHOD_NAME_READ_DESCRIPTOR_FOR_DEVICE = @"readDescriptorForDevice"; + +NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_IDENTIFIER = @"writeDescriptorForIdentifier"; +NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_CHARACTERISTIC = @"writeDescriptorForCharacteristic"; +NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_SERVICE = @"writeDescriptorForService"; +NSString * const METHOD_NAME_WRITE_DESCRIPTOR_FOR_DEVICE = @"writeDescriptorForDevice"; diff --git a/ios/Classes/FlutterBleLibPlugin.m b/ios/Classes/FlutterBleLibPlugin.m index 175ae3fc..f63ae4e7 100644 --- a/ios/Classes/FlutterBleLibPlugin.m +++ b/ios/Classes/FlutterBleLibPlugin.m @@ -12,6 +12,7 @@ #import "CommonTypes.h" #import "CharacteristicResponseConverter.h" #import "PeripheralResponseConverter.h" +#import "DescriptorResponseConverter.h" #import "ServiceResponseConverter.h" @import MultiplatformBleAdapter; @@ -98,6 +99,12 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result [self characteristicsForService:call result:result]; } else if ([METHOD_NAME_GET_CHARACTERISTICS isEqualToString:call.method]) { [self characteristics:call result:result]; + } else if ([METHOD_NAME_GET_DESCRIPTORS_FOR_DEVICE isEqualToString:call.method]) { + [self descriptorsForDevice:call result:result]; + } else if ([METHOD_NAME_GET_DESCRIPTORS_FOR_SERVICE isEqualToString:call.method]) { + [self descriptorsForService:call result:result]; + } else if ([METHOD_NAME_GET_DESCRIPTORS_FOR_CHARACTERISTIC isEqualToString:call.method]) { + [self descriptorsForCharacteristic:call result:result]; } else if ([METHOD_NAME_READ_CHARACTERISTIC_FOR_DEVICE isEqualToString:call.method]) { [self readCharacteristicForDevice:call result:result]; } else if ([METHOD_NAME_READ_CHARACTERISTIC_FOR_SERVICE isEqualToString:call.method]) { @@ -116,6 +123,22 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result [self monitorCharacteristicForService:call result:result]; } else if ([METHOD_NAME_MONITOR_CHARACTERISTIC_FOR_IDENTIFIER isEqualToString:call.method]) { [self monitorCharacteristic:call result:result]; + } else if ([METHOD_NAME_READ_DESCRIPTOR_FOR_DEVICE isEqualToString:call.method]) { + [self readDescriptorForDevice:call result:result]; + } else if ([METHOD_NAME_READ_DESCRIPTOR_FOR_SERVICE isEqualToString:call.method]) { + [self readDescriptorForService:call result:result]; + } else if ([METHOD_NAME_READ_DESCRIPTOR_FOR_CHARACTERISTIC isEqualToString:call.method]) { + [self readDescriptorForCharacteristic:call result:result]; + } else if ([METHOD_NAME_READ_DESCRIPTOR_FOR_IDENTIFIER isEqualToString:call.method]) { + [self readDescriptorForIdentifier:call result:result]; + } else if ([METHOD_NAME_WRITE_DESCRIPTOR_FOR_DEVICE isEqualToString:call.method]) { + [self writeDescriptorForDevice:call result:result]; + } else if ([METHOD_NAME_WRITE_DESCRIPTOR_FOR_SERVICE isEqualToString:call.method]) { + [self writeDescriptorForService:call result:result]; + } else if ([METHOD_NAME_WRITE_DESCRIPTOR_FOR_CHARACTERISTIC isEqualToString:call.method]) { + [self writeDescriptorForCharacteristic:call result:result]; + } else if ([METHOD_NAME_WRITE_DESCRIPTOR_FOR_IDENTIFIER isEqualToString:call.method]) { + [self writeDescriptorForIdentifier:call result:result]; } else if ([METHOD_NAME_GET_KNOWN_DEVICES isEqualToString:call.method]) { [self devices:call result:result]; } else if ([METHOD_NAME_GET_CONNECTED_DEVICES isEqualToString:call.method]) { @@ -259,13 +282,34 @@ - (void)characteristicsForService:(FlutterMethodCall *)call result:(FlutterResul } - (void)characteristics:(FlutterMethodCall *)call result:(FlutterResult)result { - [_adapter servicesForDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] - resolve:[self resolveForCharacteristics:result - serviceUuid:call.arguments[ARGUMENT_KEY_SERVICE_UUID]] - reject:[self rejectForFlutterResult:result]]; + [_adapter characteristicsForDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] + serviceUUID:call.arguments[ARGUMENT_KEY_SERVICE_UUID] + resolve:[self resolveForCharacteristics:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)descriptorsForDevice:(FlutterMethodCall *)call result:(FlutterResult)result { + [_adapter descriptorsForDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] + serviceUUID:call.arguments[ARGUMENT_KEY_SERVICE_UUID] + characteristicUUID:call.arguments[ARGUMENT_KEY_CHARACTERISTIC_UUID] + resolve:[self resolveForDescriptors:result] + reject:[self rejectForFlutterResult:result]]; } -// MARK: - MBA Methods - Characteristics observation +- (void)descriptorsForService:(FlutterMethodCall *)call result:(FlutterResult)result { + [_adapter descriptorsForService:[call.arguments[ARGUMENT_KEY_SERVICE_ID] doubleValue] + characteristicUUID:call.arguments[ARGUMENT_KEY_CHARACTERISTIC_UUID] + resolve:[self resolveForDescriptors:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)descriptorsForCharacteristic:(FlutterMethodCall *)call result:(FlutterResult)result { + [_adapter descriptorsForCharacteristic:[call.arguments[ARGUMENT_KEY_CHARACTERISTIC_IDENTIFIER] doubleValue] + resolve:[self resolveForDescriptors:result] + reject:[self rejectForFlutterResult:result]]; +} + +// MARK: - MBA Methods - Characteristics operations - (void)readCharacteristicForDevice:(FlutterMethodCall *)call result:(FlutterResult)result { [_adapter readCharacteristicForDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] @@ -352,6 +396,80 @@ - (void)monitorCharacteristic:(FlutterMethodCall *)call result:(FlutterResult)re reject:[self rejectForFlutterResult:result]]; } +// MARK: - MBA Method - Descriptor operations + +- (void)readDescriptorForDevice:(FlutterMethodCall *)call result:(FlutterResult)result { + [_adapter readDescriptorForDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] + serviceUUID:call.arguments[ARGUMENT_KEY_SERVICE_UUID] + characteristicUUID:call.arguments[ARGUMENT_KEY_CHARACTERISTIC_UUID] + descriptorUUID:call.arguments[ARGUMENT_KEY_DESCRIPTOR_UUID] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)readDescriptorForService:(FlutterMethodCall *)call result:(FlutterResult)result { + [_adapter readDescriptorForService:[call.arguments[ARGUMENT_KEY_SERVICE_ID] doubleValue] + characteristicUUID:call.arguments[ARGUMENT_KEY_CHARACTERISTIC_UUID] + descriptorUUID:call.arguments[ARGUMENT_KEY_DESCRIPTOR_UUID] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)readDescriptorForCharacteristic:(FlutterMethodCall *) call result:(FlutterResult) result { + [_adapter readDescriptorForCharacteristic:[call.arguments[ARGUMENT_KEY_CHARACTERISTIC_IDENTIFIER] doubleValue] + descriptorUUID:call.arguments[ARGUMENT_KEY_DESCRIPTOR_UUID] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)readDescriptorForIdentifier:(FlutterMethodCall *) call result:(FlutterResult) result { + [_adapter readDescriptor:[call.arguments[ARGUMENT_KEY_DESCRIPTOR_IDENTIFIER] doubleValue] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)writeDescriptorForDevice:(FlutterMethodCall *) call result:(FlutterResult) result { + [_adapter writeDescriptorForDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] + serviceUUID:call.arguments[ARGUMENT_KEY_SERVICE_UUID] + characteristicUUID:call.arguments[ARGUMENT_KEY_CHARACTERISTIC_UUID] + descriptorUUID:call.arguments[ARGUMENT_KEY_DESCRIPTOR_UUID] + valueBase64:[self base64encodedStringFromBytes:call.arguments[ARGUMENT_KEY_VALUE]] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)writeDescriptorForService:(FlutterMethodCall *) call result:(FlutterResult) result { + [_adapter writeDescriptorForService:[call.arguments[ARGUMENT_KEY_SERVICE_ID] doubleValue] + characteristicUUID:call.arguments[ARGUMENT_KEY_CHARACTERISTIC_UUID] + descriptorUUID:call.arguments[ARGUMENT_KEY_DESCRIPTOR_UUID] + valueBase64:[self base64encodedStringFromBytes:call.arguments[ARGUMENT_KEY_VALUE]] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)writeDescriptorForCharacteristic:(FlutterMethodCall *) call result:(FlutterResult) result { + [_adapter writeDescriptorForCharacteristic:[call.arguments[ARGUMENT_KEY_CHARACTERISTIC_IDENTIFIER] doubleValue] + descriptorUUID:call.arguments[ARGUMENT_KEY_DESCRIPTOR_UUID] + valueBase64:[self base64encodedStringFromBytes:call.arguments[ARGUMENT_KEY_VALUE]] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + +- (void)writeDescriptorForIdentifier:(FlutterMethodCall *) call result:(FlutterResult) result { + [_adapter writeDescriptor:[call.arguments[ARGUMENT_KEY_DESCRIPTOR_IDENTIFIER] doubleValue] + valueBase64:[self base64encodedStringFromBytes:call.arguments[ARGUMENT_KEY_VALUE]] + transactionId:[ArgumentHandler stringOrNil:call.arguments[ARGUMENT_KEY_TRANSACTION_ID]] + resolve:[self resolveForReadWriteDescriptor:result] + reject:[self rejectForFlutterResult:result]]; +} + // MARK: - MBA Methods - Known / Connected devices - (void)devices:(FlutterMethodCall *)call result:(FlutterResult)result { @@ -414,6 +532,12 @@ - (void)dispatchEvent:(NSString * _Nonnull)name value:(id _Nonnull)value { // MARK: - Utility methods +- (Resolve)resolveForReadWriteDescriptor:(FlutterResult)result { + return ^(NSDictionary *descriptorResponse) { + result([DescriptorResponseConverter jsonStringFromDescriptorResponse:descriptorResponse]); + }; +} + - (Resolve)resolveForCancelConnection:(FlutterResult)result { return ^(id response) { result(nil); @@ -432,30 +556,15 @@ - (Resolve)resolveForCharacteristicsForService:(FlutterResult)result { }; } -- (Resolve)resolveForCharacteristics:(FlutterResult)result serviceUuid:(NSString *)serviceUuid { - return ^(NSArray *servicesArray) { - - NSDictionary *matchingService = nil; - for (NSDictionary *service in [ServiceResponseConverter servicesFromServicesResponse:servicesArray]) { - if ([[service valueForKey:@"serviceUuid"] isEqualToString:serviceUuid]) { - matchingService = service; - break; - } - } - - if (matchingService == nil) { - result([FlutterError errorWithCode:@"-1" message:@"Service not found" details:nil]); - return; - } - - Resolve resolve = ^(NSArray* characteristicsArray) { - result([CharacteristicResponseConverter jsonStringFromCharacteristicsResponse:characteristicsArray - service:matchingService]); - }; +- (Resolve)resolveForCharacteristics:(FlutterResult)result { + return ^(NSArray* characteristicsArray) { + result([CharacteristicResponseConverter jsonStringWithServiceFromCharacteristicsResponse:characteristicsArray]); + }; +} - [_adapter characteristicsForService:[[matchingService valueForKey:@"serviceId"] doubleValue] - resolve:resolve - reject:[self rejectForFlutterResult:result]]; +- (Resolve)resolveForDescriptors:(FlutterResult)result { + return ^(NSArray *descriptorsArray) { + result([DescriptorResponseConverter jsonStringFromMultipleDescriptorsResponse:descriptorsArray]); }; } diff --git a/ios/Classes/Response/DescriptorResponse.h b/ios/Classes/Response/DescriptorResponse.h new file mode 100644 index 00000000..b10423dd --- /dev/null +++ b/ios/Classes/Response/DescriptorResponse.h @@ -0,0 +1,7 @@ +extern NSString * const DESCRIPTOR_RESPONSE_UUID; +extern NSString * const DESCRIPTOR_RESPONSE_ID; +extern NSString * const DESCRIPTOR_RESPONSE_VALUE; +extern NSString * const DESCRIPTOR_RESPONSE_CHARACTERISTIC_UUID; +extern NSString * const DESCRIPTOR_RESPONSE_CHARACTERISTIC_ID; +extern NSString * const DESCRIPTOR_RESPONSE_SERVICE_UUID; +extern NSString * const DESCRIPTOR_RESPONSE_SERVICE_ID; diff --git a/ios/Classes/Response/DescriptorResponse.m b/ios/Classes/Response/DescriptorResponse.m new file mode 100644 index 00000000..b8f3a1ec --- /dev/null +++ b/ios/Classes/Response/DescriptorResponse.m @@ -0,0 +1,7 @@ +NSString * const DESCRIPTOR_RESPONSE_UUID = @"uuid"; +NSString * const DESCRIPTOR_RESPONSE_ID = @"id"; +NSString * const DESCRIPTOR_RESPONSE_VALUE = @"value"; +NSString * const DESCRIPTOR_RESPONSE_CHARACTERISTIC_UUID = @"characteristicUUID"; +NSString * const DESCRIPTOR_RESPONSE_CHARACTERISTIC_ID = @"characteristicID"; +NSString * const DESCRIPTOR_RESPONSE_SERVICE_UUID = @"serviceUUID"; +NSString * const DESCRIPTOR_RESPONSE_SERVICE_ID = @"serviceID"; diff --git a/ios/Classes/ResponseConverter/CharacteristicResponseConverter.h b/ios/Classes/ResponseConverter/CharacteristicResponseConverter.h index 0cf3b0db..dfe48e8c 100644 --- a/ios/Classes/ResponseConverter/CharacteristicResponseConverter.h +++ b/ios/Classes/ResponseConverter/CharacteristicResponseConverter.h @@ -5,8 +5,7 @@ + (NSString *)jsonStringFromCharacteristicsResponse:(NSArray *)characteristicsResponse; -+ (NSString *)jsonStringFromCharacteristicsResponse:(NSArray *)characteristicsResponse - service:(NSDictionary *)service; ++ (NSString *)jsonStringWithServiceFromCharacteristicsResponse:(NSArray *)characteristicsResponse; + (NSArray *)characteristicsFromCharacteristicResponse:(NSArray *)characteristicsResponse; diff --git a/ios/Classes/ResponseConverter/CharacteristicResponseConverter.m b/ios/Classes/ResponseConverter/CharacteristicResponseConverter.m index addc1f41..e957481f 100644 --- a/ios/Classes/ResponseConverter/CharacteristicResponseConverter.m +++ b/ios/Classes/ResponseConverter/CharacteristicResponseConverter.m @@ -38,11 +38,24 @@ + (NSString *)jsonStringFromCharacteristicsResponse:(NSArray *)characteristicsRe return [JSONStringifier jsonStringFromJSONObject:result]; } -+ (NSString *)jsonStringFromCharacteristicsResponse:(NSArray *)characteristicsResponse - service:(NSDictionary *)service { - NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithDictionary:service]; - [result setObject:[self characteristicsFromCharacteristicResponse:characteristicsResponse] - forKey:keyCharacteristics]; ++ (NSString *)jsonStringWithServiceFromCharacteristicsResponse:(NSArray *)characteristicsResponse { + NSArray *characteristics = [self characteristicsFromCharacteristicResponse:characteristicsResponse]; + id serviceId; + id serviceUuid; + + if (characteristicsResponse.count == 0) { + serviceId = [NSNumber numberWithInt:-1]; + serviceUuid = [NSNull null]; + } else { + serviceId = [characteristicsResponse.firstObject objectForKey:CHARACTERISTIC_RESPONSE_SERVICE_ID]; + serviceUuid = [characteristicsResponse.firstObject objectForKey:CHARACTERISTIC_RESPONSE_SERVICE_UUID]; + } + + NSDictionary *result = [[NSDictionary alloc] initWithObjectsAndKeys: + characteristics, keyCharacteristics, + serviceId, keyServiceID, + serviceUuid, keyServiceUUID, + nil]; return [JSONStringifier jsonStringFromJSONObject:result]; } diff --git a/ios/Classes/ResponseConverter/DescriptorResponseConverter.h b/ios/Classes/ResponseConverter/DescriptorResponseConverter.h new file mode 100644 index 00000000..e343d58a --- /dev/null +++ b/ios/Classes/ResponseConverter/DescriptorResponseConverter.h @@ -0,0 +1,7 @@ +@interface DescriptorResponseConverter : NSObject + ++ (NSString *)jsonStringFromDescriptorResponse:(NSDictionary *)response; + ++ (NSString *)jsonStringFromMultipleDescriptorsResponse:(NSArray *)descriptorsResponse; + +@end diff --git a/ios/Classes/ResponseConverter/DescriptorResponseConverter.m b/ios/Classes/ResponseConverter/DescriptorResponseConverter.m new file mode 100644 index 00000000..710dfc56 --- /dev/null +++ b/ios/Classes/ResponseConverter/DescriptorResponseConverter.m @@ -0,0 +1,55 @@ +#import "DescriptorResponseConverter.h" +#import "DescriptorResponse.h" +#import "JSONStringifier.h" + +@implementation DescriptorResponseConverter + +const NSString *keyDescriptorResponseDescriptorId = @"descriptorId"; +const NSString *keyDescriptorResponseDescriptorUuid = @"descriptorUuid"; +const NSString *keyDescriptorResponseValue = @"value"; +const NSString *keyDescriptorResponseServiceId = @"serviceId"; +const NSString *keyDescriptorResponseServiceUuid = @"serviceUuid"; +const NSString *keyDescriptorResponseCharacteristicId = @"id"; +const NSString *keyDescriptorResponseCharacteristicUuid = @"uuid"; +const NSString *keyDescriptorResponseDescriptors = @"descriptors"; + ++ (NSString *)jsonStringFromDescriptorResponse:(NSDictionary *)response { + NSDictionary *result = [[NSDictionary alloc] initWithObjectsAndKeys: + [response objectForKey:DESCRIPTOR_RESPONSE_ID], keyDescriptorResponseDescriptorId, + [response objectForKey:DESCRIPTOR_RESPONSE_UUID], keyDescriptorResponseDescriptorUuid, + [response objectForKey:DESCRIPTOR_RESPONSE_VALUE], keyDescriptorResponseValue, + [response objectForKey:DESCRIPTOR_RESPONSE_SERVICE_ID], keyDescriptorResponseServiceId, + [response objectForKey:DESCRIPTOR_RESPONSE_SERVICE_UUID], keyDescriptorResponseServiceUuid, + [response objectForKey:DESCRIPTOR_RESPONSE_CHARACTERISTIC_ID], keyDescriptorResponseCharacteristicId, + [response objectForKey:DESCRIPTOR_RESPONSE_CHARACTERISTIC_UUID], keyDescriptorResponseCharacteristicUuid, + nil]; + return [JSONStringifier jsonStringFromJSONObject:result]; +} + ++ (NSString *)jsonStringFromMultipleDescriptorsResponse:(NSArray *)descriptorsResponse { + if ([descriptorsResponse count] > 0) { + NSMutableArray *descriptors = [[NSMutableArray alloc] init]; + for (NSDictionary *singleDescriptor in descriptorsResponse) { + [descriptors addObject:[[NSDictionary alloc] initWithObjectsAndKeys: + [singleDescriptor objectForKey:DESCRIPTOR_RESPONSE_ID], keyDescriptorResponseDescriptorId, + [singleDescriptor objectForKey:DESCRIPTOR_RESPONSE_UUID], keyDescriptorResponseDescriptorUuid, + nil] + ]; + } + + NSDictionary *firstDescriptor = descriptorsResponse[0]; + NSDictionary *result = [[NSDictionary alloc] initWithObjectsAndKeys: + [firstDescriptor objectForKey:DESCRIPTOR_RESPONSE_SERVICE_ID], keyDescriptorResponseServiceId, + [firstDescriptor objectForKey:DESCRIPTOR_RESPONSE_SERVICE_UUID], keyDescriptorResponseServiceUuid, + [firstDescriptor objectForKey:DESCRIPTOR_RESPONSE_CHARACTERISTIC_ID], keyDescriptorResponseCharacteristicId, + [firstDescriptor objectForKey:DESCRIPTOR_RESPONSE_CHARACTERISTIC_UUID], keyDescriptorResponseCharacteristicUuid, + descriptors, keyDescriptorResponseDescriptors, + nil]; + + return [JSONStringifier jsonStringFromJSONObject:result]; + } else { + return [JSONStringifier jsonStringFromJSONObject:descriptorsResponse]; + } +} + +@end diff --git a/ios/flutter_ble_lib.podspec b/ios/flutter_ble_lib.podspec index bbbd3522..76b0dc4e 100644 --- a/ios/flutter_ble_lib.podspec +++ b/ios/flutter_ble_lib.podspec @@ -3,7 +3,7 @@ # Pod::Spec.new do |s| s.name = 'flutter_ble_lib' - s.version = '0.0.1' + s.version = '2.2.0' s.summary = 'A new flutter plugin project.' s.description = <<-DESC A new flutter plugin project. @@ -15,8 +15,9 @@ A new flutter plugin project. s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - s.dependency 'MultiplatformBleAdapter', '0.0.4' + s.swift_versions = ['4.0', '4.2', '5.0'] + s.dependency 'MultiplatformBleAdapter', '0.1.4' - s.ios.deployment_target = '10.0' + s.ios.deployment_target = '8.0' end diff --git a/lib/characteristic.dart b/lib/characteristic.dart index 3ec9a544..02bf9980 100644 --- a/lib/characteristic.dart +++ b/lib/characteristic.dart @@ -63,6 +63,31 @@ class Characteristic extends InternalCharacteristic { transactionId ?? TransactionIdGenerator.getNextId(), ); + Future> descriptors() => + _manager.descriptorsForCharacteristic(this); + + Future readDescriptor( + String descriptorUuid, { + String transactionId, + }) => + _manager.readDescriptorForCharacteristic( + this, + descriptorUuid, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + + Future writeDescriptor( + String descriptorUuid, + Uint8List value, { + String transactionId, + }) => + _manager.writeDescriptorForCharacteristic( + this, + descriptorUuid, + value, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + @override bool operator ==(Object other) => identical(this, other) || @@ -90,14 +115,17 @@ class Characteristic extends InternalCharacteristic { @override String toString() { - return 'Characteristic{service: $service, _manager: $_manager, uuid: $uuid, isReadable: $isReadable, isWritableWithResponse: $isWritableWithResponse, isWritableWithoutResponse: $isWritableWithoutResponse, isNotifiable: $isNotifiable, isIndicatable: $isIndicatable}'; + return 'Characteristic{service: $service,' + ' _manager: $_manager,' + ' uuid: $uuid,' + ' isReadable: $isReadable,' + ' isWritableWithResponse: $isWritableWithResponse,' + ' isWritableWithoutResponse: $isWritableWithoutResponse,' + ' isNotifiable: $isNotifiable,' + ' isIndicatable: $isIndicatable}'; } } -mixin WithValue on Characteristic { - Uint8List value; -} - class CharacteristicWithValue extends Characteristic with WithValue { CharacteristicWithValue.fromJson( Map jsonObject, diff --git a/lib/descriptor.dart b/lib/descriptor.dart new file mode 100644 index 00000000..9b938721 --- /dev/null +++ b/lib/descriptor.dart @@ -0,0 +1,46 @@ +part of flutter_ble_lib; + +abstract class _DescriptorMetadata { + static const String uuid = "descriptorUuid"; + static const String id = "descriptorId"; + static const String value = "value"; +} + +class Descriptor extends InternalDescriptor { + ManagerForDescriptor _manager; + Characteristic characteristic; + String uuid; + + Descriptor.fromJson( + Map jsonObject, + Characteristic characteristic, + ManagerForDescriptor manager, + ) : super(jsonObject[_DescriptorMetadata.id]) { + _manager = manager; + this.characteristic = characteristic; + uuid = jsonObject[_DescriptorMetadata.uuid]; + } + + Future read({String transactionId}) => + _manager.readDescriptorForIdentifier( + this, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + + Future write(Uint8List value, {String transactionId}) => + _manager.writeDescriptorForIdentifier( + this, + value, + transactionId ?? TransactionIdGenerator.getNextId(), + ); +} + +class DescriptorWithValue extends Descriptor with WithValue { + DescriptorWithValue.fromJson( + Map jsonObject, + Characteristic characteristic, + ManagerForDescriptor manager, + ) : super.fromJson(jsonObject, characteristic, manager) { + value = base64Decode(jsonObject[_DescriptorMetadata.value]); + } +} diff --git a/lib/error/ble_error.dart b/lib/error/ble_error.dart index e2e15300..1b1ddbd9 100644 --- a/lib/error/ble_error.dart +++ b/lib/error/ble_error.dart @@ -92,6 +92,7 @@ class BleErrorCode { static const int DescriptorNotFound = 503; static const int DescriptorsNotDiscovered = 504; static const int DescriptorInvalidDataFormat = 505; + static const int DescriptorWriteNotAllowed = 506; static const int ScanStartFailed = 600; static const int LocationServicesDisabled = 601; diff --git a/lib/flutter_ble_lib.dart b/lib/flutter_ble_lib.dart index 6b8226c8..2d35f51e 100644 --- a/lib/flutter_ble_lib.dart +++ b/lib/flutter_ble_lib.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; -import 'package:flutter_ble_lib/internal/bridge/internal_bridge_lib.dart'; +import 'package:flutter_ble_lib/internal/_internal.dart'; import 'package:flutter_ble_lib/internal/util/transaction_id_generator.dart'; import 'internal/managers_for_classes.dart'; @@ -12,6 +12,7 @@ import 'internal/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'; diff --git a/lib/internal/bridge/internal_bridge_lib.dart b/lib/internal/_internal.dart similarity index 50% rename from lib/internal/bridge/internal_bridge_lib.dart rename to lib/internal/_internal.dart index e848698f..e9dcabb8 100644 --- a/lib/internal/bridge/internal_bridge_lib.dart +++ b/lib/internal/_internal.dart @@ -1,4 +1,4 @@ -library internal_bridge_lib; +library _internal; import 'dart:async'; import 'dart:convert'; @@ -13,28 +13,30 @@ import 'package:flutter_ble_lib/internal/containers.dart'; import 'package:flutter_ble_lib/internal/util/transaction_id_generator.dart'; import 'package:flutter_ble_lib/internal/util/transformers.dart'; -import '../managers_for_classes.dart'; +import 'managers_for_classes.dart'; -part '../base_entities.dart'; +part 'base_entities.dart'; -part '../internal_ble_manager.dart'; +part 'internal_ble_manager.dart'; -part 'bluetooth_state_mixin.dart'; +part 'bridge/bluetooth_state_mixin.dart'; -part 'characteristics_mixin.dart'; +part 'bridge/characteristics_mixin.dart'; -part 'device_connection_mixin.dart'; +part 'bridge/device_connection_mixin.dart'; -part 'device_rssi_mixin.dart'; +part 'bridge/descriptors_mixin.dart'; -part 'devices_mixin.dart'; +part 'bridge/device_rssi_mixin.dart'; -part 'discovery_mixin.dart'; +part 'bridge/devices_mixin.dart'; -part 'lib_core.dart'; +part 'bridge/discovery_mixin.dart'; -part 'log_level_mixin.dart'; +part 'bridge/lib_core.dart'; -part 'mtu_mixin.dart'; +part 'bridge/log_level_mixin.dart'; -part 'scanning_mixin.dart'; +part 'bridge/mtu_mixin.dart'; + +part 'bridge/scanning_mixin.dart'; diff --git a/lib/internal/base_entities.dart b/lib/internal/base_entities.dart index f6cc8f0b..2d8fada1 100644 --- a/lib/internal/base_entities.dart +++ b/lib/internal/base_entities.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; class InternalService { int _id; @@ -11,3 +11,13 @@ class InternalCharacteristic { InternalCharacteristic(this._id); } + +class InternalDescriptor { + int _id; + + InternalDescriptor(this._id); +} + +mixin WithValue { + Uint8List value; +} diff --git a/lib/internal/bridge/bluetooth_state_mixin.dart b/lib/internal/bridge/bluetooth_state_mixin.dart index 83f2ca2a..bc379167 100644 --- a/lib/internal/bridge/bluetooth_state_mixin.dart +++ b/lib/internal/bridge/bluetooth_state_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin BluetoothStateMixin on FlutterBLE { final Stream _adapterStateChanges = diff --git a/lib/internal/bridge/characteristics_mixin.dart b/lib/internal/bridge/characteristics_mixin.dart index faf594db..535ef0da 100644 --- a/lib/internal/bridge/characteristics_mixin.dart +++ b/lib/internal/bridge/characteristics_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin CharacteristicsMixin on FlutterBLE { final Stream _characteristicsMonitoringEvents = diff --git a/lib/internal/bridge/descriptors_mixin.dart b/lib/internal/bridge/descriptors_mixin.dart new file mode 100644 index 00000000..e29218a0 --- /dev/null +++ b/lib/internal/bridge/descriptors_mixin.dart @@ -0,0 +1,203 @@ +part of _internal; + +mixin DescriptorsMixin on FlutterBLE { + Future readDescriptorForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.readDescriptorForDevice, + { + ArgumentName.deviceIdentifier: peripheral.identifier, + ArgumentName.serviceUuid: serviceUuid, + ArgumentName.characteristicUuid: characteristicUuid, + ArgumentName.descriptorUuid: descriptorUuid, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + Service service = + Service.fromJson(jsonObject, peripheral, _manager); + Characteristic characteristic = + Characteristic.fromJson(jsonObject, service, _manager); + return DescriptorWithValue.fromJson( + jsonObject, characteristic, _manager); + }); + + Future readDescriptorForService( + Service service, + String characteristicUuid, + String descriptorUuid, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.readDescriptorForService, + { + ArgumentName.serviceIdentifier: service._id, + ArgumentName.characteristicUuid: characteristicUuid, + ArgumentName.descriptorUuid: descriptorUuid, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + Characteristic characteristic = + Characteristic.fromJson(jsonObject, service, _manager); + return DescriptorWithValue.fromJson( + jsonObject, characteristic, _manager); + }); + + Future readDescriptorForCharacteristic( + Characteristic characteristic, + String descriptorUuid, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.readDescriptorForCharacteristic, + { + ArgumentName.characteristicIdentifier: characteristic._id, + ArgumentName.descriptorUuid: descriptorUuid, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + + return DescriptorWithValue.fromJson( + jsonObject, characteristic, _manager); + }); + + Future readDescriptorForIdentifier( + Descriptor descriptor, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.readDescriptorForIdentifier, + { + ArgumentName.descriptorIdentifier: descriptor._id, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + return DescriptorWithValue.fromJson( + jsonObject, descriptor.characteristic, _manager) + .value; + }); + + Future writeDescriptorForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + Uint8List value, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.writeDescriptorForDevice, + { + ArgumentName.deviceIdentifier: peripheral.identifier, + ArgumentName.serviceUuid: serviceUuid, + ArgumentName.characteristicUuid: characteristicUuid, + ArgumentName.descriptorUuid: descriptorUuid, + ArgumentName.value: value, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + Service service = + Service.fromJson(jsonObject, peripheral, _manager); + Characteristic characteristic = + Characteristic.fromJson(jsonObject, service, _manager); + return Descriptor.fromJson(jsonObject, characteristic, _manager); + }); + + Future writeDescriptorForService( + Service service, + String characteristicUuid, + String descriptorUuid, + Uint8List value, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.writeDescriptorForService, + { + ArgumentName.serviceIdentifier: service._id, + ArgumentName.characteristicUuid: characteristicUuid, + ArgumentName.descriptorUuid: descriptorUuid, + ArgumentName.value: value, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + Characteristic characteristic = + Characteristic.fromJson(jsonObject, service, _manager); + return Descriptor.fromJson(jsonObject, characteristic, _manager); + }); + + Future writeDescriptorForCharacteristic( + Characteristic characteristic, + String descriptorUuid, + Uint8List value, + String transactionId, + ) => + _methodChannel + .invokeMethod( + MethodName.writeDescriptorForCharacteristic, + { + ArgumentName.characteristicIdentifier: characteristic._id, + ArgumentName.descriptorUuid: descriptorUuid, + ArgumentName.value: value, + ArgumentName.transactionId: transactionId, + }, + ) + .catchError(_handleError) + .then((jsonResponse) { + Map jsonObject = jsonDecode(jsonResponse); + return Descriptor.fromJson(jsonObject, characteristic, _manager); + }); + + Future writeDescriptorForIdentifier( + Descriptor descriptor, + Uint8List value, + String transactionId, + ) => + _methodChannel.invokeMethod( + MethodName.writeDescriptorForIdentifier, + { + ArgumentName.descriptorIdentifier: descriptor._id, + ArgumentName.value: value, + ArgumentName.transactionId: transactionId, + }, + ).catchError(_handleError); + + Future _handleError( + Object error, [ + dynamic stacktrace, + ]) => + Future.error( + BleError.fromJson( + jsonDecode( + (error as PlatformException).details, + ), + ), + ); +} diff --git a/lib/internal/bridge/device_connection_mixin.dart b/lib/internal/bridge/device_connection_mixin.dart index 6b867492..55aa17b9 100644 --- a/lib/internal/bridge/device_connection_mixin.dart +++ b/lib/internal/bridge/device_connection_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin DeviceConnectionMixin on FlutterBLE { final Stream _peripheralConnectionStateChanges = diff --git a/lib/internal/bridge/device_rssi_mixin.dart b/lib/internal/bridge/device_rssi_mixin.dart index 4a698193..1673c33b 100644 --- a/lib/internal/bridge/device_rssi_mixin.dart +++ b/lib/internal/bridge/device_rssi_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin RssiMixin on FlutterBLE { Future rssi(Peripheral peripheral, String transactionId) async { diff --git a/lib/internal/bridge/devices_mixin.dart b/lib/internal/bridge/devices_mixin.dart index d6169d65..ca2895e8 100644 --- a/lib/internal/bridge/devices_mixin.dart +++ b/lib/internal/bridge/devices_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin DevicesMixin on FlutterBLE { Future> knownDevices( diff --git a/lib/internal/bridge/discovery_mixin.dart b/lib/internal/bridge/discovery_mixin.dart index 76c8d288..3feb110a 100644 --- a/lib/internal/bridge/discovery_mixin.dart +++ b/lib/internal/bridge/discovery_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin DiscoveryMixin on FlutterBLE { Future discoverAllServicesAndCharacteristics( @@ -69,4 +69,85 @@ mixin DiscoveryMixin on FlutterBLE { return Characteristic.fromJson(characteristicJson, service, _manager); }).toList(); } + + Future> descriptorsForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + ) async { + String jsonString = await _methodChannel + .invokeMethod(MethodName.descriptorsForDevice, { + ArgumentName.deviceIdentifier: peripheral.identifier, + ArgumentName.serviceUuid: serviceUuid, + ArgumentName.characteristicUuid: characteristicUuid, + }).catchError( + (errorJson) => Future.error( + BleError.fromJson(jsonDecode(errorJson.details)), + ), + ); + + Map jsonObject = jsonDecode(jsonString); + + Service service = Service.fromJson(jsonObject, peripheral, _manager); + Characteristic characteristic = + Characteristic.fromJson(jsonObject, service, _manager); + + List> jsonDescriptors = + (jsonObject["descriptors"] as List).cast(); + + return jsonDescriptors + .map((jsonDescriptor) => + Descriptor.fromJson(jsonDescriptor, characteristic, _manager)) + .toList(); + } + + Future> descriptorsForService( + Service service, + String characteristicUuid, + ) async { + String jsonString = await _methodChannel + .invokeMethod(MethodName.descriptorsForService, { + ArgumentName.serviceIdentifier: service._id, + ArgumentName.characteristicUuid: characteristicUuid, + }).catchError( + (errorJson) => Future.error( + BleError.fromJson(jsonDecode(errorJson.details)), + ), + ); + + Map jsonObject = jsonDecode(jsonString); + + Characteristic characteristic = + Characteristic.fromJson(jsonObject, service, _manager); + + List> jsonDescriptors = + (jsonObject["descriptors"] as List).cast(); + + return jsonDescriptors + .map((jsonDescriptor) => + Descriptor.fromJson(jsonDescriptor, characteristic, _manager)) + .toList(); + } + + Future> descriptorsForCharacteristic( + Characteristic characteristic, + ) async { + String jsonString = await _methodChannel.invokeMethod( + MethodName.descriptorsForCharacteristic, { + ArgumentName.characteristicIdentifier: characteristic._id, + }).catchError( + (errorJson) => Future.error( + BleError.fromJson(jsonDecode(errorJson.details)), + ), + ); + + Map json = jsonDecode(jsonString); + + List> jsonDescriptors = + (json["descriptors"] as List).cast(); + return jsonDescriptors + .map((jsonDescriptor) => + Descriptor.fromJson(jsonDescriptor, characteristic, _manager)) + .toList(); + } } diff --git a/lib/internal/bridge/lib_core.dart b/lib/internal/bridge/lib_core.dart index 2adebed2..8589f1de 100644 --- a/lib/internal/bridge/lib_core.dart +++ b/lib/internal/bridge/lib_core.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; abstract class FlutterBLE { InternalBleManager _manager; @@ -23,7 +23,8 @@ class FlutterBleLib extends FlutterBLE MtuMixin, BluetoothStateMixin, DevicesMixin, - CharacteristicsMixin { + CharacteristicsMixin, + DescriptorsMixin { final Stream _restoreStateEvents = const EventChannel(ChannelName.stateRestoreEvents) .receiveBroadcastStream(); diff --git a/lib/internal/bridge/log_level_mixin.dart b/lib/internal/bridge/log_level_mixin.dart index 2ae40cc0..fb8056d5 100644 --- a/lib/internal/bridge/log_level_mixin.dart +++ b/lib/internal/bridge/log_level_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin LogLevelMixin on FlutterBLE { Future setLogLevel(LogLevel logLevel) async { diff --git a/lib/internal/bridge/mtu_mixin.dart b/lib/internal/bridge/mtu_mixin.dart index 3ca69f36..b5948913 100644 --- a/lib/internal/bridge/mtu_mixin.dart +++ b/lib/internal/bridge/mtu_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin MtuMixin on FlutterBLE { Future requestMtu( diff --git a/lib/internal/bridge/scanning_mixin.dart b/lib/internal/bridge/scanning_mixin.dart index 17725de9..9b099f1c 100644 --- a/lib/internal/bridge/scanning_mixin.dart +++ b/lib/internal/bridge/scanning_mixin.dart @@ -1,4 +1,4 @@ -part of internal_bridge_lib; +part of _internal; mixin ScanningMixin on FlutterBLE { Stream _scanEvents; diff --git a/lib/internal/constants.dart b/lib/internal/constants.dart index 77fdc5e8..18e53266 100644 --- a/lib/internal/constants.dart +++ b/lib/internal/constants.dart @@ -22,6 +22,10 @@ abstract class MethodName { static const String services = "services"; static const String characteristics = "characteristics"; static const String characteristicsForService = "characteristicsForService"; + static const String descriptorsForDevice = "descriptorsForDevice"; + static const String descriptorsForService = "descriptorsForService"; + static const String descriptorsForCharacteristic = + "descriptorsForCharacteristic"; static const String setLogLevel = "setLogLevel"; static const String logLevel = "logLevel"; @@ -50,6 +54,20 @@ abstract class MethodName { static const String monitorCharacteristicForService = "monitorCharacteristicForService"; + static const String readDescriptorForDevice = "readDescriptorForDevice"; + static const String readDescriptorForService = "readDescriptorForService"; + static const String readDescriptorForCharacteristic = + "readDescriptorForCharacteristic"; + static const String readDescriptorForIdentifier = + "readDescriptorForIdentifier"; + + static const String writeDescriptorForDevice = "writeDescriptorForDevice"; + static const String writeDescriptorForService = "writeDescriptorForService"; + static const String writeDescriptorForCharacteristic = + "writeDescriptorForCharacteristic"; + static const String writeDescriptorForIdentifier = + "writeDescriptorForIdentifier"; + static const String connectedDevices = "getConnectedDevices"; static const String knownDevices = "getKnownDevices"; } @@ -86,6 +104,8 @@ abstract class ArgumentName { static const String serviceIdentifier = "serviceId"; static const String characteristicUuid = "characteristicUuid"; static const String characteristicIdentifier = "characteristicIdentifier"; + static const String descriptorUuid = "descriptorUuid"; + static const String descriptorIdentifier = "descriptorIdentifier"; static const String value = "value"; static const String withResponse = "withResponse"; diff --git a/lib/internal/internal_ble_manager.dart b/lib/internal/internal_ble_manager.dart index f13ae480..42814da6 100644 --- a/lib/internal/internal_ble_manager.dart +++ b/lib/internal/internal_ble_manager.dart @@ -1,11 +1,12 @@ -part of internal_bridge_lib; +part of _internal; class InternalBleManager implements BleManager, ManagerForPeripheral, ManagerForService, - ManagerForCharacteristic { + ManagerForCharacteristic, + ManagerForDescriptor { FlutterBleLib _bleLib; InternalBleManager() { @@ -129,6 +130,27 @@ class InternalBleManager Future> services(Peripheral peripheral) => _bleLib.services(peripheral); + @override + Future> descriptorsForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + ) => + _bleLib.descriptorsForPeripheral( + peripheral, serviceUuid, characteristicUuid); + + @override + Future> descriptorsForService( + Service service, + String characteristicUuid, + ) => + _bleLib.descriptorsForService(service, characteristicUuid); + + @override + Future> descriptorsForCharacteristic( + Characteristic characteristic) => + _bleLib.descriptorsForCharacteristic(characteristic); + @override Future discoverAllServicesAndCharacteristics( Peripheral peripheral, @@ -289,4 +311,116 @@ class InternalBleManager characteristic._id, transactionId, ); + + @override + Future writeDescriptorForIdentifier( + Descriptor descriptor, + Uint8List value, + String transactionId, + ) => + _bleLib.writeDescriptorForIdentifier( + descriptor, + value, + transactionId, + ); + + @override + Future writeDescriptorForCharacteristic( + Characteristic characteristic, + String descriptorUuid, + Uint8List value, + String transactionId, + ) => + _bleLib.writeDescriptorForCharacteristic( + characteristic, + descriptorUuid, + value, + transactionId, + ); + + @override + Future writeDescriptorForService( + Service service, + String characteristicUuid, + String descriptorUuid, + Uint8List value, + String transactionId, + ) => + _bleLib.writeDescriptorForService( + service, + characteristicUuid, + descriptorUuid, + value, + transactionId, + ); + + @override + Future writeDescriptorForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + Uint8List value, + String transactionId, + ) => + _bleLib.writeDescriptorForPeripheral( + peripheral, + serviceUuid, + characteristicUuid, + descriptorUuid, + value, + transactionId, + ); + + @override + Future readDescriptorForIdentifier( + Descriptor descriptor, + String transactionId, + ) => + _bleLib.readDescriptorForIdentifier( + descriptor, + transactionId, + ); + + @override + Future readDescriptorForCharacteristic( + Characteristic characteristic, + String descriptorUuid, + String transactionId, + ) => + _bleLib.readDescriptorForCharacteristic( + characteristic, + descriptorUuid, + transactionId, + ); + + @override + Future readDescriptorForService( + Service service, + String characteristicUuid, + String descriptorUuid, + String transactionId, + ) => + _bleLib.readDescriptorForService( + service, + characteristicUuid, + descriptorUuid, + transactionId, + ); + + @override + Future readDescriptorForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + String transactionId, + ) => + _bleLib.readDescriptorForPeripheral( + peripheral, + serviceUuid, + characteristicUuid, + descriptorUuid, + transactionId, + ); } diff --git a/lib/internal/managers_for_classes.dart b/lib/internal/managers_for_classes.dart index 9694d3fc..43647b47 100644 --- a/lib/internal/managers_for_classes.dart +++ b/lib/internal/managers_for_classes.dart @@ -1,11 +1,16 @@ import 'dart:typed_data'; import 'package:flutter_ble_lib/flutter_ble_lib.dart'; -import 'package:flutter_ble_lib/internal/bridge/internal_bridge_lib.dart'; +import 'package:flutter_ble_lib/internal/_internal.dart'; abstract class ManagerForPeripheral { - Future connectToPeripheral(String peripheralIdentifier, - {bool isAutoConnect, int requestMtu, bool refreshGatt, Duration timeout}); + Future connectToPeripheral( + String peripheralIdentifier, { + bool isAutoConnect, + int requestMtu, + bool refreshGatt, + Duration timeout, + }); Future isPeripheralConnected(String peripheralIdentifier); @@ -13,9 +18,10 @@ abstract class ManagerForPeripheral { String peripheralIdentifier); Stream observePeripheralConnectionState( - String peripheralIdentifier, - bool emitCurrentValue, - bool completeOnDisconnect); + String peripheralIdentifier, + bool emitCurrentValue, + bool completeOnDisconnect, + ); Future discoverAllServicesAndCharacteristics( Peripheral peripheral, String transactionId); @@ -23,11 +29,20 @@ abstract class ManagerForPeripheral { Future> services(Peripheral peripheral); Future> characteristics( - Peripheral peripheral, String serviceUuid); + Peripheral peripheral, + String serviceUuid, + ); - Future rssi(Peripheral peripheral, String transactionId); + Future rssi( + Peripheral peripheral, + String transactionId, + ); - Future requestMtu(Peripheral peripheral, int mtu, String transactionId); + Future requestMtu( + Peripheral peripheral, + int mtu, + String transactionId, + ); Future readCharacteristicForDevice( Peripheral peripheral, @@ -50,6 +65,29 @@ abstract class ManagerForPeripheral { String characteristicUUID, String transactionId, ); + + Future> descriptorsForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + ); + + Future readDescriptorForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + String transactionId, + ); + + Future writeDescriptorForPeripheral( + Peripheral peripheral, + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + Uint8List bytes, + String transactionId, + ); } abstract class ManagerForService { @@ -77,6 +115,26 @@ abstract class ManagerForService { String characteristicUUID, String transactionId, ); + + Future> descriptorsForService( + Service service, + String characteristicUuid, + ); + + Future readDescriptorForService( + Service service, + String characteristicUuid, + String descriptorUuid, + String transactionId, + ); + + Future writeDescriptorForService( + Service service, + String characteristicUuid, + String descriptorUuid, + Uint8List bytes, + String transactionId, + ); } abstract class ManagerForCharacteristic { @@ -99,4 +157,34 @@ abstract class ManagerForCharacteristic { InternalCharacteristic characteristic, String transactionId, ); + + Future> descriptorsForCharacteristic( + Characteristic characteristic, + ); + + Future readDescriptorForCharacteristic( + Characteristic characteristic, + String descriptorUuid, + String transactionId, + ); + + Future writeDescriptorForCharacteristic( + Characteristic characteristic, + String descriptorUuid, + Uint8List value, + String transactionId, + ); +} + +abstract class ManagerForDescriptor { + Future readDescriptorForIdentifier( + Descriptor descriptor, + String transactionId, + ); + + Future writeDescriptorForIdentifier( + Descriptor descriptor, + Uint8List bytes, + String transactionId, + ); } diff --git a/lib/peripheral.dart b/lib/peripheral.dart index 5930a585..8c7dbafe 100644 --- a/lib/peripheral.dart +++ b/lib/peripheral.dart @@ -82,6 +82,42 @@ class Peripheral { transactionId ?? TransactionIdGenerator.getNextId(), ); + Future> descriptorsForCharacteristic( + String serviceUuid, + String characteristicUuid, + ) => + _manager.descriptorsForPeripheral(this, serviceUuid, characteristicUuid); + + Future readDescriptor( + String serviceUuid, + String characteristicUuid, + String descriptorUuid, { + String transactionId, + }) => + _manager.readDescriptorForPeripheral( + this, + serviceUuid, + characteristicUuid, + descriptorUuid, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + + Future writeDescriptor( + String serviceUuid, + String characteristicUuid, + String descriptorUuid, + Uint8List value, { + String transactionId, + }) => + _manager.writeDescriptorForPeripheral( + this, + serviceUuid, + characteristicUuid, + descriptorUuid, + value, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + Stream monitorCharacteristic( String serviceUUID, String characteristicUUID, { diff --git a/lib/scan_result.dart b/lib/scan_result.dart index 5b5a84f2..a203fb84 100644 --- a/lib/scan_result.dart +++ b/lib/scan_result.dart @@ -19,8 +19,8 @@ class ScanResult { Peripheral peripheral; int rssi; int mtu; - bool isConnectable; - List overflowServiceUUIDs; + bool isConnectable; //iOS only + List overflowServiceUUIDs; //iOS only AdvertisementData advertisementData; ScanResult.fromJson(Map json, ManagerForPeripheral manager) diff --git a/lib/service.dart b/lib/service.dart index cdd96dc3..d8403760 100644 --- a/lib/service.dart +++ b/lib/service.dart @@ -37,8 +37,10 @@ class Service extends InternalService { withResponse, transactionId ?? TransactionIdGenerator.getNextId()); - Future readCharacteristic(String characteristicUUID, - {String transactionId}) => + Future readCharacteristic( + String characteristicUUID, { + String transactionId, + }) => _manager.readCharacteristicForService( peripheral, this, @@ -57,6 +59,40 @@ class Service extends InternalService { transactionId ?? TransactionIdGenerator.getNextId(), ); + Future> descriptorsForCharacteristic( + String characteristicUuid, + ) => + _manager.descriptorsForService( + this, + characteristicUuid, + ); + + Future readDescriptor( + String characteristicUuid, + String descriptorUuid, { + String transactionId, + }) => + _manager.readDescriptorForService( + this, + characteristicUuid, + descriptorUuid, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + + Future writeDescriptor( + String characteristicUuid, + String descriptorUuid, + Uint8List value, { + String transactionId, + }) => + _manager.writeDescriptorForService( + this, + characteristicUuid, + descriptorUuid, + value, + transactionId ?? TransactionIdGenerator.getNextId(), + ); + @override bool operator ==(Object other) => identical(this, other) || diff --git a/pubspec.yaml b/pubspec.yaml index 14312361..1fea12bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_ble_lib description: FlutterBle Library is a flutter library that supports BLE operations. It uses MultiPlatformBleAdapter as a native backend.. -version: 2.1.0 +version: 2.2.0 author: "Polidea " homepage: https://github.com/Polidea/FlutterBleLib @@ -12,6 +12,7 @@ dependencies: async: ^2.2.0 flutter: sdk: flutter + permission_handler: ^4.2.0+hotfix.3 dev_dependencies: test: ^1.5.3 @@ -32,7 +33,6 @@ flutter: plugin: androidPackage: com.polidea.flutter_ble_lib pluginClass: FlutterBleLibPlugin - # To add assets to your plugin package, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg @@ -43,7 +43,6 @@ flutter: # # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. - # To add custom fonts to your plugin package, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a diff --git a/test/flutter_ble_lib_test.dart b/test/flutter_ble_lib_test.dart deleted file mode 100644 index cc551e24..00000000 --- a/test/flutter_ble_lib_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_ble_lib/flutter_ble_lib.dart'; - -void main() { - const MethodChannel channel = MethodChannel('flutter_ble_lib'); - - setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return '42'; - }); - }); - - tearDown(() { - channel.setMockMethodCallHandler(null); - }); -} diff --git a/test/internal/bridge/lib_core_test.dart b/test/internal/bridge/lib_core_test.dart index 25cfcbf3..a7d81e99 100644 --- a/test/internal/bridge/lib_core_test.dart +++ b/test/internal/bridge/lib_core_test.dart @@ -5,7 +5,7 @@ import 'dart:typed_data'; import 'package:flutter/services.dart'; import 'package:flutter_ble_lib/flutter_ble_lib.dart'; -import 'package:flutter_ble_lib/internal/bridge/internal_bridge_lib.dart'; +import 'package:flutter_ble_lib/internal/_internal.dart'; import 'package:flutter_ble_lib/internal/constants.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; @@ -33,20 +33,20 @@ void main() { }); Future emitPlatformError(String errorJson) => - defaultBinaryMessenger.handlePlatformMessage( + ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( monitorCharacteristicEventChannelName, const StandardMethodCodec() .encodeErrorEnvelope(code: "irrelevant", details: errorJson), (ByteData data) {}); Future emitMonitoringEvent(String eventJson) => - defaultBinaryMessenger.handlePlatformMessage( + ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( monitorCharacteristicEventChannelName, const StandardMethodCodec().encodeSuccessEnvelope(eventJson), (ByteData data) {}); Future emitStreamCompletion() => - defaultBinaryMessenger.handlePlatformMessage( + ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( monitorCharacteristicEventChannelName, null, (ByteData data) {}, @@ -267,7 +267,7 @@ void main() { bleLib.monitorCharacteristicForIdentifier(peripheral, 1, "1"); StreamSubscription subscription = monitoringStream.listen((_) {}); - StreamSubscription subscription1 = monitoringStream.listen((_) {}); + monitoringStream.listen((_) {}); int calledCount = 0; methodChannel.setMockMethodCallHandler((call) {