IOS Bluetooth development

Due to the need of the work, some time ago to sort out the IOS Bluetooth communication related things, put a result collection to share with you. If there is a shortage of welcome correction.

Project background

Introduce what I do, the equipment now has four, respectively, body fat scales, blood pressure, blood glucose meter, monitor etc.. Everyone should know what they are. Yes, they are mainly used to measure some of the body’s data, such as blood pressure, blood sugar, fat, etc.. Through these data to reflect the user’s physical health. Communicate with iPhone phone via bluetooth. Mobile phone terminal app by sending different instructions (via Bluetooth) control to perform some action corresponding equipment, such as read the data on the device, to the user after the measurement data will send the user to the server, and then return to the health condition of the user to the mobile phone. If you don’t say much, let’s get started.

Two, IOS Bluetooth introduction

Bluetooth protocol itself has changed from 1 to 4 upgrade, the new 4 in its low power consumption is known, it is generally called BLE (Bluetoothlow energy). Bluetooth
IOS four framework, including two support and peripherals. One is ExternalAccessory. From the ios3.0 began to support, but also in the iphone4s out of the use of more than one model, but it has a bad place, External Accessory need to get the Apple Corp MFI certification. Another framework is the CoreBluetooth to be introduced in this article, the iphone4s began to support, specifically for communication with the BLE device (because it is based on the API BLE). This does not require MFI, and now a lot of Bluetooth devices are supported by 4, so it is also recommended in the development of a IOS comparison.

Three, CoreBluetooth introduction

The core CoreBluetooth framework is actually two things, peripheral and central, can be understood as the center and peripheral equipment. They correspond to a set of related API and classes, as shown in the following figure:

IOS Bluetooth development

Structure of CoreBluetooth

If you want to program the equipment is the central you use most, and vice versa. In our example, blood pressure monitors, body fat scales and so on are peripheral, our iPhone phone is central, so I will use most of the left part of the figure. There are a lot of peripheral programming examples, such as with a iPad and a iPhone communication, iPad is considered to be central, iPhone end is peripheral, in this case the iPhone will use the above right end part of the class to develop.

Four, services and features

Is necessary to explain to you. What is the service and the characteristics of it (service and characteristic)?
each 4 Bluetooth devices are displayed through service and its own characteristics, a device must contain one or more services, each service below contains several features. The smallest unit of interaction with the outside world. For example, a Bluetooth 4 devices, with the characteristics of A to describe their ex factory information, with the characteristics of B to send and receive data, etc..
services and features UUID is used to uniquely identify the concept of UUID, if you do not know your own Google, the international organization for some typical Bluetooth devices (such as heart rate and blood pressure measuring equipment) provides a standard service UUID (feature UUID more, here is not listed a), as follows:


There are a lot of equipment is not in the standard list, for example, I use the blood pressure and body fat scale. The Bluetooth hardware equipment manufacturers often provide their equipment inside each service (service) and features (characteristics) function, such as what is used to interact (read and write), which can obtain the information module (read only).

Five, implementation details

As a center to achieve a complete communication, generally go through several steps:
establish the central role of scanning peripheral (discover) – (connect) – connected peripherals and peripherals in service feature scan (discover) – data communication and peripherals (explore and interact) – disconnected (disconnect).

1 establish a central role

First in my class header file contains the CoreBluetooth header file, and inherit the two protocols of < CBCentralManagerDelegate, CBPeripheralDelegate> and the code is as follows:

#import < CoreBluetooth/CoreBluetooth.h> / / center equipment management @property (nonatomic, strong) CBCentralManager *centerManager; / / set the initialization center in viewDidLoad and self.centerManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil agent options:nil];
2 scan peripherals (discover)
[self.centerManager scanForPeripheralsWithServices:nil options:options];

This parameter should also can specify a particular peripheral UUID, so in theory this central will only discover the specific equipment, but I found that if the actual test, with specific UUID parameters could not find any equipment. This may be due to equipment in the relevant broadcast packets

3 connection peripherals (connect)

When scanning to 4 devices, the system will tell us the device information through the callback function, then we can connect the corresponding equipment, the code is as follows:

- (void) centralManager: (CBCentralManager * central) didDiscoverPeripheral: (CBPeripheral * peripheral) advertisementData: (NSDictionary * advertisementData) RSSI: (NSNumber * RSSI) {/ / _dicoveredPeripherals / / external device is used to store has been scanned if found this peripheral device I added it to the array of if ([_dicoveredPeripherals containsObject:peripheral] [_dicoveredPeripherals addObject:peripheral]!) (@ NSLog; "dicoveredPeripherals:%@", _dicoveredPeripherals);}
/ / connect to the specified equipment - (BOOL) connect: (CBPeripheral * peripheral) {NSLog (@ "connect start"); _testPeripheral = nil; [self.centerManager connectPeripheral:peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]]; / / open a timer monitoring connection timeout condition connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector (connectTimeout:) userInfo:peripheral (YES); repeats:NO]; return}
4 scanning peripheral services and features (discover)

