蓝牙(CoreBluetooth) - Obj-C

  • iOS中提供了4个框架用于实现蓝牙连接:

1.GameKit.framework(用法简单,只能用于iOS设备间,iOS 7过期)
2.MultipeerConnectivity.framework(只能iOS设备间,iOS 7用来替代GameKit,WiFi蓝牙都支持,WiFi优先级高)
3.ExternalAccessory.framework(可用于第三方蓝牙设备交互,但需要蓝牙设备经过苹果MFi认证)
4.CoreBluetooth(可用于第三方蓝牙设备交互,必须要支持蓝牙4.0)

当前主要使用CoreBluetooth(CoreBluetooth下无法使用模拟器进行演示)

蓝牙使用时需要两个两个设备,一个作为中心,一个作为外设,作为手机端,既可以作为外设,也可以作为中心,这里主要演示手机作为中心设备的场景

  • CoreBluetooth实现的具体步骤主要有:
    1.创建中央管理者
    2.扫描外设
    3.连接外设
    4.查找服务
    5.查找特征
    6.读写数据

接收数据的示例代码:

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController () <CBCentralManagerDelegate,CBPeripheralDelegate>
// 扫描蓝牙设备按钮
@property (weak, nonatomic) IBOutlet UIButton *scanBtn;
// 中央管理者(自己的设备)
@property (nonatomic,strong) CBCentralManager *centralManager;
// 外设(相对自己,手机端需要去连接的设备)
@property (nonatomic,strong) CBPeripheral *peripheral;
@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建一个中央管理者 (传递nil,将使用主队列)
    self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
    
    self.scanBtn.enabled = NO;
}


// 扫描蓝牙
- (IBAction)scanBluetoothDevice{
    
    // 2. 扫描外设  (传递nil 扫描所有外设)
    [self.centralManager scanForPeripheralsWithServices:nil options:nil];
    
}

#pragma mark - CBCentralManagerDelegate

// 中央管理者已经更新状态后调用
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    
    /*
         CBCentralManagerStateUnknown = 0,  未知
         CBCentralManagerStateResetting,    正在重启
         CBCentralManagerStateUnsupported,  不支持
         CBCentralManagerStateUnauthorized, 未授权
         CBCentralManagerStatePoweredOff,   关闭蓝牙
         CBCentralManagerStatePoweredOn,    开启蓝牙  只有该状态才是正常情况
     */
    if (central.state == CBCentralManagerStatePoweredOn) { // 蓝牙开启
        
        // 当蓝牙开启时,扫描蓝牙
        self.scanBtn.enabled = YES;
        
    }
    
}
/**
 *  已经发现某个外设后调用
 *
 *  @param central           中央管理者
 *  @param peripheral        外设
 *  @param advertisementData 广播数据
 *  @param RSSI              信号强度 分贝
 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    
    // 3. 连接外设(使用场景:显示搜索到的蓝牙设备列表,UI展示供用户选择,判断名称后进行连接)
    
    /*
         NSString *const CBAdvertisementDataLocalNameKey;
         NSString *const CBAdvertisementDataManufacturerDataKey;
         NSString *const CBAdvertisementDataServiceDataKey;
         NSString *const CBAdvertisementDataServiceUUIDsKey;
         NSString *const CBAdvertisementDataOverflowServiceUUIDsKey;
         NSString *const CBAdvertisementDataTxPowerLevelKey;
         NSString *const CBAdvertisementDataIsConnectable;
         NSString *const CBAdvertisementDataSolicitedServiceUUIDsKey;
     */
    if ([advertisementData[CBAdvertisementDataLocalNameKey] isEqualToString:@"外设名称"]) {
        // 在查找到需要的设备后停止扫描外设
        [self.centralManager stopScan];
        // 连接外设
        [self.centralManager connectPeripheral:peripheral options:nil];
        // 记录外设
        self.peripheral = peripheral;
        
    }
    
}

