diff --git a/REFERENCE.md b/REFERENCE.md index e6e9429a..e9b14bd0 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -142,9 +142,12 @@ All of the following methods belong to Peripheral instance. ```dart Future connect( {bool isAutoConnect = false, - int requestMtu, + int requestMtu = NO_MTU_NEGOTIATION, bool refreshGatt = false, - Duration timeout}); + Duration timeout, + bool isNotifyOnConnection = false, + bool isNotifyOnDisconnection = false, + bool isNotifyOnNotification = false}); ``` Attempts to connect to the peripheral. diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id new file mode 100644 index 00000000..d7b781ad --- /dev/null +++ b/example/ios/Flutter/.last_build_id @@ -0,0 +1 @@ +7fc9c9500a628906af1c5baf9385035d \ No newline at end of file diff --git a/example/ios/Podfile b/example/ios/Podfile index b30a428b..8e0967df 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -62,7 +62,7 @@ target 'Runner' do end # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' + pod 'Flutter', :path => 'Flutter' # Plugin Pods diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a6a5adb4..79fd3818 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -4,7 +4,7 @@ PODS: - Flutter - MultiplatformBleAdapter (= 0.1.5) - MultiplatformBleAdapter (0.1.5) - - "permission_handler (4.2.0+hotfix.3)": + - "permission_handler (4.4.0+hotfix.4)": - Flutter DEPENDENCIES: @@ -28,8 +28,8 @@ SPEC CHECKSUMS: Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_ble_lib: 20e79f0b1d78d921d9ed68ab4451e190029bc3d9 MultiplatformBleAdapter: 3c4391d428382738a47662ae1f665a29ce78ff39 - permission_handler: 40520ab8ad1bb78a282b832464e995ec87f77ec6 + permission_handler: 8278954f2382902f63f00dd8828769c0bd6d511b -PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 +PODFILE CHECKSUM: 84720d6720b1cd5ac49da90536aac58b9f839038 -COCOAPODS: 1.8.4 +COCOAPODS: 1.9.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index f32ba7b6..dec8f0df 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,11 +10,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1F98025F8F407F461CB357DF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E99B52135973B0C19BFDEF7 /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 81E1240A2334F85D005D9563 /* SwiftBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81E124092334F85D005D9563 /* SwiftBridging.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; @@ -30,8 +26,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -45,7 +39,6 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 1AB7F698716680F75BACA8D9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -54,7 +47,6 @@ 96C714B17D5919D3696FE535 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -68,8 +60,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 1F98025F8F407F461CB357DF /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -80,9 +70,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -260,7 +248,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -336,7 +324,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -416,7 +403,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -472,7 +458,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/example/lib/device_details/device_details_bloc.dart b/example/lib/device_details/device_details_bloc.dart index 693de732..341ced19 100644 --- a/example/lib/device_details/device_details_bloc.dart +++ b/example/lib/device_details/device_details_bloc.dart @@ -224,7 +224,7 @@ class DeviceDetailsBloc { try { log("Connecting to ${peripheral.name}"); - await peripheral.connect(); + await peripheral.connect(isAutoConnect: true, isNotifyOnConnection: true, isNotifyOnDisconnection: true, isNotifyOnNotification: true,); log("Connected!"); } on BleError catch (e) { logError(e.toString()); diff --git a/ios/Classes/Constants/ArgumentKey.h b/ios/Classes/Constants/ArgumentKey.h index 56981d17..a34bcb87 100644 --- a/ios/Classes/Constants/ArgumentKey.h +++ b/ios/Classes/Constants/ArgumentKey.h @@ -22,6 +22,10 @@ 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_NOTIFY_ON_NOTIFICATION; +extern NSString * const ARGUMENT_KEY_NOTIFY_ON_DISCONNECTION; +extern NSString * const ARGUMENT_KEY_NOTIFY_ON_CONNECTION; + extern NSString * const ARGUMENT_KEY_DESCRIPTOR_UUID; extern NSString * const ARGUMENT_KEY_DESCRIPTOR_IDENTIFIER; diff --git a/ios/Classes/Constants/ArgumentKey.m b/ios/Classes/Constants/ArgumentKey.m index 590a4df8..e4615404 100644 --- a/ios/Classes/Constants/ArgumentKey.m +++ b/ios/Classes/Constants/ArgumentKey.m @@ -13,6 +13,13 @@ NSString * const ARGUMENT_KEY_TIMEOUT_MILLIS = @"timeoutMillis"; NSString * const ARGUMENT_KEY_EMIT_CURRENT_VALUE = @"emitCurrentValue"; +NSString * const ARGUMENT_KEY_NOTIFY_ON_NOTIFICATION = @"notifyOnNotification"; +NSString * const ARGUMENT_KEY_NOTIFY_ON_DISCONNECTION = @"notifyOnDisconnection"; +NSString * const ARGUMENT_KEY_NOTIFY_ON_CONNECTION = @"notifyOnConnection"; +NSString * const ARGUMENT_KEY_ENABLE_TRANSPORT_BRIDGING = @"enableTransportBridging"; +NSString * const ARGUMENT_KEY_REQUIRES_ANCS = @"requiresANCS"; +NSString * const ARGUMENT_KEY_START_DELAY = @"startDelay"; + NSString * const ARGUMENT_KEY_LOG_LEVEL = @"logLevel"; NSString * const ARGUMENT_KEY_SERVICE_UUID = @"serviceUuid"; diff --git a/ios/Classes/FlutterBleLibPlugin.m b/ios/Classes/FlutterBleLibPlugin.m index 07e26441..b8e51e8c 100644 --- a/ios/Classes/FlutterBleLibPlugin.m +++ b/ios/Classes/FlutterBleLibPlugin.m @@ -209,11 +209,13 @@ - (void)stopDeviceScan:(FlutterResult)result { // MARK: - MBA Methods - Connection - (void)connectToDevice:(FlutterMethodCall *)call result:(FlutterResult)result { - NSArray* expectedArguments = [NSArray arrayWithObjects:ARGUMENT_KEY_TIMEOUT_MILLIS, nil]; + NSArray* expectedArguments = [NSArray arrayWithObjects:ARGUMENT_KEY_TIMEOUT_MILLIS, ARGUMENT_KEY_NOTIFY_ON_NOTIFICATION, ARGUMENT_KEY_NOTIFY_ON_DISCONNECTION, ARGUMENT_KEY_NOTIFY_ON_CONNECTION, nil]; + NSDictionary* options = [ArgumentHandler dictionaryOrNil:expectedArguments in:call.arguments]; + [_adapter connectToDevice:call.arguments[ARGUMENT_KEY_DEVICE_IDENTIFIER] - options:[ArgumentHandler dictionaryOrNil:expectedArguments in:call.arguments] + options:options resolve:result - reject:[self rejectForFlutterResult:result]]; + reject:[self rejectForFlutterResult:result]]; } - (void)cancelDeviceConnection:(FlutterMethodCall *)call result:(FlutterResult)result { diff --git a/lib/peripheral.dart b/lib/peripheral.dart index c8298878..807295dd 100644 --- a/lib/peripheral.dart +++ b/lib/peripheral.dart @@ -48,16 +48,45 @@ class Peripheral { /// is established right after timeout event, peripheral will be disconnected /// immediately. Timeout may happen earlier then specified due to OS /// specific behavior. + /// + /// Optional params [isNotifyOnConnection], [isNotifyOnDisconnection], [isNotifyOnNotification] + /// is used for automatically notify app when this device connected/disconnected + /// or send notification about change its state (IOS only) + /// is used in background mode + /// + /// Optional [enableTransportBridging] is indicating that the system will bring up classic + /// transport profiles when low energy transport for peripheral is connected (iOS 13.0 or more only) + /// + /// Optional [isRequiresANCS] is indicating that the ANCS (Apple Notification Center Service) + /// is required for the peripheral is connected. (iOS 13.0 or more only) + /// + /// Optional [startDelay] is indicating the number of seconds + /// for the system to wait before starting a connection. (iOS only) + /// + /// Future connect( {bool isAutoConnect = false, int requestMtu = NO_MTU_NEGOTIATION, bool refreshGatt = false, - Duration timeout}) => + Duration timeout, + bool isNotifyOnConnection = false, + bool isNotifyOnDisconnection = false, + bool isNotifyOnNotification = false, + bool enableTransportBridging = false, + bool isRequiresANCS = false, + Duration startDelay}) => _manager.connectToPeripheral(identifier, isAutoConnect: isAutoConnect, requestMtu: requestMtu, refreshGatt: refreshGatt, - timeout: timeout); + timeout: timeout, + isNotifyOnConnection: isNotifyOnConnection, + isNotifyOnDisconnection: isNotifyOnDisconnection, + isNotifyOnNotification: isNotifyOnNotification, + enableTransportBridging: enableTransportBridging, + isRequiresANCS: isRequiresANCS, + startDelay: startDelay + ); /// Returns a stream of [PeripheralConnectionState]. /// diff --git a/lib/src/_constants.dart b/lib/src/_constants.dart index 18e53266..fd5aae0a 100644 --- a/lib/src/_constants.dart +++ b/lib/src/_constants.dart @@ -115,6 +115,13 @@ abstract class ArgumentName { static const String mtu = "mtu"; static const String deviceIdentifiers = "deviceIdentifiers"; + + static const String notifyOnNotification = "notifyOnNotification"; + static const String notifyOnDisconnection = "notifyOnDisconnection"; + static const String notifyOnConnection = "notifyOnConnection"; + static const String enableTransportBridging = "enableTransportBridging"; + static const String requiresANCS = "requiresANCS"; + static const String startDelay = "startDelay"; } abstract class NativeConnectionState { diff --git a/lib/src/_managers_for_classes.dart b/lib/src/_managers_for_classes.dart index 69a92814..4eb695ae 100644 --- a/lib/src/_managers_for_classes.dart +++ b/lib/src/_managers_for_classes.dart @@ -11,6 +11,12 @@ abstract class ManagerForPeripheral { int requestMtu, bool refreshGatt, Duration timeout, + bool isNotifyOnConnection, + bool isNotifyOnDisconnection, + bool isNotifyOnNotification, + bool enableTransportBridging, + bool isRequiresANCS, + Duration startDelay }); Future isPeripheralConnected(String peripheralIdentifier); diff --git a/lib/src/bridge/device_connection_mixin.dart b/lib/src/bridge/device_connection_mixin.dart index 55aa17b9..2398d80d 100644 --- a/lib/src/bridge/device_connection_mixin.dart +++ b/lib/src/bridge/device_connection_mixin.dart @@ -5,15 +5,31 @@ mixin DeviceConnectionMixin on FlutterBLE { const EventChannel(ChannelName.connectionStateChangeEvents) .receiveBroadcastStream(); - Future connectToPeripheral(String deviceIdentifier, bool isAutoConnect, - int requestMtu, bool refreshGatt, Duration timeout) async { + Future connectToPeripheral({String deviceIdentifier, + bool isAutoConnect, + int requestMtu, + bool refreshGatt, + Duration timeout, + bool isNotifyOnConnection, + bool isNotifyOnDisconnection, + bool isNotifyOnNotification, + bool enableTransportBridging, + bool isRequiresANCS, + Duration startDelay +}) async { return await _methodChannel .invokeMethod(MethodName.connectToDevice, { ArgumentName.deviceIdentifier: deviceIdentifier, ArgumentName.isAutoConnect: isAutoConnect, ArgumentName.requestMtu: requestMtu, ArgumentName.refreshGatt: refreshGatt, - ArgumentName.timeoutMillis: timeout?.inMilliseconds + ArgumentName.timeoutMillis: timeout?.inMilliseconds, + ArgumentName.notifyOnConnection: isNotifyOnConnection, + ArgumentName.notifyOnDisconnection: isNotifyOnDisconnection, + ArgumentName.notifyOnNotification: isNotifyOnNotification, + ArgumentName.enableTransportBridging: enableTransportBridging, + ArgumentName.requiresANCS: isRequiresANCS, + ArgumentName.startDelay: startDelay?.inSeconds }).catchError((errorJson) => Future.error(BleError.fromJson(jsonDecode(errorJson.details)))); } diff --git a/lib/src/internal_ble_manager.dart b/lib/src/internal_ble_manager.dart index 5234e89c..1bea4fe7 100644 --- a/lib/src/internal_ble_manager.dart +++ b/lib/src/internal_ble_manager.dart @@ -69,9 +69,23 @@ class InternalBleManager int requestMtu, bool refreshGatt, Duration timeout, - }) async => - _bleLib.connectToPeripheral( - identifier, isAutoConnect, requestMtu, refreshGatt, timeout); + bool isNotifyOnConnection, + bool isNotifyOnDisconnection, + bool isNotifyOnNotification, + bool enableTransportBridging, + bool isRequiresANCS, + Duration startDelay + }) async => _bleLib.connectToPeripheral( + deviceIdentifier: identifier, + isAutoConnect: isAutoConnect, + requestMtu: requestMtu, + refreshGatt: refreshGatt, + isNotifyOnConnection: isNotifyOnConnection, + isNotifyOnDisconnection: isNotifyOnDisconnection, + isNotifyOnNotification: isNotifyOnNotification, + isRequiresANCS: isRequiresANCS, + startDelay: startDelay + ); @override Stream observePeripheralConnectionState(