ios Bluetooth Development (2) Code implementation of ios connection peripheral

Keywords: iOS xcode emulator Mobile

Original web address

The last article introduced the technical knowledge of Bluetooth, and here we describe the application scenario of central mode in detail.Main device (mobile phone scans connected peripherals, discovers peripheral services and attributes, operates applications of services and attributes.Generally speaking, peripherals (such as Bluetooth devices, such as smart handrings, etc.) are developed by hardware engineers and the services provided by the devices are defined. For each service, the attributes of each feature (read-only, write-only, notification, etc.). The business scenario for this example is to read and write Bluetooth devices using a mobile app.

Code implementation process for ios connection peripherals

1. Establish a central role
 2. Scan peripherals (discover)
3. Connect peripherals
 4. Scan peripherals for services and features (discover)
    - 4.1 Get peripheral services
    - 4.2 Get the Characteristics of the peripheral, get the values of Characteristics, get the values of Descriptor and Descriptor of Characteristics
 5. Explore and interact with peripherals
 6. Subscribe to notifications from Characteristic
 7. Disconnect

Prepare the environment

  1 xcode
  2 Develop certificates and mobile phones (Bluetooth programs need to be debugged using real machines, and simulators can be used, but the method is painful, I'll put it last)
  3Bluetooth peripheral

Implementation Steps

1 Import the CoreBluetooth header file, set up the main device management class, and set up the main device delegation

    #import <CoreBluetooth/CoreBluetooth.h>
    @interface ViewController : UIViewController<CBCentralManagerDelegate>


    @interface ViewController (){
        //System Bluetooth device management object, you can understand him as the main device, through him, you can scan and link peripherals
        CBCentralManager *manager;
        //Used to save discovered devices
        NSMutableArray *peripherals;
    }

    - (void)viewDidLoad {
        [super viewDidLoad];
        /*
         Set delegation for master device, CBCentralManagerDelegate
            Must be achieved:
            - (void)centralManagerDidUpdateState:(CBCentralManager *)central;//Delegation for state change of primary device, suitable for initializing CBCentralManager, opens the device and can only be used if the device is properly opened
            More important among delegates that choose to implement:
            - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //Delegation to find peripherals
            - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//Delegates Connecting Peripherals Successfully
            - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//Delegation with peripheral connection failure
            - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//Disconnect delegation from peripherals
        */
         //Initializes and sets delegates and thread queues, preferably with nil as the parameter for one thread and main thread as the default
         manager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];


2Scan peripherals (discover). The method of scanning peripherals is placed in the delegation of the successful opening of the centralManager, because scanning can only start if the device is successfully opened, otherwise an error will be reported.

        -(void)centralManagerDidUpdateState:(CBCentralManager *)central{

            switch (central.state) {
                case CBCentralManagerStateUnknown:
                    NSLog(@">>>CBCentralManagerStateUnknown");
                    break;
                case CBCentralManagerStateResetting:
                    NSLog(@">>>CBCentralManagerStateResetting");
                    break;
                case CBCentralManagerStateUnsupported:
                    NSLog(@">>>CBCentralManagerStateUnsupported");
                    break;
                case CBCentralManagerStateUnauthorized:
                    NSLog(@">>>CBCentralManagerStateUnauthorized");
                    break;
                case CBCentralManagerStatePoweredOff:
                    NSLog(@">>>CBCentralManagerStatePoweredOff");
                    break;
                case CBCentralManagerStatePoweredOn:
                    NSLog(@">>>CBCentralManagerStatePoweredOn");
                    //Start scanning around peripherals
                    /*
                     The first parameter, nil, scans all the peripherals around it and enters when scanned
                          - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;
                     */
                    [manager scanForPeripheralsWithServices:nil options:nil];

                    break;
                default:
                    break;
            }

        }

        //Scanning to the device will enter the method
        -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{

            NSLog(@"When Scanning to Device:%@",peripheral.name);
            //Next you can connect the device

        }

3 Connect peripherals

        //Scanning to the device will enter the method
        -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{

            //Connect to our test device, if you don't have one, you can download an app called lightbule to simulate a device
            //Here I set the connection rules myself. I set the device that starts with P
                   if ([peripheral.name hasPrefix:@"P"]){
                   /*
                       A primary device can connect up to 7 peripherals, each peripheral can only connect to a primary device at most. Connection succeeds, fails, disconnections enter their respective delegation
                    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//Delegates Connecting Peripherals Successfully
                    - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//Delegation with peripheral connection failure
                    - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//Disconnect delegation from peripherals
                    */

                    //The device found must hold it, otherwise peripheral will not be saved in CBCentralManager, and methods in CBPeripheralDelegate will not be called!!
                    [peripherals addObject:peripheral];
                    //Connect device
                   [manager connectPeripheral:peripheral options:nil];
               }

        }


        //Connect to Peripherals - Success
        - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
        {
            NSLog(@">>>Connect to a connection named (%@)Equipment-Success",peripheral.name);
        }

        //Connect to Peripherals - Failed
        -(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
        {
            NSLog(@">>>Connect to a connection named (%@)Equipment-fail,Reason:%@",[peripheral name],[error localizedDescription]);
        }

        //Peripherals Disconnect
        - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
            NSLog(@">>>Peripheral disconnection %@: %@\n", [peripheral name], [error localizedDescription]);

        }



One point is very easy to make mistakes, please note.This line is part of the didDiscoverPeripheral delegation

   //The device found must hold it, otherwise peripheral will not be saved in CBCentralManager, and methods in CBPeripheralDelegate will not be called!!
    [peripherals addObject:peripheral];

Please note that if you don't save it, it will affect the subsequent methods. Many people in this place make mistakes, which almost every day in my Bluetooth communication group will result in no connection and subsequent operations on peripherals.

You can also take a look at the xcode description of this delegation, focusing on the @discussion content, which specifically indicates the need for retained objects.

/*!
 *  @method centralManager:didDiscoverPeripheral:advertisementData:RSSI:
 *
 *  @param central              The central manager providing this update.
 *  @param peripheral           A <code>CBPeripheral</code> object.
 *  @param advertisementData    A dictionary containing any advertisement and scan response data.
 *  @param RSSI                 The current RSSI of <i>peripheral</i>, in dBm. A value of <code>127</code> is reserved and indicates the RSSI
 *								was not available.
 *
 *  @discussion                 This method is invoked while scanning, upon the discovery of <i>peripheral</i> by <i>central</i>. A discovered peripheral must
 *                              be retained in order to use it; otherwise, it is assumed to not be of interest and will be cleaned up by the central manager. For
 *                              a list of <i>advertisementData</i> keys, see {@link CBAdvertisementDataLocalNameKey} and other similar constants.
 *
 *  @seealso                    CBAdvertisementData.h
 *
 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI;

4 Scan services and features in peripherals (discover)

Once the device is connected successfully, the service of the device can be scanned, which is also in the form of delegation. When the result is scanned, it enters the delegation method.However, this delegation is no longer a delegate for the primary device (CBCentralManagerDelegate), but a delegate for the peripheral device (CBPeripheralDelegate), which contains many callback methods for the interaction between the primary device and the peripheral, including getting services, getting features, getting values for characteristics, getting values for the Characteristics'Descriptor, and writing data, read rssi, subscribe to data by notification, etc.

4.1 Getting services for peripherals

        //Connect to Peripherals - Success
        - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
        {
            NSLog(@">>>Connect to a connection named (%@)Equipment-Success",peripheral.name);
            //Set peripheral delegate CBPeripheralDelegate
            //@interface ViewController : UIViewController<CBCentralManagerDelegate,CBPeripheralDelegate>
            [peripheral setDelegate:self];
            //Scan the peripheral Services and enter the method after success: -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
            [peripheral discoverServices:nil];

        }

        //Scan to Services
        -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
            //  NSLog (@ ">>> Scan to Service:%@", peripheral.services);
            if (error)
            {
                NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
                return;
            }

            for (CBService *service in peripheral.services) {
                             NSLog(@"%@",service.UUID);
                             //Scan Characteristics for each service and enter the method: -(void) peripheral:(CBPeripheral *) peripheral didDiscoverCharacteristicsForService:(CBService *) service error:(NSError *)
                             [peripheral discoverCharacteristics:nil forService:service];
                         }

        }


4.2 Get the Characteristics of the peripheral, get the value of Characteristics, get the values of Descriptor and Descriptor of Characteristics

     //Scan to Characteristics
     -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
         if (error)
         {
             NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
             return;
         }

         for (CBCharacteristic *characteristic in service.characteristics)
         {
             NSLog(@"service:%@ Of Characteristic: %@",service.UUID,characteristic.UUID);
         }

         //Get the value of Characteristic and read the data into the method: -(void) peripheral:(CBPeripheral *) peripheral didUpdateValueForCharacteristic:(CBCharacteristic *) characteristic error:(NSError *)
         for (CBCharacteristic *characteristic in service.characteristics){
             {
                 [peripheral readValueForCharacteristic:characteristic];
             }
         }

         //Search for Characteristic's Descriptors and read the data into the method: -(void) peripheral:(CBPeripheral *) peripheral didDiscoverDescriptors ForCharacteristic:(CBCharacteristic *) characteristic error:(NSError *)
         for (CBCharacteristic *characteristic in service.characteristics){
             [peripheral discoverDescriptorsForCharacteristic:characteristic];
         }


     }

    //Get the value of charateristic
    -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        //Print out UUID s and values for characteristic
        //Note that the value type is NSData, and when developed, the data will be parsed according to the way the peripheral protocol is developed.
        NSLog(@"characteristic uuid:%@  value:%@",characteristic.UUID,characteristic.value);

    }

    //Search for Characteristic's Descriptors
    -(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

        //Print out Characteristic and his Descriptors
         NSLog(@"characteristic uuid:%@",characteristic.UUID);
        for (CBDescriptor *d in characteristic.descriptors) {
            NSLog(@"Descriptor uuid:%@",d.UUID);
        }

    }
    //Get the value of Descriptors
    -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
        //Print out DescriptorsUUID and value
        //This descriptor is all a description of a characteristic, usually a string, so here we convert it to a string to parse it
        NSLog(@"characteristic uuid:%@  value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);
    }


5 Write data into Characteristic

    //Write data
    -(void)writeCharacteristic:(CBPeripheral *)peripheral
                characteristic:(CBCharacteristic *)characteristic
                         value:(NSData *)value{

        //Print out the permissions of characteristic, you can see that there are many kinds, this is NS_OPTIONS, which can be used for several values at the same time. The common ones are read, write, notify, indicate. Knowing that these are basic enough, the first one is read and write permission, the last two are notifications, two different ways of notification.
        /*
         typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
         CBCharacteristicPropertyBroadcast												= 0x01,
         CBCharacteristicPropertyRead													= 0x02,
         CBCharacteristicPropertyWriteWithoutResponse									= 0x04,
         CBCharacteristicPropertyWrite													= 0x08,
         CBCharacteristicPropertyNotify													= 0x10,
         CBCharacteristicPropertyIndicate												= 0x20,
         CBCharacteristicPropertyAuthenticatedSignedWrites								= 0x40,
         CBCharacteristicPropertyExtendedProperties										= 0x80,
         CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)		= 0x100,
         CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)	= 0x200
         };

         */
        NSLog(@"%lu", (unsigned long)characteristic.properties);


        //Only characteristic.properties can be written with write permission
        if(characteristic.properties & CBCharacteristicPropertyWrite){
            /*
                The best type parameter can be CBCharacteristicWriteWithResponse or type:CBCharacteristicWriteWithResponse, the difference is whether there is feedback
            */
            [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
        }else{
            NSLog(@"This field is not writable!");
        }


    }

6 Subscribe to notifications from Characteristic

    //Set Notification
    -(void)notifyCharacteristic:(CBPeripheral *)peripheral
                characteristic:(CBCharacteristic *)characteristic{
        //Set notification, data notification will enter: didUpdateValueForCharacteristic method
        [peripheral setNotifyValue:YES forCharacteristic:characteristic];

    }

    //Cancel Notification
    -(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
                 characteristic:(CBCharacteristic *)characteristic{

         [peripheral setNotifyValue:NO forCharacteristic:characteristic];
    }




7 Disconnect

    //Stop scanning and disconnect
    -(void)disconnectPeripheral:(CBCentralManager *)centralManager
                     peripheral:(CBPeripheral *)peripheral{
        //Stop Scanning
        [centralManager stopScan];
        //Disconnect
        [centralManager cancelPeripheralConnection:peripheral];
    }



8 Simulator Bluetooth debugging, use carefully, it is best to debug with real machine.

    Since BLE is only supported on iOS after the 4S of the iPhone, these new generation iOS devices are not cheap, so debugging with an iOS emulator during testing can save some development costs.How to debug BLE on iOS emulator,
    Apple originally gave us the instructions that a BLE-enabled mac can be debugged with an emulator and gave us a technical document (portal). The nauseous thing was that Apple then blew out and removed the document.
    BLE support on the iOS 7.0 simulator has also been removed (would you like to buy more device tests?Apple sucks.) After that, I searched the Internet for the following solutions:
    1. Buy a CSR Bluetooth 4.0 USB adapter (about $30 on a treasure) and insert it into the machine (you know)
    2. Restart Mac by typing sudo NVRAM bluetoothHostController SwitchBehavior="never" under Terminal.
    3. Debug the code with XCode 4.6 and run the program on the iOS 6.1 emulator (running the iOS 7.0 emulator with XCode 5.0 will throw an exception, as detailed above, Apple sucks, you know)

    How can I reduce the IOS version of the simulator?
    There are many simulators in XCode->Preferences->Downloads that you can download
    Select a 6.1 download

Code download:

Most of the sample code in my blog was uploaded to GitHub at https://github.com/coolnameismy/demo. Click on the jump code download address

The code store directory for this article is BleDemo

babyBluetooth Group

  • qq AC Group 6: 284341984
  • qq AC Group 5: 426082944 (full)
  • qq AC Group 4: 313084771 (full)
  • qq AC Group 3:530142592 (full)
  • qq AC Group 2:168756967 (full)
  • qq AC Group 1:426603940 (full)

Last

Thank you for watching. If it helps you, please follow and star on github , published in Liu Yanwei's Technology Blog , please indicate the source

Posted by croakingtoad on Wed, 12 Jun 2019 09:31:49 -0700