iOS 蓝牙开发(一)

前期回顾

iOS 蓝牙开发(二)
iOS 蓝牙开发(三)
iOS 蓝牙开发(四)

一、基本概念

  • 1.1,中心设备(central):是发起连接的主设备,如:App。
  • 1.2,外设(peripheral):被连接的设备称为外部设备,即外设, 如:体脂称,健康手环等;
  • 1.3,服务(CBService): 外设可以包含一个或多个服务,它是用于实现装置的功能或特征数据相关联的行为集合。
  • 1.4,特征(CBCharacteristic):每个服务可以对应多个特征,它是提供外设服务进一步的细节。
开始前先记录运行后的扫描结果
扫描结果和lightBule的对比

二,蓝牙相关实现

在iOS中蓝牙相关实现都是在CoreBluetooth这个framework中的,所以我们创建一个单例类中需要先导入#import <CoreBluetooth/CoreBluetooth.h>,再后即可使用这个单例类进行管理我们蓝牙的扫描、连接、状态等实现。

  • 2.1, 初始化蓝牙CBCentralManager
        dispatch_queue_t centralQueue = dispatch_queue_create("com.acadsoc.wgazjbuletoothsdk",DISPATCH_QUEUE_SERIAL);
        NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey : [NSNumber numberWithBool:YES], CBCentralManagerOptionRestoreIdentifierKey : @"com.hykj.wgazjbuletoothsdk"};
        self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:options];
                                    
//        self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
        self.resultStr = @"";
        self.services = [[NSMutableArray alloc]init];
  • 2.2,扫描周边可连接蓝牙设备
    当我们在扫描周边外设之前需要判断蓝牙是否可用,在- (void)centralManagerDidUpdateState:(CBCentralManager *)central函数中进行获取设备蓝牙的更新。

判断手机蓝牙状态
CBManagerStateUnknown = 0, 未知
CBManagerStateResetting, 重置中
CBManagerStateUnsupported, 不支持
CBManagerStateUnauthorized, 未验证
CBManagerStatePoweredOff, 未启动
CBManagerStatePoweredOn, 可用

central.state为CBManagerStatePoweredOn即可开始扫描, 具体方法[self.centralManager scanForPeripheralsWithServices:nil options:nil]当调用scanForPeripheralsWithServices:options:函数时就会实时调用其代理方法- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    
    if (self.stateUpdateBlock) {
        self.stateUpdateBlock(central.state);
    }
    switch (central.state)
    {
        case CBManagerStatePoweredOn:

            NSLog(@"蓝牙已开启");
            // 根据SERVICE_UUID来扫描外设,如果不设置SERVICE_UUID,则扫描所有蓝牙设备
            // 第一个参数为CBUUID的数组,需要搜索特点服务的蓝牙设备,只要每搜索到一个符合条件的蓝牙设备都会调用didDiscoverPeripheral代理方法
            [self startScan];
            break;
        case CBManagerStatePoweredOff:
            
            NSLog(@"蓝牙已关闭, 请打开蓝牙");
            break;
        case CBManagerStateUnsupported:
            NSLog(@"设备不支持蓝牙");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@"应用尚未被授权使用蓝牙");
            break;
        case CBManagerStateUnknown:
            NSLog(@"未知错误,请重新开启蓝牙");
            break;
        case CBManagerStateResetting:
            NSLog(@"蓝牙重置中");
            [self stopScan];
            break;
        default:
            NSLog(@"Central Manager did change state");
            break;
    }
}

// 开始扫描周围可用蓝牙
- (void)startScan {
    
    //不重复扫描已发现设备
    //CBCentralManagerScanOptionAllowDuplicatesKey设置为NO表示不重复扫瞄已发现设备,为YES就是允许。
    //CBCentralManagerOptionShowPowerAlertKey设置为YES就是在蓝牙未打开的时候显示弹框
    NSDictionary *option = @{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:NO],CBCentralManagerOptionShowPowerAlertKey:[NSNumber numberWithBool:YES]};
    // 第一个参数填nil代表扫描所有蓝牙设备,第二个参数options也可以写nil
    [self.centralManager scanForPeripheralsWithServices:nil options:option];
}

