diff --git a/CHANGELOG.md b/CHANGELOG.md index f5914da..e8625b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,25 @@ This file documents the changes between different build versions of the `flic2lib.framework` +## flic2lib-ios 1.1.0 + +### Significant Changes + +* The framework is now distributed using the new XCFramework packaging format. This means that instead of a single `flic2lib.framework` file, you will need to use a `flic2lib.xcframework` bundle. This bundle is essentially a folder containing framework builds for all supported architectures. The main benefit of this is that the framework will from now on run in the iOS Simulator, by default, with no configuration needed. + + This change switch was necessary due to the fact that Xcode 11.4 now throws a compiler error if any embedded framework is not build for Simulator. This would only generate a warning in previous versions. Thus the previously provided simulator files would no longer work without the use of cumbersome build scripts. + + Xcode 11 is required in order to use XCFramework bundles. + +### Minor Changes + +* New property, `latencyMode`, added. This property can be set using the new `FLICLatencyMode` enums. The purpose of this is to allow you to reduce the click latency on events that occur while the Flic is connected. This may be useful if you are developing a foreground application, such as a game, where a lower latency is needed. However, keep in mind that this will affect expected battery life. + ## flic2lib-ios 1.0.5 ### Significant Changes -* Adjustments made to the framework in order to support API changes made in iOS 13.4. Older versions of the framework will still work on iOS 13.4, but we do recommend updating to this version. If you do not update the framework then there is a risk that the button connection will not be re-set properly if connection is lost during the Bluetooth LE encryption exchange/setup process. +* Adjustments made to the framework in order to support Core Bluetooth API changes indtroduced in iOS 13.4. Older versions of this framework will still work on iOS 13.4, but we do recommend updating. If you do not update the framework then there is a risk that the button connection will not be re-set properly if connection is lost during the Bluetooth LE encryption exchange/setup process. This is particularily important for applications that uses long-term execution in the background. ### Minor Changes diff --git a/README.md b/README.md index f432928..5d16605 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,6 @@ Have a look at the repository Wiki for further information: The API documentation of the flic2lib.framework. -* [Simulator Support](https://github.com/50ButtonsEach/flic2lib-ios/wiki/Simulator-Support) - - If needed, follow this tutorial on how to run flic2lib in the iOS Simulator. - * [OS Version Compatibility](https://github.com/50ButtonsEach/flic2lib-ios/wiki/OS-Compatibility) Deployment information. diff --git a/flic2lib.framework/flic2lib b/flic2lib.framework/flic2lib deleted file mode 100755 index 00d860e..0000000 Binary files a/flic2lib.framework/flic2lib and /dev/null differ diff --git a/flic2lib.xcframework/Info.plist b/flic2lib.xcframework/Info.plist new file mode 100644 index 0000000..64b5ad8 --- /dev/null +++ b/flic2lib.xcframework/Info.plist @@ -0,0 +1,41 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-armv7_arm64 + LibraryPath + flic2lib.framework + SupportedArchitectures + + armv7 + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-i386_x86_64-simulator + LibraryPath + flic2lib.framework + SupportedArchitectures + + i386 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/flic2lib.framework/Headers/FLICButton.h b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICButton.h similarity index 96% rename from flic2lib.framework/Headers/FLICButton.h rename to flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICButton.h index 31cb4c7..9cc61e3 100644 --- a/flic2lib.framework/Headers/FLICButton.h +++ b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICButton.h @@ -148,6 +148,16 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, readonly) BOOL isUnpaired; +/*! + * @property latencyMode + * + * @discussion Lets you switch between two different latency modes. For most use-cases it is recommend to keep the default FLICLatencyModeNormal. + * FLICLatencyModeLow should ideally only be used for foreground applications, such as games, where low latency is needed. Keep in mind that the + * energy consumption will be significantly higher in the low latency mode. + * + */ +@property(nonatomic, readwrite) FLICLatencyMode latencyMode; + /*! * @method connect * diff --git a/flic2lib.framework/Headers/FLICEnums.h b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICEnums.h similarity index 94% rename from flic2lib.framework/Headers/FLICEnums.h rename to flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICEnums.h index 751ca2e..48bc8bb 100644 --- a/flic2lib.framework/Headers/FLICEnums.h +++ b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICEnums.h @@ -293,4 +293,23 @@ typedef NS_ENUM(NSInteger, FLICButtonTriggerMode) FLICButtonTriggerModeClick, }; +/*! + * @enum FLICButtonTriggerMode + * + * @discussion The different latency modes that you can configure the Flic button to use. + * + */ +typedef NS_ENUM(NSInteger, FLICLatencyMode) +{ + /** + * This is the default mode of the button. It will give you a good compromise between click latency (less than 105 ms while connected) and current consumption. + */ + FLICLatencyModeNormal = 0, + /** + * Using this mode will give your button the lowest possible click latency (typicaly less than 30 ms while connected). + * This mode will significantly increase the current consumption. + */ + FLICLatencyModeLow, +}; + #endif /* FLICEnums_h */ diff --git a/flic2lib.framework/Headers/FLICManager.h b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICManager.h similarity index 100% rename from flic2lib.framework/Headers/FLICManager.h rename to flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/FLICManager.h diff --git a/flic2lib.framework/Headers/flic2lib.h b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/flic2lib.h similarity index 100% rename from flic2lib.framework/Headers/flic2lib.h rename to flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Headers/flic2lib.h diff --git a/flic2lib.framework/Info.plist b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Info.plist similarity index 82% rename from flic2lib.framework/Info.plist rename to flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Info.plist index 8c43501..b4e2542 100644 Binary files a/flic2lib.framework/Info.plist and b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Info.plist differ diff --git a/flic2lib.framework/Modules/module.modulemap b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Modules/module.modulemap similarity index 100% rename from flic2lib.framework/Modules/module.modulemap rename to flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/Modules/module.modulemap diff --git a/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/flic2lib b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/flic2lib new file mode 100755 index 0000000..db8fe66 Binary files /dev/null and b/flic2lib.xcframework/ios-armv7_arm64/flic2lib.framework/flic2lib differ diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICButton.h b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICButton.h new file mode 100644 index 0000000..9cc61e3 --- /dev/null +++ b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICButton.h @@ -0,0 +1,335 @@ +// +// FLICButton.h +// flic2lib +// +// Created by Anton Meier on 2019-04-11. +// Copyright © 2020 Shortcut Labs. All rights reserved. +// + +#import +#import "FLICEnums.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol FLICButtonDelegate; + +/*! + * @class FLICButton + * + * @discussion An instance of this class represents a physical Flic. + * + */ +@interface FLICButton : NSObject + +/*! + * @property identifier + * + * @discussion This identifier is guaranteed to be the same for each Flic paired to a particular iOS device. Thus it can be used to identify a Flic within an app. + * However, If you need to identify Flics cross different apps on different iOS devices, then you should have look at the either uuid, serialNumber, or bluetoothAddress. + * + */ +@property(readonly, nonatomic, strong, nonnull) NSUUID *identifier; + +/*! + * @property delegate + * + * @discussion The delegate that will receive events related to this particular Flic. + * You can either set this delegate manually for each button, or let the manager do so automatically using the buttonDelegate as default. + * + */ +@property(weak, nonatomic, nullable) id delegate; + +/*! + * @property name + * + * @discussion The bluetooth advertisement name of the Flic. This will be the same name that is shown by iOS it its bluetooth settings. + * + */ +@property(nonatomic, readonly, strong, nullable) NSString *name; + +/*! + * @property nickname + * + * @discussion With this property you can read out the display name that the user may change in for example the Flic app. This value can also be changed from third party apps + * integrating this framework (including your app). The purpose of this is to provide more human readable name that the user can use to identify its Flic's across apps. + * For example "Kitchen Flic" or "Bedroom Lights". The nickname has a maximum length limit of 23 bytes. Keep in mind that this is the length in bytes, and not the + * number of UTF8 characters (which may be up to 4 bytes long). If you write anything longer than 23 bytes then the nickname will automatically be truncated to at + * most 23 bytes. When truncating the string, the framework will always cut between UTF8 character, so you don't have to worry about writing half an emoji, for example. + * + */ +@property(nonatomic, readwrite, strong, nullable) NSString *nickname; + +/*! + * @property bluetoothAddress + * + * @discussion The bluetooth address of the Flic. This will be a string representation of a 49 bit long address. Example: "00:80:e4:da:12:34:56" + * + */ +@property(nonatomic, readonly, strong, nonnull) NSString *bluetoothAddress; + +/*! + * @property uuid + * + * @discussion This is a unique identifier string that best used to identify a Flic. This is for example used to identify Flics on all our API endpoints. + * + */ +@property(nonatomic, readonly, strong, nonnull) NSString *uuid; + +/*! + * @property serialNumber + * + * @discussion The serial number is a production identifier that is printed on the backside of the Flic inside the battery hatch. + * This serves no other purpose than allowing a user to identify a button by manually looking at it. Can be useful in some cases. + * + */ +@property(nonatomic, readonly, strong, nonnull) NSString *serialNumber; + +/*! + * @property triggerMode + * + * @discussion Use this property to let the flic2lib know what type of click events you are interested it. By default you will get Click, Double Click and Hold events. + * However, if you for example are only interested in Click events then you can set this property to FLICButtonTriggerModeClick. Doing so will allow the flic2lib to + * deliver the events quicker since it can now ignore Double Click and Hold. + * + */ +@property(nonatomic, readwrite) FLICButtonTriggerMode triggerMode; + +/*! + * @property state + * + * @discussion Lets you know if the Flic is Connected, Disconnected, Connecting, or Disconnecting. + * + */ +@property(nonatomic, readonly) FLICButtonState state; + +/*! + * @property pressCount + * + * @discussion The number of times the Flic has been clicked since last time it booted. + * + */ +@property(nonatomic, readonly) uint32_t pressCount; + +/*! + * @property firmwareRevision + * + * @discussion The revision of the firmware currently running on the Flic. + * + */ +@property(nonatomic, readonly) uint32_t firmwareRevision; + +/*! + * @property isReady + * + * @discussion When a Flic connects it will go through a quick cryptographic verification to ensure that it is both a genuine Flic and that it is the correct Flic. + * Once this is completed this property will be set to YES and it is not until after that that you will start receiving click events (if any). As soon as the button disconnects + * this will be set to NO again. + * + */ +@property(nonatomic, readonly) BOOL isReady; + +/*! + * @property batteryVoltage + * + * @discussion This will be the last know battery sample taken on the Flic. If this value is 0 then you should assume that no sample has yet been taken. It is important to know that + * the voltage may fluctuate depending on many different factors, such as temperature and workload. For example, heavy usage of the LED will temporarily lower the voltage, + * but it is likely to recover shortly after. Therefore we do not recomend to exactly translate this value into a battery percentage, instead consider showing a + * "change the battery soon"-status in your app once the voltage goes below 2.65V. + * + */ +@property(nonatomic, readonly) float batteryVoltage; + +/*! + * @property isUnpaired + * + * @discussion If this property is YES, then it means that this app's pairing with this specific Flic is no longer valid. This can for example occur if the Flic has been factory reset, + * or if the maximum number of pairings have been reached. In this case you will need to delete the button from the manager and then scan for it again. + * + */ +@property(nonatomic, readonly) BOOL isUnpaired; + +/*! + * @property latencyMode + * + * @discussion Lets you switch between two different latency modes. For most use-cases it is recommend to keep the default FLICLatencyModeNormal. + * FLICLatencyModeLow should ideally only be used for foreground applications, such as games, where low latency is needed. Keep in mind that the + * energy consumption will be significantly higher in the low latency mode. + * + */ +@property(nonatomic, readwrite) FLICLatencyMode latencyMode; + +/*! + * @method connect + * + * @discussion Attempts to connect the Flic. If the Flic is not available, due to either being out of range or not advertising, then it will be connected once it becomes + * available as this call does not time out. This is often called a pending connection. It can be canceled by calling disconnect. + * + */ +- (void)connect; + +/*! + * @method disconnect + * + * @discussion Disconnect a currently connected Flic or cancel a pending connection. + * + */ +- (void)disconnect; + +@end + +/*! + * @protocol FLICButtonDelegate + * + * @discussion The delegate of a FLICButton instance must adopt the FLICButtonDelegate protocol. All calls to the delegate methods will be on the main dispatch queue. + * + */ +@protocol FLICButtonDelegate + +/*! + * @method buttonDidConnect: + * + * @param button The FLICButton instance that the event originated from. + * + * @discussion This method is called every time the Flic establishes a new bluetooth connection. Keep in mind that you also have to wait for the buttonIsReady: before + * the Flic is ready to be used. + * + */ +- (void)buttonDidConnect:(FLICButton *)button; + +/*! + * @method buttonIsReady: + * + * @param button The FLICButton instance that the event originated from. + * + * @discussion This method is called after each connection once the Flic has been cryptographically verified. You will not receive any click events before this is called. + * + */ +- (void)buttonIsReady:(FLICButton *)button; + +/*! + * @method button:didDisconnectWithError: + * + * @param button The FLICButton instance that the event originated from. + * @param error This error lets you know the reason for the disconnect. An error does not necessarily mean that something went wrong. + * + * @discussion This method is called every time the bluetooth link with the Flic is lost. This can occur for several different reasons. The most common would be that + * the iOS device and the Flic is no longer within range of each other. + * + */ +- (void)button:(FLICButton *)button didDisconnectWithError:(NSError * _Nullable)error; + +/*! + * @method button:didFailToConnectWithError: + * + * @param button The FLICButton instance that the event originated from. + * @param error This error lets you know why the connection attempt failed. + * + * @discussion This method is called when a connection attempt to a button fails. This indicates that something has gone wrong and that the pending connection will not be reset. + * + */ +- (void)button:(FLICButton *)button didFailToConnectWithError:(NSError * _Nullable)error; + +@optional + +/*! + * @method button:didReceiveButtonDown:age: + * + * @param button The FLICButton instance that the event originated from. + * @param queued Whether the event is a queued event that happened before the Flic connected or if it is a real time event. + * @param age If the event was queued, then this will let you know the age of the event rounded to the nearest second. + * + * @discussion The Flic registered a button down event. + * + */ +- (void)button:(FLICButton *)button didReceiveButtonDown:(BOOL)queued age:(NSInteger)age; + +/*! + * @method button:didReceiveButtonUp:age: + * + * @param button The FLICButton instance that the event originated from. + * @param queued Whether the event is a queued event that happened before the Flic connected or if it is a real time event. + * @param age If the event was queued, then this will let you know the age of the event rounded to the nearest second. + * + * @discussion The Flic registered a button up event. + * + */ +- (void)button:(FLICButton *)button didReceiveButtonUp:(BOOL)queued age:(NSInteger)age; + +/*! + * @method button:didReceiveButtonClick:age: + * + * @param button The FLICButton instance that the event originated from. + * @param queued Whether the event is a queued event that happened before the Flic connected or if it is a real time event. + * @param age If the event was queued, then this will let you know the age of the event rounded to the nearest second. + * + * @discussion The Flic registered a button click event. + * + */ +- (void)button:(FLICButton *)button didReceiveButtonClick:(BOOL)queued age:(NSInteger)age; + +/*! + * @method button:didReceiveButtonDoubleClick:age: + * + * @param button The FLICButton instance that the event originated from. + * @param queued Whether the event is a queued event that happened before the Flic connected or if it is a real time event. + * @param age If the event was queued, then this will let you know the age of the event rounded to the nearest second. + * + * @discussion The Flic registered a double click event. + * + */ +- (void)button:(FLICButton *)button didReceiveButtonDoubleClick:(BOOL)queued age:(NSInteger)age; + +/*! + * @method button:didReceiveButtonHold:age: + * + * @param button The FLICButton instance that the event originated from. + * @param queued Whether the event is a queued event that happened before the Flic connected or if it is a real time event. + * @param age If the event was queued, then this will let you know the age of the event rounded to the nearest second. + * + * @discussion The Flic registered a button hold event. + * + */ +- (void)button:(FLICButton *)button didReceiveButtonHold:(BOOL)queued age:(NSInteger)age; + +/*! + * @method button:didUnpairWithError: + * + * @param button The FLICButton instance that the event originated from. + * @param error This will always be nil at this time. + * + * @discussion The app no longer has a valid pairing with the Flic button. The isUnpaired property will now be YES and all connection + * attempts made will immediately fail. To fix this you need to delete the button from the manager and then re-scan it again. + * + */ +- (void)button:(FLICButton *)button didUnpairWithError:(NSError * _Nullable)error; + +/*! + * @method button:didUpdateBatteryVoltage: + * + * @param button The FLICButton instance that the event originated from. + * @param voltage Float representation of the latest battery voltage sample. + * + * @discussion This callback will be sent once the Flic button updates its battery voltage with a new value. Typically this will occurs a few seconds + * after the button connects. If you show a battery indicator in you app, then this would be a good place to refresh your UI. Please + * see the description for the batteryVoltage property for more information. + * + */ +- (void)button:(FLICButton *)button didUpdateBatteryVoltage:(float)voltage; + +/*! + * @method button:didUpdateNickname: + * + * @param button The FLICButton instance that the event originated from. + * @param nickname The new nickname that was sent from the Flic. + * + * @discussion If the nickname is updated by another app (including the official Flic app), then you will get this callback letting you know that the + * name has changed. This may either be in real time (if multiple apps are connected at the same time), or a deayed event that + * occurs after the button connects (if the nickname was changed while your app was not active). If your app displays this nickname, + * then this would be a good place to refresh your UI. + * + */ +- (void)button:(FLICButton *)button didUpdateNickname:(NSString *)nickname; + +@end + +NS_ASSUME_NONNULL_END diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICEnums.h b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICEnums.h new file mode 100644 index 0000000..48bc8bb --- /dev/null +++ b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICEnums.h @@ -0,0 +1,315 @@ +// +// FLICEnums.h +// fliclib +// +// Created by Anton Meier on 2019-04-18. +// Copyright © 2020 Shortcut Labs. All rights reserved. +// + +#ifndef FLICEnums_h +#define FLICEnums_h + +extern NSString * const FLICErrorDomain; +extern NSString * const FLICButtonScannerErrorDomain; + +/*! + * @enum FLICManagerState + * + * @discussion Represents the the different states that a Flic manager can be in at any given time. These states are mostly translated values of Apple's CoreBluetooth CBManagerState enums. + * + */ +typedef NS_ENUM(NSInteger, FLICManagerState) +{ + /** + * State is unknown, update imminent. + */ + FLICManagerStateUnknown = 0, + /** + * The bluetooth connection with the system service was momentarily lost, update imminent. + */ + FLICManagerStateResetting, + /** + * The Flic manager can not be used on this platform. + */ + FLICManagerStateUnsupported, + /** + * The application is not authorized to use Bluetooth Low Energy. + */ + FLICManagerStateUnauthorized, + /** + * Bluetooth is currently powered off. + */ + FLICManagerStatePoweredOff, + /** + * Bluetooth is currently powered on and available to use. + */ + FLICManagerStatePoweredOn +}; + +/*! + * @enum FLICButtonScannerErrorCode + * + * @discussion Represents the different error codes that can be generated while scanning and pairing new Flics. + * +*/ +typedef NS_ENUM(NSInteger, FLICButtonScannerErrorCode) +{ + /** + * The scan was unsuccessful due to an unknown reason. + */ + FLICButtonScannerErrorCodeUnknown = 0, + /** + * The scan could not be started since bluetooth was not in the powered on state. + */ + FLICButtonScannerErrorCodeBluetoothNotActivated, + /** + * No button was advertising in public mode within proximity. + */ + FLICButtonScannerErrorCodeNoPublicButtonDiscovered, + /** + * The bluetooth pairing failed since the user already has paired this button before with this device. + * This is solved by removing the pairing from the iOS bluetooth pairing settings screen. + */ + FLICButtonScannerErrorCodeBLEPairingFailedPreviousPairingAlreadyExisting, + /** + * The bluetooth pairing failed since the user pressed cancel on the pairing dialog. + */ + FLICButtonScannerErrorCodeBLEPairingFailedUserCanceled, + /** + * The bluetooth pairing failed since iOS decided to decline the request. It is unknown why or if this can happen. + */ + FLICButtonScannerErrorCodeBLEPairingFailedUnknownReason, + /** + * Indicates that the button cannot be unlocked since it belongs to a different brand. + */ + FLICButtonScannerErrorCodeAppCredentialsDontMatch, + /** + * The scan was manually canceled using the stopScan method. + */ + FLICButtonScannerErrorCodeUserCanceled, + /** + * The Flic's certificate belongs to a different bluetooth address. + */ + FLICButtonScannerErrorCodeInvalidBluetoothAddress, + /** + * The framework was unable to pair with the Flic since it did not pass the authenticity check. + */ + FLICButtonScannerErrorCodeGenuineCheckFailed, + /** + * The discovered Flic cannot be connected since it is currently connected to a different device. + */ + FLICButtonScannerErrorCodeAlreadyConnectedToAnotherDevice, + /** + * The discovered Flic cannot be connected since the maximum number of simultaneous app connections has been reached. + */ + FLICButtonScannerErrorCodeTooManyApps, + /** + * A bluetooth specific error. The framework was unable to establish a connection to the Flic peripheral. + */ + FLICButtonScannerErrorCodeCouldNotSetBluetoothNotify, + /** + * A bluetooth specific error. The framework was unable to establish a connection to the Flic peripheral. + */ + FLICButtonScannerErrorCodeCouldNotDiscoverBluetoothServices, + /** + * The bluetooth connection was dropped during the verification process. + */ + FLICButtonScannerErrorCodeButtonDisconnectedDuringVerification, + /** + * The Flic peripheral connection was unexpectedly lost. + */ + FLICButtonScannerErrorCodeConnectionTimeout, + /** + * The bluetooth connection failed. + */ + FLICButtonScannerErrorCodeFailedToEstablish, + /** + * The iOS device reached the maximum number of allowed bluetooth peripherals. + */ + FLICButtonScannerErrorCodeConnectionLimitReached, + /** + * The signature generated by the Flic button could not be verified. + */ + FLICButtonScannerErrorCodeInvalidVerifier, + /** + * The Flic button was no longer in public mode when the verification process ran. + */ + FLICButtonScannerErrorCodeNotInPublicMode, +}; + +/*! + * @enum FLICButtonScannerStatusEvent + * + * @discussion While the scanner is running, it will send a status events to let you know what it is doing. These enums represents those events. + * +*/ +typedef NS_ENUM(NSInteger, FLICButtonScannerStatusEvent) +{ + /** + * A public Flic has been discovered and a connection attempt will now be made. + */ + FLICButtonScannerStatusEventDiscovered = 0, + /** + * The Flic was successfully bluetooth connected. + */ + FLICButtonScannerStatusEventConnected, + /** + * The Flic has been verified and unlocked for this app. The Flic will soon be delivered in the assigned completion handler. + */ + FLICButtonScannerStatusEventVerified, + /** + * The Flic could not be verified. The completion handler will soon run to let you know what the error was. + */ + FLICButtonScannerStatusEventVerificationFailed, +}; + +/*! + * @enum FLICError + * + * @discussion These enums represents the different error codes that can be sent from flic2lib, excluding the button scanner which has its own set of error codes. + * + */ +typedef NS_ENUM(NSInteger, FLICError) +{ + /** + * An unknown error has occurred. + */ + FLICErrorUnknown = 0, + /** + * You are trying to use the manager while it has not been configured yet. + */ + FLICErrorNotConfigured, + /** + * A bluetooth specific error code. This means that something went wrong while the phone tried to establish a connection with the Flic peripheral. + */ + FLICErrorCouldNotDiscoverBluetoothServices, + /** + * The framework was unable to verify the cryptographic signature from the Flic while setting up a session. + */ + FLICErrorVerificationSignatureMismatch, + /** + * The UUID of a button is not correct. + */ + FLICErrorInvalidUuid, + /** + * While establishing a connection with the Flic the framework was unable to verify the authenticity of the button. + */ + FLICErrorGenuineCheckFailed, + /** + * The app was unable to establish a connection with the Flic button because it already had a connection with too many apps on this particular phone. + */ + FLICErrorTooManyApps, + /** + * The pairing on the Flic button has been lost so the app's pairing data is no longer valid. This typically happens if the Flic is factory reset. + */ + FLICErrorUnpaired, + /** + * The manager was unable to complete the task since the device is not running on a supported iOS version. + */ + FLICErrorUnsupportedOSVersion, + /** + * You are trying to use a FLICButton object that has already been forgotten by the manager. Please discard of your references to this object. + */ + FLICErrorAlreadyForgotten, +}; + +/*! + * @enum FLICButtonState + * + * @discussion The different states that a Flic can be in at any given time. + * + */ +typedef NS_ENUM(NSInteger, FLICButtonState) +{ + /** + * The Flic is currently disconnected and a pending connection is not set. The Flic will not connect again unless you manually call the connect method. + */ + FLICButtonStateDisconnected = 0, + /** + * The Flic is currently disconnected, but a pending connection is set. The Flic will automatically connect again as soon as it becomes available. + */ + FLICButtonStateConnecting, + /** + * The Flic currently has a bluetooth connection with the phone. This does not necessarily mean that it has been verified. + * Please listen for the isReady event, or read the isReady property, for that information + */ + FLICButtonStateConnected, + /** + * The Flic is currently connected, but is attempting to disconnect. Typically this state will only occur for very short periods of time before either switching to + * the connecting or disconnected state again. + */ + FLICButtonStateDisconnecting, +}; + +/*! + * @enum FLICButtonTriggerMode + * + * @discussion The different trigger modes that you can configure the Flic button to use. Please make sure that you understand how these work. + * The choosen trigger mode will affect the latency on the press events coming from the Flic button. + * + */ +typedef NS_ENUM(NSInteger, FLICButtonTriggerMode) +{ + /** + * Used to distinguish between only click and hold. + * + * Click will be fired when the button is released if it was pressed for maximum 1 second. + * Otherwise, hold will be fired 1 second after the button was pressed. Click will then not be fired upon release. + * Since this option will only distinguish between click and hold it does not have to take double click into consideration. + * This means that the click event can be sent immediately on button release rather than to wait for a possible double click. + * + * Note: this will be the default behavior. + */ + FLICButtonTriggerModeClickAndHold = 0, + /** + * Used to distinguish between only single click and double click. + * + * Double click will be registered if the time between two button down events was at most 0.5 seconds. + * The double click event will then be fired upon button release. + * + * If the time was more than 0.5 seconds, a single click event will be fired; either directly upon button release if the button was down + * for more than 0.5 seconds, or after 0.5 seconds if the button was down for less than 0.5 seconds. + */ + FLICButtonTriggerModeClickAndDoubleClick, + /** + * Used to distinguish between single click, double click and hold. + * + * If the time between the first button down and button up event was more than 1 second, a hold event will be fired. + * Else, double click will be fired if the time between two button down events was at most 0.5 seconds. + * The double click event will then be fired upon button release. + * + * If the time was more than 0.5 seconds, a single click event will be fired; either directly upon button release if the button was down + * for more than 0.5 seconds, or after 0.5 seconds if the button was down for less than 0.5 seconds. + * + * Note: Three fast consecutive clicks means one double click and then one single click. Four fast consecutive clicks means two double clicks. + */ + FLICButtonTriggerModeClickAndDoubleClickAndHold, + /** + * This mode will only send click and the event will be sent directly on buttonDown. + * This will be the same as listening for buttonDown. + * + * Note: This is optimal if your application requires the lowest latency possible. + */ + FLICButtonTriggerModeClick, +}; + +/*! + * @enum FLICButtonTriggerMode + * + * @discussion The different latency modes that you can configure the Flic button to use. + * + */ +typedef NS_ENUM(NSInteger, FLICLatencyMode) +{ + /** + * This is the default mode of the button. It will give you a good compromise between click latency (less than 105 ms while connected) and current consumption. + */ + FLICLatencyModeNormal = 0, + /** + * Using this mode will give your button the lowest possible click latency (typicaly less than 30 ms while connected). + * This mode will significantly increase the current consumption. + */ + FLICLatencyModeLow, +}; + +#endif /* FLICEnums_h */ diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICManager.h b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICManager.h new file mode 100644 index 0000000..ad3c2d7 --- /dev/null +++ b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/FLICManager.h @@ -0,0 +1,171 @@ +// +// FLICManager.h +// flic2lib +// +// Created by Anton Meier on 2019-04-11. +// Copyright © 2020 Shortcut Labs. All rights reserved. +// + +#import +#import +#import "FLICButton.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol FLICManagerDelegate; + +/*! + * @class FLICManager + * + * @discussion This interface is intended to be used as a singleton. It keeps track of all the buttons that have been paired with this particular app and restores them on each + * application launch. + * + */ +@interface FLICManager : NSObject + +/*! + * @property delegate + * + * @discussion The delegate that all the FLICManagerDelegate events will be sent to. Usually this is configured only once when the application is first launched, using the + * configureWithDelegate:buttonDelegate:background: method. + * + */ +@property(weak, nonatomic, nullable) id delegate; + +/*! + * @property buttonDelegate + * + * @discussion Once set, this delegate will automatically be set to every button instance on each application launch. This will also be assigned to new buttons that are discovered + * using the scanForButtonsWithStateChangeHandler:completionHandler method. Using this delegate also ensures that the click events are delivered as fast as possible + * when an application is restored in the background. + * + */ +@property(weak, nonatomic, nullable) id buttonDelegate; + +/*! + * @property state + * + * @discussion This is the state of the Flic manager. This state closely resembles the CBManager state of Apple's CoreBluetooth framework. You will only be able to communicate with + * Flic buttons while the manager is in the FlicManagerStatePoweredOn state. + * + */ +@property(readonly) FLICManagerState state; + +/*! + * @property scanning + * + * @discussion Let's you know if a scan is currently running or not. Reading this value will not affect a scan. + * + */ +@property(nonatomic, readonly) BOOL isScanning; + +/*! + * @method sharedManager + * + * @discussion This class method return the singleton manager, assuming that it has been configured first using the configureWithDelegate:buttonDelegate:background: method first, + * otherwise nil is returned. + * + */ ++ (instancetype _Nullable)sharedManager; + +/*! + * @method + * + * @param delegate The delegate to be used with the manager singleton. + * @param buttonDelegate The delegate to be automatically assigned to each FLICButton instance. + * @param background Whether or not you intend to use this application in the background. + * + * @discussion This configuration method must be called before the manager can be used. It is recommended that this is done as soon as possible after your application has launched + * in order to minimize the delay of any pending click events. The flic2lib officially only support iOS 12 and up, however, to make it easier for the developer, the framework + * is built with a target of iOS 9 and contains slices for both arm64 and armv7. This means that you will be able to include, and load, the framework in apps that support iOS 9. + * However, if you try to configure the manager on a device running iOS 11, or below, then the manager state will switch to FLICManagerStateUnsupported. A good place + * to handle this would be in the manager:didUpdateSate: method. + * + */ ++ (instancetype _Nullable)configureWithDelegate:(id _Nullable)delegate + buttonDelegate:(id _Nullable)buttonDelegate + background:(BOOL)background; + +/*! + * @method buttons + * + * @discussion This array will contain every button that is currently paired with this application. Each button will be added to the list after a call to + * scanForButtonsWithStateChangeHandler:completionHandler: has completed without error. It is important to know that you may not try to access this list until after the + * managerDidRestoreState: method has been sent to the manager delegate. + * + */ +- (NSArray *)buttons; + +/*! + * @method forgetButton: + * + * @param button The button that you wish to delete from the manager. + * @param completion This returns the identifier of the button instance that was just removed along with an error, if needed. + * + * @discussion This will delete this button from the manager. After a successful call to this method you will no longer be able to communicate with the associated Flic button unless you + * pair it again using the scanForButtonsWithStateChangeHandler:completionHandler:. On completion, the button will no longer be included in the manager's buttons array. + * After a successful call to this method, you should discard of any references to that particular Flic button object. If you try to forget a button that is already forgotten, then + * you will get an error with the FLICErrorAlreadyForgotten code. + * + */ +- (void)forgetButton:(FLICButton *)button completion:(void (^)(NSUUID *uuid, NSError * _Nullable error))completion; + +/*! + * @method + * + * @param stateHandler This handler returns status events that lets you know what the scanner is currently doing. The purpose of this handler is to provide a predefined states where + * you may update your application UI. + * @param completion The completion handler will always run and if successful it will return a new FLICButton instance, otherwise it will provide you with an error. + * + * @discussion This method lets you add new Flic buttons to the manager. The scan flow is automated and the stateHandler will let you know what information you should provide to + * your application end user. If you try to scan for buttons while running on an iOS version below the mimimun requirement, then you will get an error with the + * FLICErrorUnsupportedOSVersion error code. + * + */ +- (void)scanForButtonsWithStateChangeHandler:(void (^)(FLICButtonScannerStatusEvent event))stateHandler + completion:(void (^)(FLICButton * _Nullable button, NSError * _Nullable error))completion; + +/*! + * @method stopScan + * + * @discussion Cancel an ongoing button scan. This will result in a scan completion with an error. + * + */ +- (void)stopScan; + +@end + +/*! + * @protocol FLICManagerDelegate + * + * @discussion The delegate of a FLICManager instance must adopt the FLICManagerDelegate protocol. All calls to the delegate methods will be on the main dispatch queue. + * + */ +@protocol FLICManagerDelegate + +/*! + * @method managerDidRestoreState: + * + * @param manager The manager instance that the event originates from. Since this is intended to be used as a singleton, there should only ever be one manager instance. + * + * @discussion This is called once the manager has been restored. This means that all the FLICButton instances from your previous session are restored as well. After this method + * has been called you may start using the manager and communicate with the Flic buttons. This method will only be called once on each application launch. + * + */ +- (void)managerDidRestoreState:(FLICManager *)manager; + +/*! + * @method manager:didUpdateState: + * + * @param manager The manager instance that the event originates from. Since this is intended to be used as a singleton, there should only ever be one manager instance. + * @param state The state of the Flic manager singleton. + * + * @discussion Each time the state of the Flic manager changes, you will get this callback. Usually this is related to bluetooth state changes on the iOS device. It is also guaranteed to + * be called at least once after the manager has been configured. + * + */ +- (void)manager:(FLICManager *)manager didUpdateState:(FLICManagerState)state; + +@end + +NS_ASSUME_NONNULL_END diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/flic2lib.h b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/flic2lib.h new file mode 100644 index 0000000..829bd9d --- /dev/null +++ b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Headers/flic2lib.h @@ -0,0 +1,19 @@ +// +// flic2lib.h +// flic2lib +// +// Created by Anton Meier on 2019-04-10. +// Copyright © 2020 Shortcut Labs. All rights reserved. +// + +#import + +#import +#import +#import + +//! Project version number for flic2lib. +FOUNDATION_EXPORT double flic2libVersionNumber; + +//! Project version string for flic2lib. +FOUNDATION_EXPORT const unsigned char flic2libVersionString[]; diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Info.plist b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Info.plist new file mode 100644 index 0000000..0b4c0fc Binary files /dev/null and b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Info.plist differ diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Modules/module.modulemap b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Modules/module.modulemap new file mode 100644 index 0000000..7893aa8 --- /dev/null +++ b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module flic2lib { + umbrella header "flic2lib.h" + + export * + module * { export * } +} diff --git a/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/flic2lib b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/flic2lib new file mode 100755 index 0000000..3d78187 Binary files /dev/null and b/flic2lib.xcframework/ios-i386_x86_64-simulator/flic2lib.framework/flic2lib differ diff --git a/simulator/FLICButtonSimulator.m b/simulator/FLICButtonSimulator.m deleted file mode 100644 index c24e8ff..0000000 --- a/simulator/FLICButtonSimulator.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// FLICButtonSimulator.m -// flic2lib -// -// Created by Anton Meier on 2019-12-10. -// Copyright © 2020 Shortcut Labs. All rights reserved. -// - -#import - -#if TARGET_OS_SIMULATOR - -@implementation FLICButton - -- (void)connect; -{ - -} - -- (void)disconnect; -{ - -} - -@end - -#endif diff --git a/simulator/FLICManagerSimulator.m b/simulator/FLICManagerSimulator.m deleted file mode 100644 index b7eebc4..0000000 --- a/simulator/FLICManagerSimulator.m +++ /dev/null @@ -1,81 +0,0 @@ -// -// FLICManagerSimulator.m -// flic2lib -// -// Created by Anton Meier on 2019-12-10. -// Copyright © 2020 Shortcut Labs. All rights reserved. -// - -#import - -#if TARGET_OS_SIMULATOR - -NSString * const FLICErrorDomain = @"com.shortcutlabs.flic2lib"; -NSString * const FLICButtonScannerErrorDomain = @"com.shortcutlabs.flic2lib.buttonscanner"; - -@implementation FLICManager - -static FLICManager *_sharedManager = nil; - -+ (instancetype _Nullable)sharedManager; -{ - return _sharedManager; -} - -+ (instancetype _Nullable)configureWithDelegate:(id _Nullable)delegate - buttonDelegate:(id _Nullable)buttonDelegate - background:(BOOL)background; -{ - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - _sharedManager = [[FLICManager alloc] init]; - _sharedManager.delegate = delegate; - _sharedManager.buttonDelegate = buttonDelegate; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - if ([FLICManager sharedManager].delegate && [[FLICManager sharedManager].delegate respondsToSelector:@selector(managerDidRestoreState:)]) - { - [[FLICManager sharedManager].delegate managerDidRestoreState:[FLICManager sharedManager]]; - } - }); - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - if ([FLICManager sharedManager].delegate && [[FLICManager sharedManager].delegate respondsToSelector:@selector(manager:didUpdateState:)]) - { - [[FLICManager sharedManager].delegate manager:[FLICManager sharedManager] didUpdateState:FLICManagerStatePoweredOn]; - } - }); - }); - - return _sharedManager; -} - -- (NSArray *)buttons; -{ - return @[]; -} - -- (void)forgetButton:(FLICButton *)button completion:(void (^)(NSUUID *uuid, NSError * _Nullable error))completion; -{ - dispatch_async(dispatch_get_main_queue(), ^{ - completion(button.identifier, nil); - }); -} - -- (void)scanForButtonsWithStateChangeHandler:(void (^)(FLICButtonScannerStatusEvent event))stateHandler - completion:(void (^)(FLICButton * _Nullable button, NSError * _Nullable error))completion; -{ - dispatch_async(dispatch_get_main_queue(), ^{ - completion(nil, [NSError errorWithDomain:FLICButtonScannerErrorDomain code:FLICButtonScannerErrorCodeUnknown userInfo:@{NSLocalizedDescriptionKey: @"You can not scan for Flic buttons while running on the iOS Simulator."}]); - }); -} - -- (void)stopScan; -{ - -} - -@end - -#endif