Powered By Flic - Implementation Guidelines
The PBF framework provides everything needed for your iOS or Android app to start communicating with your own branded buttons. The buttons communicate using Bluetooth Low Energy meaning that only the mobile devices equipped with that technology are supported. At this moment we support the following devices:
From iPhone 4S, 5th generation iPod Touch, 3rd generation iPad and newer devices running on iOS 8.3 or above operating systems.
Most flagship devices from the major manufacturers capable of running Android 4.4 or above operating systems.
The purpose of this framework is to provide a simple and intuitive way of communicating with your branded buttons by abstracting away the complexity of Bluetooth Low Energy.
1 Technical overview and Terminology
1.2 Pending connection
2 PBF modes
2.1 Background mode
2.2 Foreground mode
3 PBF trigger behaviors
4 Verification Process
4.1 Full Verification
4.2 Quick Verification
4.3 Privacy Modes
4.3.1 Public Mode
4.3.2 Private Mode
4.3.3 Switching Between Modes
4.5 Factory Reset
4.6 App Credentials
5 Battery Usage
5.3 On board LED
6 Network data usage
6.1 Address syncing
6.2 Verification process
6.3 Firmware update
7 Platform Limitations and Guidelines
7.1 Number of connected PBFs to a device
7.2 Background capabilities on iOS
7.3 State Preservation and Restoration on iOS
7.3.1 Significant-Change location service
7.4 Background capabilities on Android
The physical button, Powered By Flic, will in this document be referenced to as both PBF and "the button" interchangeably.
The phone or tablet used to connect to a button will be referenced as a "device".
The framework consists of two classes, a Manager class and a Button class. The manager takes care of, and also keeps track of, all the buttons that are associated with the particular device and app. It remembers all the buttons that have ever been used and makes sure to preserve them in the case of an application crash or termination. Starting a communication with a button is as easy as creating a manager and starting a scan. All buttons that are advertising within a certain proximity of the device will be found. Whenever a button is found a Button object is created and assigned to that particular physical button. You can say that such a button object is a virtual representation of the physical button and all events triggered on the physical button will be delivered to the user via that button object.
One thing that is important for you as a developer to remember is that all buttons has to be verified as genuine buttons before you can start receiving trigger events. This additional security level is needed for several reasons, both in order to protect the hardware and software combination, but also from a user perspective where he/she needs to know that all events that are delivered through the API originates from a genuine button and not fake/corrupt hardware. This essentially means that both your App and the actual button must be verified by our backend before it can be used. This process, however, only needs to be completed on the very first connection between the device and the button. Every succeeding connection only requires a seamless quick verify between the device and that particular button. We will go in to this in further details in the Verification Process section further down in this document.
When the PBF is not connected to the device then the only way for it to be discovered and connected to is through advertising. Advertising is the button's way of letting it's surrounding know that it is available and have some data to send. These advertising packets include the button's identifier which in turn lets the device know which PBF that is advertising and thus whether it is in any interest to that particular device or not. Typically if the PBF is not connected then this advertising sequence would start on a button press and then go on until either a device connects to it or until it reaches a certain timeout that is dependent on what mode the PBF is configured to be in. If the PBF's LED flashes red a few times it is pressed, then it means that it is advertising and thus not connected.
A pending connection is a non timeout connection request on the device that is constantly waiting for a certain button to appear. Once the phone discovers the button it will immediately connect to it. If the connection is successful, then the connection state property of the button object will switch to connected. Typically a pending connection will occur either if a user calls the
connect method on the
Button object or if it was connected before but the connection was lost. More information on the available modes can be found further down in this document.
The connected state is the only state in which the button and the device can exchange data. The connected state is not the same as being verified. As mentioned earlier, a button will only forward events after it has been verified, which is notified by a
ready callback. Typically this verification only takes around 100-200 ms.
The disconnected state is the state where the PBF and the device are not connected to each other, nor looking for each other. This state consumes no power on the device and no power on the PBF provided that the advertisement has not manually been started again by the user.
To make it easier for you we have for iOS predefined two modes that we feel should take care of most use-cases. The main different is the power consumptions.
The regular mode is the recommended mode to use and is made to work with applications. This mode works regardless if you are planning to make a foreground app or background app that need a long running connection with the button even when the application is not in the foreground. In this mode the button will be in a constant connection to the device whenever the two are in proximity with each other. It will always try to automatically reconnect in case the connection is lost. If the button and the device have been away from each other for an extended period of time then the button may decide to stop its advertisement in order to preserve energy. If this occurs then it will start again as soon as the user manually pressed it. If the connection however is canceled using the
disconnect method then the auto connect feature will be turned off. This mode has a maximum link latency of around 280ms whenever connected. This is the most energy conservative mode.
This mode is practically the same as the regular mode, but with the main difference that it instead has a maximum link latency of around 45ms whenever the button is connected and the app is in the foreground. This is good for foreground applications where response time is crucial. The downside is that it consumes more energy so use with caution. As soon as the application leaves the foreground the latency will be set back to the standard. Please only use this mode if you have a very good reason to do so.
On the Android platform we also have a few more modes that are available. See the API documentation for more details on this.
For PBF we have defined five different trigger events that can be triggered when a user interacts with a button. These events are the following:
To make all of these events work together in an uncomplicated way we have three different trigger behavior modes that you as a developer can choose between depending on what fits your application the best. They are described in more detail in the API documentation. Regardless of which mode you want to use, buttonDown and buttonUp will always be available as well.
Before a user can start using a PBF it has to go through a verification process in order to verify the authenticity of both the PBF itself, as well as the software that it communicates to. This level of security allows us to protect the hardware and software combination, which we feel is important for us in order to deliver the best user experience to you and your end users. This also allows for you as a developer, and user, to feel secure that all the events that are delivered through the framework originates from a genuine PBF button. Besides that, it also helps to make sure that the trigger events that might be queued up on the button gets delivered to the correct user. Additionally, this also provides protection against replay attack to prevent other people to send false events to your device.
In short the verification process is there in order to facilitate the following needs:
- The App to verify the authenticity of the PBF, and verify that it is allowed to communicate with the particular App credentials of this App.
- The PBF to verify the authenticity of the App. Both that it uses the correct framework and that it has the correct App credentials.
- The backend to verify the authenticity of the App and PBF combination.
What this essentially means is that both the App and the PBF must be verified by our backend before it can be used. This process luckily only has to be completed on the very first connect between the device and a PBF. Every succeeding connection only requires a quick verify between the device and that particular PBF.
The full verification process has to be completed on each PBF one time before it can be used. This will be done on the very first connect to a new device. It is in this process that the crypto key exchange occurs between the PBF, the app, and the backend server and it thus requires an active internet connection in order to complete. When complete, you will get the
buttonIsReady: callback. Depending on the current internet connection this can take up to a few seconds. If for some reason something goes wrong during this process then a
didFailToConnectWithError: callback will be sent.
The quick verification process will be performed every time a previously fully verified PBF connects to a device, no matter the reason for it. The purpose of this is simply to verify that it is the same PBF that reconnects and that it is not a fake/corrupt hardware trying to spoof, or replay, a connection. Typically this process takes about 200 milliseconds and no internet connection is needed for this. A
connection failed callback will be sent here if something goes wrong as well.
The PBF has two different privacy modes that it can operate in, Public and Private:
By default when a PBF comes from the factory it will be in the public mode. What public mode means is that all connection attempts will be granted, which is required when connecting the button to a new app for the first time. This means that you have to make sure that the button is in the public mode before scanning for it.
As soon as the PBF has established a connection to a device and everything has been verified correctly the PBF will switch to the private mode. While in this mode it will only grant connections from devices that it has previously been verified with (whitelisted devices), all other connections will be denied. This allows us to lower the risk of having other devices connecting to a button that is owned by someone else and thus ”stealing” the connection. This whitelisting is described in a separate section below.
Switching Between Modes
If the button is in the private mode then there are only two ways to switch it to public:
- By pressing down on the PBF and holding it for 6 seconds when it is not connected to a device.
- By doing a factory reset (all whitelisted devices will be cleared).
The first option is of course the recommended option if you just want to add another device to the whitelist. This public state is however only temporary and lasts for up to 30 seconds if no connection is made. If a connection is made, either successfully or unsuccessfully, then it will switch back to private again. This means that if you want to add a new device and the connection fails for some reason, then you have to redo the process again.
As mentioned earlier, it will automatically switch to private as soon as it has at least one device in the whitelist. There is no way to switch from public to private if no devices has been whitelisted.
More information on this will be updated later on. For now all you need to know is that the whitelist supports up to 6 devices.
If you for some reason want to perform a factory reset on the PBF then it can only be achieved through the SDK on a button that is currently connected. Resetting the button will set it back to the settings that it had when it came from the factory. The internal whitelist will also be cleared.
For you to use the framework you needs to receive App credentials from us that will be tied to the app that is being developed. These App credentials consists of two keys:
- App ID - A string representation a 16 byte hex value.
- App Secret - A string representation a 16 byte hex value.
These credentials will represent the identity of your App and it is up to you to make sure that they are kept a secret. Both of them has to be provided to the framework when you instantiate the manager, which will be the case during a restoration process as well. However, the credentials will not be validated when the manager is instantiated, instead they will be validated every time a button goes through a full verification process, as mentioned above.
When it comes to battery usage there are a few things that are important to know about in order to minimize the battery usage on both the PBF and the device. The absolute key thing here is to always choose the most battery conservative implementation that works with your application. For example, if you are developing a game that is only supposed to work in the foreground, then you should always make sure to disconnect the button whenever the app is no longer in the foreground. It would not make sense to keep an active connection beyond that point.
Scanning for buttons can consume some power on the device so you should try to avoid having a scan running for long periods of times if possible. As mentioned earlier, scanning in the background is not recommended. Scanning should ideally only occur when you want to find a new button for the first time, so as long as you provide an interface for the user to scan for new buttons and then stop the scanning once a button is found it should not be an issue. Using a timeout on the scan would also be a good idea.
When the button is connected it is constantly communicating with the device in order to withhold the connection, which of course means that power will be consumed. Luckily the power consumption is not a big issue in the connected state as long as you don't use the low latency mode. The framework will seamlessly change the interval at which the button communicate with the device to lower the consumption whenever possible.
The PBF has an on board LED that can be used whenever it is connected. The LED is by far the most power consuming component on the PBF so we strictly recommend that you only use it when absolutely necessary.
The framework will use a network connection during a few different scenarios.
Since our buttons are branded to many different companies but each company's app should only recognize the correct buttons, the SDK will pull a list from our server with address ranges corresponding to your company's branded buttons. The scanning procedure will then filter away buttons that is not included in this list.
As mentioned earlier in this document, for security reasons internet access is required the very first time a new PBF connects to a device for the first time. This corresponds to when a button is found and unlocked during a scan.
The framework will occasionally poll the backend server to see if there is a new firmware upgrade available for the PBF buttons. This is important since it will allow us to automatically upgrade to new firmware versions seamlessly in the background in case a new, and better, firmware is available. Every PBF customer has the option to choose if, or when, a new firmware version will be pushed out to the buttons in case your company wants to quality assure it first. This auto-update feature can also be opted-out of if needed, but usually all firmware patches are recommended.
The framework does collect statistics about the PBF buttons for a variety of reasons. First of all it is very important to mention that we do not gather any information that is tied to a specific user and that the core purpose of the statistics gathering is to be able to detect abnormal behaviours in the usage of the button. This way we can not only detect issues sooner, but it also helps us in troubleshooting in case an issue is discovered. All statistics events that are collected are stored locally on the device and then batch uploaded to our backend at given intervals.
The following events are gathered:
- Click events of all types.
- Connect events
- Button verification complete events
- Disconnect events
- Connection failed events including error codes
- Battery levels
- Framework initialization events
- Button scan discovery events
- Firmware update start events
- Firmware update complete events
- Firmware update failed events
- Button reboot counter
When developing for PBF on the different platforms there are some restrictions and guidelines that are important to know about. The restrictions may or may not limit the capabilities of PBF depending on what type of application you are creating. We recommend that you read through these limitations and guidelines and make sure that you understand them before you start developing.
How many buttons that can be connected to a particular device at any given time is dependent on the hardware of that particular device. Most smartphones today support around 8 Bluetooth devices connected at the same time. This is a limit that is shared between other accessories as well, meaning that if the user has other bluetooth peripherals connected then the total number of PBFs that can be connected will be lower. It is up to the manufacturer of the smartphone and the software of that smartphone to decide how manny peripherals that are supported. We have noticed a range between 3 and 10 units between different devices.
The iOS platform has some very strict restrictions on what an application is allowed to do when it is not in the foreground. When the application is not in the foreground you are by default not allowed to do any kind of work in the background. Apple provides a few different background execution modes that an application can choose to use provided that the app lives up to the requirements specified for the different background modes. Take a look at Apple’s own documentation of "App States and Multitasking" if you want to learn more about this.
One such background mode affects Bluetooth Low Energy communication which is the protocol used by PBF. This background mode, called bluetooth-central, is the mode that the framework needs to use if you are planning to communicate with a button while the app is not in the foreground. This will allow your application to be woken up by the system from the suspended state to the background whenever an event has happened on the button. At this time the app will be allowed to perform some tasks that are related to the bluetooth event for a short period of time before being suspended again. The following three guidelines below are specified by Apple and has to be followed when using this background execution mode:
- Apps should be session based and provide an interface that allows the user to decide when to start and stop the delivery of Bluetooth-related events.
- Upon being woken up, an app has around 10 seconds to complete a task. Ideally, it should complete the task as fast as possible and allow itself to be suspended again. Apps that spend too much time executing in the background can be throttled back by the system or killed.
- Apps should not use being woken up as an opportunity to perform extraneous tasks that are unrelated to why the app was woken up by the system.
Also take a look at the ”Being a Responsible Background App" in Apple’s iOS App Programming Guide.
In short this means for the framework that the app will be woken up to the background during the following scenarios:
- When a PBF is pressed while connected and a press event needs to be sent
- When a PBF connects
- When a PBF disconnects
- When the bluetooth state changes
- When a PBF is found during a scan
While it is possible to scan for buttons in the background we strongly discourage it. Doing so goes against our recommended and intended use-flow of the framework, as well as may have a negative effect on the battery consumption of the iOS device due to increased radio usage. Apart from this, Apple also impose some additional restrictions on background scanning such as a longer scanning interval which in our case would mean that finding buttons would take more time than usual.
The requirement that apps needs to be session based simply means that the end user of the App must be prompted with a quick and easy way of entirely turning off all bluetooth communication with that specific App. This is something that you as a developer are responsible to live up to; failing to do so may lead to your app being rejected by Apple. We have made it simple for you by providing two methods on the manager (
disable:) that you can use for this purpose.
If you are reading this you are probably aware of the fact that iOS has the right to terminate your app at any time without notice; no matter if your app is in the foreground, background or suspended state. By default this means that all tasks that your application is doing will be stopped. This could for example be due to memory limitations on the system or any other reason.
Luckily the framework can recover from this for you! This means that you will be able to continue communicating with the buttons even after your app gets terminated by the system. Whenever a bluetooth event happens when the app is terminated then the app will get launched back into the background again, at which point you are able to go ahead and restore the manager. The manager will be restored back to the last previously known state and all the button objects that were associated to that particular manager will be recreated. After that you can simply collect all the flic objects again and continue to use them normally, but remember that all the rules associated with background execution still applies here. Keep in mind that fliclib does not support the built in "State Preservation and Restoration" for viewControllers, instead you must use the preservation methods specified by the framework.
Unfortunately there are a few cases where background execution from state preservation in the terminated state works differently from the regular background execution from suspended state. The app will not be brought back to the background during the following two scenarios:
- When the bluetooth state changes (this will also cause all pending connections to be canceled)
- After the app is terminated due to a system reboot
- If your application has crashed
These three cases are particularly important to understand when using the framework since they can cause a problem if the user expects it to work when it in fact does not. When it comes to rebooting the iOS device Apple does not provide a way to restart the Bluetooth Low Energy related tasks. This ultimately means that in order for your app to continue the communicating with a PBF after a system reboot it need to be launched into the background again through other means, or alternatively by being launched to the foreground again by the user. As mentioned above, a bluetooth state change will also destruct any bluetooth communication. This means that if the user turns off the bluetooth module on the device while the app is terminated, then it will not start working properly again even if the bluetooth module is powered on again. The same thing applies here as with the reboot, meaning that the app has to be launched by other means. These restrictions are very unfortunate.
Significant-Change location service
Due to the restrictions discussed in the previous section we strongly recommend that your app subscribes to significant location changes on iOS. Doing so will function as a workaround for these mentioned issues. Subscribing to the Significant-Change location service will allow your app to be woken up at regular intervals at which point the framework can restore its state on its own. This will work both after bluetooth state changes, as well as after system reboots. Please call the
onLocationChange method on the manager whenever you get a location change. Please have a look at Apple's documentation of this in the Starting the Significant-Change Location Service section of the Getting the User's Location document.
There is, however, one drawback with using the Significant-Change location service and that is that you have to motivate to your end users why your application should be allowed to track the users location. This is done by assigning descriptive strings to the NSLocationAlwaysUsageDescription and NSLocationUsageDescription keys in your app’s Info.plist file and set the value of those keys to strings that describes how your app intends to use location data. These strings will be shown to your user by the iOS prompt that he or she has to accept before the location service will be activated. It is unclear wether or not Apple will review this on App Store submission as well. It is up to you to come up with descriptive strings that you feel fits your application the best.
The SDK on Android internally uses the Bluetooth client libraries powered by Android. Internally it assigns callbacks to the Bluetooth stack that will be called upon events such as connected, disconnected, notifications (button presses etc.). For this to work the app process must be kept alive. However, by default Android usually kills app processes when there are currently no running activities in the foreground. To prevent this from happening the app must have declared and have a foreground service running. As long as there is a foreground service running, no matter what it does, the app process will continue to run and hence the SDK will keep running and receive button events. Most Powered by Flic use cases are to trigger an event when the screen is turned off, which means the app must use a foreground service. However for some use cases this is not as needed, such as when the button is used as a game controller, controlling a game that runs in a foreground activity, since the button should only work when the app is brought to the front anyway.
When the device reboots, your application will normally not be started automatically, which means the buttons won't work until the user starts the app. To fix this, the app needs to listen to the
android.intent.action.BOOT_COMPLETED intent that is sent by the system when the device boots. Similarly, when the app is updated on Play Store, the app needs to listen to the
Our provided sample project will deal with these two issues.