iOS BLE(蓝牙4.0) 读取埃微i5智能手环步数的简单实现

  • 开发前:
    • 1、profile
      profile可以理解为一种规范,一个标准的通信协议,它存在于从机中。蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器 ,心率计等。每个profile中会包含多个service,每个service代表从机的一种能力。

    • 2、service
      service可以理解为一个服务,在ble从机中,通过有多个服务,例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,所以会通过电量的characteristic特征值存在从机的profile里,这样主机就可以通过这个characteristic来读取80%这个数据

    • 3、characteristic
      characteristic特征值,ble主从机的通信均是通过characteristic来实现,可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。

    • 4、UUID
      UUID,统一识别码,我们刚才提到的service和characteristic,都需要一个唯一的uuid来标识

    • 整理一下,每个从机都会有一个叫做profile的东西存在,不管是上面的自定义的simpleprofile,还是标准的防丢器profile,他们都是由一些列service组成,然后每个service又包含了多个characteristic,主机和从机之间的通信,均是通过characteristic来实现。

  • 1 懒加载创建中心设备 (中心设备一般是手机本身))
/**
 *  懒加载 初始化中心设备 CBCentralManager
 *
 *  @return 中心设备
 */
- (CBCentralManager *)centralManager {
    if (!_centralManager) {
        _centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil options:nil];
    }
    return _centralManager;
}
  • 2 扫描外设并判断蓝牙开启状态及设备是否支持BLE(在需要扫描的地方调用该方法, 比如点击扫描按钮)
- (void)scanPeripheral {
    // 2.扫描外设
    if(self.centralManager.state == CBCentralManagerStatePoweredOff) {           // 蓝牙关闭状态
        
        [[[UIAlertView alloc] initWithTitle:@"蓝牙是关闭状态"
                                    message:@"请打开蓝牙"
                                   delegate:self
                          cancelButtonTitle:@"dismiss"
                          otherButtonTitles: nil] show];
        
    } else if(self.centralManager.state == CBCentralManagerStateUnsupported) {   // 设备蓝牙不支持
        
        [[[UIAlertView alloc] initWithTitle:@"设备蓝牙不支持"
                                    message:@"必须 iPhone4S 以上的设备才支持蓝牙4.0"
                                   delegate:self
                          cancelButtonTitle:@"dismiss"
                          otherButtonTitles: nil] show];
        
    } else if(self.centralManager.state == CBCentralManagerStatePoweredOn) {    // 蓝牙打开状态
        if (self.peripherals.count) {
            // 连接外设
            [self.centralManager connectPeripheral:[self.peripherals firstObject] options:nil];
            return;
        }
        NSLog(@"蓝牙已经打开, 正在搜索中...");
        self.connectStateLabel.text = @"正在搜索外设中...";
        // 如果第一个参数为nil, 那么将会扫描所有可用的外围设备, 不过这样会很慢
        [self.centralManager scanForPeripheralsWithServices:nil
                                                    options:nil];
    }
}
  • 3 必须实现CBCentralManager的一个代理方法, 在里边调用步骤2的方法
/**
 *  如果蓝牙状态改变, 会在这个方法回调
 *
 *  @param central 中心设备(一般为你的iPhone)
 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {

    [self scanPeripheral];
}
  • 4 实现CBCentralManager一个代理方法, 如果扫描到外设会在这个方法中获取外设的信息, 并且连接外设
/**
 *  这个代理方法中可以获取外设的信息
 *  4. 可以这里连接外设
 *  @param central           中心设备
 *  @param peripheral        外设
 *  @param advertisementData
 *  @param RSSI
 */
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    
    NSLog(@"已经搜索到设备, 正在连接中...");
    
    self.connectStateLabel.text = @"正在连接设备...";
    
    // 这里可以停止扫描外围设备
    [self.centralManager stopScan];
    
    if (![self.peripherals containsObject:peripheral]) {
        
        NSLog(@"外设名称: %@", peripheral.name);
        
        // 显示设备名称
        [self setUpName:peripheral.name];
        
        peripheral.delegate = self;
        
        // 应该保留外设, 否则会被释放
        [self.peripherals addObject:peripheral];

    }
    
    // 连接外设
    [self.centralManager connectPeripheral:peripheral options:nil];
    
}
  • 5 实现CBCentralManager的一个代理方法, 如果连接外设成功会回调这个方法, 在这个方法中扫描外设中的服务