The same, when the connection is successful, the system will tell us through the callback function, and then we go to the services and features all of the scanning equipment under in the callback, the following code:

/ / connect peripherals (void) - centralManager: (CBCentralManager * central) didConnectPeripheral: (CBPeripheral * peripheral) {[connectTimer invalidate]; / / stop clock NSLog (@ "Did connect to peripheral:, peripheral% @"); _testPeripheral = peripheral; [peripheral setDelegate:self]; [peripheral discoverServices:nil];}

The services and features a device in more often, in most cases, we only care about some of them, so usually found in the services and features the callback to match those we care about, such as the following code:

It was found that the peripheral equipment / / service - (void) peripheral: (CBPeripheral * peripheral) didDiscoverServices: (NSError * error) {NSLog (@ didDiscoverServices); if (error) {NSLog (@ Discovered services for with error:% @% @ ",, [error localizedDescription] if ([self.delegate); respondsToSelector:@selector (DidNotifyFailConnectService:withPeripheral:error:)] [self.delegate DidNotifyFailConnectService:nil withPeripheral:nil error:nil]); return;} / / traversal peripheral device service for (CBService *service in {/ / if we need to find the service, then we go to the if isEqual:[CBUUID [service.UUID (scanning characteristic value UUIDW IthString:UUIDSTR_ELECTRONIC_SCALE_SERVICE]] NSLog (@ Service) {found with, service.UUID UUID:% @ "); [peripheral discoverCharacteristics:nil forService:service]; break;}}}
According to the service / find the corresponding eigenvalue - (void) peripheral: (CBPeripheral * peripheral) didDiscoverCharacteristicsForService: (CBService * service) error: (NSError * error) {if (error) {NSLog (@ Discovered characteristics for with error:% @% @ ", service.UUID, [error localizedDescription] if ([self.delegate); respondsToSelector:@selector (DidNotifyFailConnectChar:withPeripheral:error:)]) [self.delegate DidNotifyFailConnectChar:nil withPeripheral:nil error:nil]; return;} / / service traversal all the eigenvalues of for (CBCharacteristic *characteristic in service.characteristics) {/ / we need to find characteristics of if ([characteristic.UUID isEqual:[CBUUID U UIDWithString:UUIDSTR_SCALE]]) {NSLog ("Discovered read characteristics:%@ for @ service:, characteristic.UUID, service.UUID% @"); _readCharacteristic = characteristic; / / read the preservation characteristics of if ([self.delegate respondsToSelector:@selector [self.delegate DidFoundReadChar:characteristic] (DidFoundReadChar:)]); break;}} for (CBCharacteristic * characteristic in service.characteristics if ([characteristic.UUID) {isEqual:[CBUUID {NSLog (@ UUIDWithString:UUIDSTR_ISSC_TRANS_RX]]) "Discovered write characteristics:%@ for service:, characteristic.UUID, service.UUID% @"); _writeCharacterist Ic = characteristic; / / if save feature written ([self.delegate respondsToSelector:@selector (DidFoundWriteChar:)]) [self.delegate DidFoundWriteChar:characteristic]; break if;}} ([self.delegate respondsToSelector:@selector (DidFoundCharacteristic:withPeripheral:error:)] [self.delegate DidFoundCharacteristic:nil withPeripheral:nil error:nil];})

I believe you should have noticed that the callback function is to start with “did”, these functions do not you call, to achieve the conditions after the system automatically calls.

5 interact with peripheral data (explore and interact)
Send data is very simple, we can encapsulate a function as follows:
Write / / data - (void) writeChar: (NSData *) data writeValue:data forCharacteristic:_writeCharacteristic {[_testPeripheral type:CBCharacteristicWriteWithResponse];}

_testPeripheral and _writeCharacteristic are the features of the devices we saved before and the ability to read and write.

Then we can call outside it, for example, of course I want to measure the body weight, the first group of data packets, and then call the send function:

- sendData *data (void) {NSData = _characteristic.value; if (data) {/ / when the data when only the returned data, otherwise an exception will be thrown into the byte Byte / NSData *byte = (Byte *) [data bytes]; / / remove one two bit Byte b[] = {byte[5], use the byte[6]}; NSData *adata into NSData / / alloc] = [[NSData initWithBytes:b length:sizeof (b)]; NSLog (@ adata =% @ ", adata); / / NSString [adata into a string *str = ConvertToNSString]; TSLog (@"% @ ", STR);}}

Data read is divided into two kinds, one is directly read (reading directly), another is the subscription (subscribe). From the name can basically understand the difference between the two. The actual use of a specific look at the specific application scenarios and the characteristics of their own attributes. A good understanding of the characteristics of the property itself refers to what? The feature has a properties field (, which is an integer value:

Enum {CBCharacteristicPropertyBroadcast = 0x01, CBCharacteristicPropertyRead = 0x02, CBCharacteristicPropertyWriteWithoutResponse = 0x04, CBCharacteristicPropertyWrite = 0x08, CBCharacteristicPropertyNotify = 0x10, CBCharacteristicPropertyIndicate = 0x20, CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40, CBCharacteristicPropertyExtendedProperties = 0x80,};

For example, you want to feature interaction, its properties value is 0x10, that you can only use the subscription to receive data. I’m here to subscribe to the code that starts the subscription as follows:

/ / monitoring equipment - (void) startSubscribe [_testPeripheral setNotifyValue:YES {forCharacteristic:_readCharacteristic]};

When the equipment data returned, also notify me by a system of correction, as shown below:

- (void) peripheral: (CBPeripheral * peripheral) didUpdateValueForCharacteristic: (CBCharacteristic * characteristic) error: (NSError * error) {if (error) {NSLog ("Error updating value for characteristic @% @ error:% @" characteristic.UUID, [error, localizedDescription]); if ([_mainMenuDelegate respondsToSelector:@selector (DidNotifyReadError:)]) [_mainMenuDelegate DidNotifyReadError:error]; return [_recvData;} appendData:characteristic.value]; if ([_recvData length] > / / = 5) received charchar unsigned {*buffer = length (unsigned * charchar) [_recvData bytes]; int nLen = buffer[3]*256 + buffer[4]; if ([_recvData (length] = = nLen+3 +2+2)) {/ / received, notify the agency work if ([_mainMenuDelegate respondsToSelector:@selector [_mainMenuDelegate DidNotifyReadData] (DidNotifyReadData)]);}}}
6 disconnect (disconnect)

This relatively simple, only need a API on the line, the code is as follows:

Active / disconnect device - disConnect (void) {if (_testPeripheral! = Nil) {NSLog (@ "disConnect start"); [self.centerManager cancelPeripheralConnection:_testPeripheral];}}

Six, summary

By a simple Bluetooth development process will go out. Here to add a little bit of how to determine the Bluetooth on and off state. Sorry, this should be written at the beginning. Whatever it is, write it here. Directly on the code.

/ / call center server status update this method - (void) centralManagerDidUpdateState: (CBCentralManager * central) {switch (central.state case CBCentralManagerStatePoweredOff:) {/ / if is closed prompts the user to Bluetooth is turned off, please open the _msg = BLE_OFF; break case CBCentralManagerStatePoweredOn:; _msg = BLE_ON; / / Bluetooth open, you can scan the external equipment. [central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: / / scan peripheral equipment @YES}]; break; default: break;} if (=nil& & _msg! _msg.length! =0) {TSLog (_msg = =% @, @ self.msg); }}

In order to make the interaction better, I added a prompt box UIAlertController. Because you want to use these hardware and mobile phone connection is the need to open the Bluetooth service. When the user does not open the Bluetooth, the reference prompts the user, your application needs to open the bluetooth”. Only when the phone’s Bluetooth is turned on, you can scan the connection, etc.. When we click here, we jump to the Bluetooth settings. The code is as follows:

Check whether to open the Bluetooth [self / / centralManagerDidUpdateState:_centerManager]; if (_centerManager.state = = CBCentralManagerStatePoweredOff) {/ / UIAlertController *alertController pop-up boxes = [UIAlertController alertControllerWithTitle:nil message:@ "you used to open the Bluetooth preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@ style:UIAlertActionStyleDefault handler:^" declined "(UIAlertAction * _Nonnull action) {TSLog (@" refuse "); / / not refuse any treatment}]; UIAlertAction *otherAction = [UIAlertAction actionWithTitle:@ style:UIAlertActionStyleDefault handler:^ (" allow "UIAlertAction * _Nonnull action (@ TSLog) {"allow"); / / allow the user to open the Bluetooth Bluetooth settings page will jump to / / each service on the system set up in NSURL *url URL will be given at the end of "prefs:root=Bluetooth"] = [NSURL URLWithString:@; if ([[UIApplication sharedApplication] canOpenURL:url]) {[[UIApplication sharedApplication] openURL:url]; [alertController addAction:cancelAction];}}]; [alertController addAction:otherAction]; [self presentViewController:alertController animated:YES completion: nil];

IOS system in various settings of the URL link

Of course, this is just a simple process for the development of Bluetooth, if there are any areas where you also please correct. If you have any good suggestions, welcome to point out that we can communicate with each other, and make progress together. Ha ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ^0^