// 扫描外设的代理方法,在该函数中揭开筛选出周边的蓝牙外设
// 在蓝牙于后台被杀掉时,重连之后会首先调用此方法,可以获取蓝牙恢复时的各种状态
- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI
{
    NSString *perName = [[NSUserDefaults standardUserDefaults] objectForKey:@"conPeripheral"];
    NSString *setOrDelNum = [[NSUserDefaults standardUserDefaults] objectForKey:@"setOrDel"];

    // 检索到设备
    if (self.discoverPeripheralBlcok) {
        if (self.prefixString.length > 0) {
            if ([peripheral.name hasPrefix:self.prefixString]) {
                self.discoverPeripheralBlcok(central,peripheral,advertisementData,RSSI);
            }
        } else {
            self.discoverPeripheralBlcok(central,peripheral,advertisementData,RSSI);
        }
        [self startScan];
    }
    if ([setOrDelNum isEqualToString:@"0"]) {
        //有自动重连的设备
        [[NSNotificationCenter defaultCenter]postNotificationName:PostAutoConnectionNotificaiton object:nil];
        if ([peripheral.name isEqualToString:perName]) {
            self.peripheral = peripheral;
            [self.centralManager connectPeripheral:peripheral options:nil];
        }
    }
}

peripheral是外设类advertisementData是广播的值,一般携带设备名,serviceUUID等信息。RSSI绝对值越大,表示信号越差,设备离的越远。如果想装换成百分比强度,(RSSI+100)/1001(这是一个约数,蓝牙信号值并不一定是-100 - 0的值)

3,连接

蓝牙的连接是当中心设备扫描到可用外设后, 利用函数[self.centralManager connectPeripheral:peripheral options:nil];进行链接, 当函数被调用后, 就会回调其对应的代理函数。

  • 3.1,链接成功后的回调
// 蓝牙设备连接成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    [self.centralManager stopScan];
    [self.peripheral setDelegate:self];
    [self.peripheral discoverServices:nil];
    
    //延时操作
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (self.connectSuccessBlock) {
            self.connectSuccessBlock(peripheral,nil,self.writeCharacteristic);
        } else {
            //返回连接成功
            if ([self.delegate respondsToSelector:@selector(automaticConnectionWithPerpheral:)]) {
                [self.delegate automaticConnectionWithPerpheral:peripheral];
            }
        }
    });
}
  • 3.2, 链接失败后的回调
// 连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    if (self.connectFailureBlock) {
        self.connectFailureBlock(peripheral,error);
    }
}

4, 其他函数和代理方法

  • 4.1,断开链接
// 断开蓝牙连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    [self disconectPeripheral];
    if (error)
        {
        NSLog(@">>> didDisconnectPeripheral for %@ with error: %@", peripheral.name, [error localizedDescription]);
        }
}

// 断开链接
- (void)disconectPeripheral {
    
    if (self.peripheral) {
        [self.centralManager cancelPeripheralConnection:self.peripheral];
    }
}
  • 4.2,停止扫描
// 停止扫描
- (void)stopScan
{
    [self.centralManager stopScan];
}

5,中心管理供给外界使用方法

// 单例
+ (ZJAWGBluetoothManager *)defaultManager;

/**
 当前蓝牙的状态
 
 @param state  状态
 */
- (void)returnBluetoothStateWithBlock:(BTStateUpdateBlock)state;

/**
 搜索蓝牙外设, 每次回调表示返回一个蓝牙外设信息
 
 @param name  模糊搜索设备名称, 即目标设备名称包含的字段
 @param discoverBlock  搜索到蓝牙外设后的回调
 */
- (void)scanPeripheralsWithName:(NSString *)name
               discoverPeripheral:(BTDiscoverPeripheralBlock)discoverBlock;

/**
 搜索蓝牙外设
 
 @param discoverBlock  搜索蓝牙外设
 */
- (void)scanPeripheralsWithDiscoverPeripheral:(BTDiscoverPeripheralBlock)discoverBlock;

/**
 连接某个蓝牙外设,并查询服务,特性,服务等描述
 
 @param peripheral  要连接的蓝牙外设
 @param complete  连接成功后的回调
 @param failure  连接失败后的回调
 */
- (void)connectPeripheral:(CBPeripheral *)peripheral
                 complete:(BTConnectSuccessBlock)complete
                  failure:(BTConnectFailureBlock)failure;

总结

本篇笔记主要是记录如何初始化蓝牙的CBCentralManager的中心管理类,并记录如何实现扫描周边外设、如何链接、获取蓝牙当前状态。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容