/**
 *  如果连接成功的话会回调这个方法
 *  5. 扫描外设中的服务
 *  @param central 中心设备
 *  @param peripheral 外设
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    
    self.connectStateLabel.text = @"连接成功, 同步数据中...";
    
    // 查找服务
    [peripheral discoverServices:nil];
    
}
  • 6 实现CBCentralManager的一个代理方法, 如果连接失败会回调这个方法
/**
 *  连接失败
 *
 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    
    self.connectStateLabel.text = @"连接失败...";
    
    self.deviceNameKeyLabel.hidden = YES;
    self.deviceNameValueLabel.hidden = YES;
    
    [self scanPeripheral];
}
  • 7 实现CBPeripheral的一个代理方法, 从外设的services属性中获取服务列表, 从而获取到想要的服务, 并从中调用查找特征的方法
/**
 *  7. 从外设的services属性中获取服务列表
 *
 *  @param peripheral 外设
 *  @param error      错误信息
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    
    NSLog(@"已经获取到服务列表, 正在匹配服务中...");
    
    if (error) {
        NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
        
//        if ([self.delegate respondsToSelector:@selector(DidNotifyFailConnectService:withPeripheral:error:)])
//            [self.delegate DidNotifyFailConnectService:nil withPeripheral:nil error:nil];
        return;
    }
    
    // 遍历服务
    for (CBService *service in peripheral.services) {
        NSLog(@"%@", service.UUID);
        
//        [peripheral discoverCharacteristics:nil forService:service];
        // 找到对应的服务
        if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FF20"]]) {
//            NSLog(@"Service found with UUID: %@", service.UUID);
            // 查找特征
            [peripheral discoverCharacteristics:nil forService:service];
            break;
        }

    }
    
}
  • 8 实现CBPeripheral的一个代理方法, 如果找到服务中的特征则会回调这个方法
/**
 *  返回已经发现的特性的代理方法
 *  8. 发现服务中的特征
 *  @param peripheral 外设
 *  @param service    服务
 *  @param error      错误信息
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    
    if (error) {
        NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
        return;
    }
    
//    NSLog(@"\n服务: %@", service.UUID);
    // 从服务中遍历特征
    for (CBCharacteristic *characteristic in service.characteristics) {
//        [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FF22"]]) {
            // 这里要注意有些特征可读, 有些特征可写, 有些可以发通知, 而不是随便调用读写或者发通知的方法的
            // [peripheral readValueForCharacteristic:characteristic];
            // [peripheral discoverDescriptorsForCharacteristic:characteristic];
            // 发送通知
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }

    }
}
  • 9 与外设进行数据交互(对于埃微智能手环, 这个特征中返回的字节数肯可能小于20, 那些情况没有分析, 所以暂且过滤掉, 如果返回20个字节的话, 那么第8, 9位存储步数; 注意, 这里仅仅针对埃微智能手环进行的数据分析)
/**
 *  9.与外设进行数据交互
 *
 *  @param peripheral     外设
 *  @param characteristic 特征
 *  @param error          错误信息
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    
    if (error) {
        NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
        return;
    }
    
    NSData *data = characteristic.value;
    char scartchVal[data.length];
    int16_t dataTemp;
    [data getBytes:&scartchVal length:data.length];
    
    long len = sizeof(scartchVal) / sizeof(scartchVal[0]);
    
    // 可能返回的字节数小于20, 那些情况没有分析, 所以暂且过滤掉
    if ((sizeof(scartchVal) / sizeof(scartchVal[0])) == 20) {
        // 对于埃微智能手环, 如果返回20个字节的话, 那么第8, 9位存储步数
        dataTemp = ((scartchVal[8] & 0xff) + ((scartchVal[9] << 8) & 0xff00));
        self.connectStateLabel.text = @"数据同步成功";
        self.stepLabel.text = [NSString stringWithFormat:@"%d", dataTemp];
    }
    ```

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

推荐阅读更多精彩内容

  • 这里我们具体说明一下中心模式的应用场景。主设备(手机去扫描连接外设,发现外设服务和属性,操作服务和属性的应用。一般...
    丶逝水流年阅读 2,234评论 3 4
  • 蓝牙 蓝牙的波段为2400-2483.5MHz(包括防护频带)。这是全球范围内无需取得执照(但定不是无管制的)的工...
    苏永茂阅读 6,103评论 0 11
  • (一) iOS蓝牙开发蓝牙相关基础知识 蓝牙常见名称和缩写 MFI ======= make for ipad ...
    雷鸣1010阅读 4,996评论 2 12
  • 由于最近工作的东家是一家物联网公司,网上BLE相关的资料确实比较少,尤其我还做了一些调试和加密相关的工作.由于调试...
    陈长见阅读 2,013评论 5 11
  • 一直以来,总是对别人的态度特别敏感,像一只容易受伤的小动物喜欢把自己包裹起来。多少次,微笑着面对迎面走来的人,却换...
    淞淞妈妈阅读 349评论 0 0