Skip to content

Tutorial

Anton Meier edited this page Apr 6, 2020 · 5 revisions

Apple Logo

iOS Tutorial

You are just a few steps away from having Flic 2 functionality in your iOS app. This tutorial will show you how to implement the basic features of flic2lib starting from a blank Xcode project. The framework is distributed as an XCFramework bundle, which means that it will, by default, run on both device and simulator targets.

Set up Xcode

  1. Place the downloaded flic2lib.xcframework folder somewhere on you computer, preferably in your project's folder structure.

  2. Drag-and-drop the whole flic2lib.xcframework folder from your finder window to the Frameworks, Libraries, and Embedded Content section under the General tab of your application's target setting.

    Ensure that flic2lib.xcframework is listed as Embed & Sign:

    Frameworks, Libraries and Embedded Content

    Doing this should automatically add the xcframework to Link Binary With Libraries under the Build Phases tab.

  3. Under Project Settings -> Build Settings, set the flag Allow Non-modular includes in Framework Modules to Yes:

    Allow non Modular

  4. In your project settings, check the Uses Bluetooth LE accessories option under Background Modes in the Signing & Capabilities tab.

    Note: If you can't see the options for Background Modes then you need to add that capability by pressing + in the top left corner of that view.

    Checking this option will let iOS know that we want permission to communicate with Flic buttons while the application is in the background.

    Background Modes

  5. It the project's Info.plist file we must now add two keys:

    • Privacy - Bluetooth Peripheral Usage Description
    • Privacy - Bluetooth Always Usage Description

    The first one specifies that we wish to connect with Bluetooth Peripherals and the second one specifies that we will do so in the background. The values that you add here will be displayed to the user when iOS shows its bluetooth permission dialogs.

    Plist Values

Objective-C Code

  1. Import the xcframework module by addinng @ import flic2lib; wherever it suits your application the best. If you are using Swift, then type @import flic2lib instead. In this case we will just add it to the view controller implementation file. We also went ahead and added both of the Button and Manager delegate protocols.

    @ import flic2lib;
    
    @interface ViewController () <FLICButtonDelegate, FLICManagerDelegate>
    
    @end
  2. The first thing we need to do before we can start using the Flic Manager is to configure its singleton. This needs to be done on every application launch.

    In this case we will do so in the viewDidLoad method. The background execution flag specifies whether or not you intend to use the buttons in the background, so we will set it to YES.

    - (void)viewDidLoad
    {
    	[super viewDidLoad];
    	[FLICManager configureWithDelegate:self buttonDelegate:self background:YES];
    }
  3. Now that the manager is configured we can go ahead and discover our first Flic by starting a scan. You will most likely only want the scan to start on some sort of user interaction. In this example we have created a UI button that is tied to the IBAction startScan.

    The manager has an integrated scan wizard that takes care of Flic discovery and pairing. When starting a scan we need to create two handlers, one event handler, and one completion handler. The event handler is meant as a way to provide information on what is going on and it is a good idea to update the app UI on those events. The completion handler will always run regardless if a button was found or not.

    - (IBAction)startScan:(id)sender;
    {
    	[[FLICManager sharedManager] scanForButtonsWithStateChangeHandler:^(FLICButtonScannerStatusEvent event) {
    		// You can use these events to update your UI.
    		switch (event)
    		{
    			case FLICButtonScannerStatusEventDiscovered:
    				NSLog(@"A Flic was discovered.");
    				break;
    			case FLICButtonScannerStatusEventConnected:
    				NSLog(@"A Flic is being verified.");
    				break;
    			case FLICButtonScannerStatusEventVerified:
    				NSLog(@"The Flic was verified successfully.");
    				break;
    			case FLICButtonScannerStatusEventVerificationFailed:
    				NSLog(@"The Flic verification failed.");
    				break;
    			default:
    				break;
    		}
    	} completion:^(FLICButton *button, NSError *error) {
    		NSLog(@"Scanner completed with error: %@", error);			
    		if (!error)
    		{
    			NSLog(@"Successfully verified: %@, %@, %@", button.name, button.bluetoothAddress, button.serialNumber);
    			// Listen to single click only.
    			button.triggerMode = FLICButtonTriggerModeClick;
    		}
    	}];
    }
  4. At this point we are mostly done, but let's add some more delegate methods so that we can actually make use of the Flics.

    It is good practice to newer call any methods on the manager before managerDidRestoreState: has been called.

    - (void)managerDidRestoreState:(FLICManager *)manager;
    {
    	// The manager was restored and can now be used.
    	for (FLICButton *button in manager.buttons)
    	{
    		NSLog(@"Did restore Flic: %@", button.name);
    	}
    }
  5. The manager:didUpdateState: is recommended in order to keep track of the state changes. Here you should handle the FLICManagerStateUnsupported state in case you intend to include the framework on devices with a deployment target lower than iOS 12. Please read the OS Compatibility document if that is relevant to you.

    - (void)manager:(FLICManager *)manager didUpdateState:(FLICManagerState)state;
    {
    	switch (state)
    	{
    		case FLICManagerStatePoweredOn:
    			// Flic buttons can now be scanned and connected.
    			NSLog(@"Bluetooth is turned on");
    			break;
    		case FLICManagerStatePoweredOff:
    			// Bluetooth is not powered on.
    			NSLog(@"Bluetooth is turned off");
    			break;
    		case FLICManagerStateUnsupported:
    			// The framework can not run on this device.
    			NSLog(@"FLICManagerStateUnsupported");
    		default:
    			break;
    	}
    }
  6. Let's add some log printing as well to verify that everything is working:

    - (void)buttonDidConnect:(FLICButton *)button;
    {
    	NSLog(@"Did connect Flic: %@", button.name);
    }
    
    - (void)button:(FLICButton *)button didDisconnectWithError:(NSError *)error;
    {
    	NSLog(@"Did disconnect Flic: %@", button.name);
    }
    
    - (void)button:(FLICButton *)button didReceiveButtonClick:(BOOL)queued age:(NSInteger)age;
    {
    	NSLog(@"Flic: %@ was clicked", button.name);
    }

That's it!


Clone this wiki locally