/**
 *  已经连接到外设后调用
 *
 *  @param central    中央管理者
 *  @param peripheral 外设
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    
    // 4. 查找服务  (传递nil,查找所有的服务)
    [peripheral discoverServices:nil];
    
    // 获取数据(查找的),设置外设的代理
    peripheral.delegate = self;
    
}

#pragma mark - CBPeripheralDelegate
/**
 *  已经查找到服务后调用
 *
 *  @param peripheral 外设
 *  @param error      错误信息
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    
    NSArray *serivicesArr = peripheral.services;
    // 遍历服务,查找指定的所务
    for (CBService *service in serivicesArr) {
        
        if ([service.UUID.UUIDString isEqualToString:@"服务的UUID"] ) {
            
            // 5. 查找特征
            [peripheral discoverCharacteristics:nil forService:service];
            
        }
    }
}
// 已经查找到特征后调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    
    // 判断特征的UUID是否是需求的特征
    for (CBCharacteristic *characteristic in service.characteristics) {
        
        if ([characteristic.UUID.UUIDString isEqualToString:@"特征的UUID"]) {
            
            // 6. 收发数据(读写数据)
            
            // 读
            [peripheral readValueForCharacteristic:characteristic];
            
        }
    }
}
// 当已经获取的更新的特征的数据后调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    NSData *data = characteristic.value;
    NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    
    
}
@end

如果需要发送数据,在didUpdateValueForCharacteristic中调用writeValue forCharacteristic方法

- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;

如果需要回应,发送数据时的类型需要为:CBCharacteristicWriteWithResponse

// 已经发送成功后调用
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    NSLog(@"发送成功");
    
}

完整的发送数据实例代码:

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController () <CBCentralManagerDelegate,CBPeripheralDelegate>
// 扫描蓝牙设备按钮
@property (weak, nonatomic) IBOutlet UIButton *scanBtn;
// 中央管理者(自己的设备)
@property (nonatomic,strong) CBCentralManager *centralManager;
// 外设
@property (nonatomic,strong) CBPeripheral *peripheral;
@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建一个中央管理者 (传递nil,将使用主队列)
    self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
    
    self.scanBtn.enabled = NO;
    
    
}


// 扫描蓝牙
- (IBAction)scanBluetoothDevice{
    
    // 2. 扫描外设  (传递nil 扫描所有外设)
    [self.centralManager scanForPeripheralsWithServices:nil options:nil];
    
}

#pragma mark - CBCentralManagerDelegate

// 中央管理者已经更新状态后调用
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    
    /*
         CBCentralManagerStateUnknown = 0,  未知
         CBCentralManagerStateResetting,    正在重启
         CBCentralManagerStateUnsupported,  不支持
         CBCentralManagerStateUnauthorized, 未授权
         CBCentralManagerStatePoweredOff,   关闭蓝牙
         CBCentralManagerStatePoweredOn,    开启蓝牙  只有该状态才是正常情况
     */
    if (central.state == CBCentralManagerStatePoweredOn) { // 蓝牙开启
        
        // 当蓝牙开启时,扫描蓝牙
        self.scanBtn.enabled = YES;
        
    }
    
}
/**
 *  已经发现某个外设后调用
 *
 *  @param central           中央管理者
 *  @param peripheral        外设
 *  @param advertisementData 广播数据
 *  @param RSSI              信号强度 分贝
 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    
    // 3. 连接外设(使用场景:显示搜索到的蓝牙设备列表,UI展示供用户选择,判断名称后进行连接)
    
    /*
         NSString *const CBAdvertisementDataLocalNameKey;
         NSString *const CBAdvertisementDataManufacturerDataKey;
         NSString *const CBAdvertisementDataServiceDataKey;
         NSString *const CBAdvertisementDataServiceUUIDsKey;
         NSString *const CBAdvertisementDataOverflowServiceUUIDsKey;
         NSString *const CBAdvertisementDataTxPowerLevelKey;
         NSString *const CBAdvertisementDataIsConnectable;
         NSString *const CBAdvertisementDataSolicitedServiceUUIDsKey;
     */
    if ([advertisementData[CBAdvertisementDataLocalNameKey] isEqualToString:@"外设名称"]) {
        
        // 连接外设
        [self.centralManager connectPeripheral:peripheral options:nil];
        // 记录外设
        self.peripheral = peripheral;
        
    }
    
}

/**
 *  已经连接到外设后调用
 *
 *  @param central    中央管理者
 *  @param peripheral 外设
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    
    // 4. 查找服务  (传递nil,查找所有的服务)
    [peripheral discoverServices:nil];
    
    // 获取数据(查找的),设置外设的代理
    peripheral.delegate = self;
    
}

#pragma mark - CBPeripheralDelegate
/**
 *  已经查找到服务后调用
 *
 *  @param peripheral 外设
 *  @param error      错误信息
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    
    NSArray *serivicesArr = peripheral.services;
    // 遍历服务,查找指定的所务
    for (CBService *service in serivicesArr) {
        
        if ([service.UUID.UUIDString isEqualToString:@"服务的UUID"] ) {
            
            // 5. 查找特征
            [peripheral discoverCharacteristics:nil forService:service];
            
        }
    }
}
// 已经查找到特征后调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    
    // 判断特征的UUID是否是需求的特征
    for (CBCharacteristic *characteristic in service.characteristics) {
        
        if ([characteristic.UUID.UUIDString isEqualToString:@"特征的UUID"]) {
            
            // 6. 收发数据(读写数据)
            
            // 读
            [peripheral readValueForCharacteristic:characteristic];
            
        }
    }
}
// 当已经获取的更新的特征的数据后调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    // 发送数据
    NSString *write = @"发送数据";
    /*
     CBCharacteristicWriteWithResponse = 0, 回应
     CBCharacteristicWriteWithoutResponse,  只发送,不知道是否成功
     */
    [peripheral writeValue:[write dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    
    
}
// 已经发送成功后调用
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    NSLog(@"发送成功");
}
@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容