蓝牙(CoreBluetooth)

在CoreBluetooth框架中,有两个主要的角色:外设和中心,整个框架都是围绕这两个主要角色设计的.

中心角色变成实现过程

1.设置CBCentralManager

2.发现并连接外设

3.发现服务

4.发现特征

5.预定特征通知

6.读取数据

[objc]view plaincopy

print?

#import 

#import 

#define TRANSFER_SERVICE_UUID           @"D63D44E5-E798-4EA5-A1C0-3F9EEEC2CDEB"

#define TRANSFER_CHARACTERISTIC_UUID    @"1652CAD2-6B0D-4D34-96A0-75058E606A98"

@interfaceViewController : UIViewController 

@property(strong,nonatomic) CBCentralManager      *centralManager;//CBCentralManager 是用来管理BLE的中心设备

@property(strong,nonatomic) CBPeripheral          *discoveredPeripheral;

@property(strong,nonatomic) NSMutableData         *data;

@property(weak,nonatomic) IBOutletUIActivityIndicatorView*activityIndicatorView;

@property(weak,nonatomic) IBOutletUILabel*scanLabel;

@property(weak,nonatomic) IBOutletUITextView*textView;

@end

[objc]view plaincopy

print?

@implementationViewController

- (void)viewDidLoad

{

[superviewDidLoad];

// 设置CBCentralManager

_centralManager = [[CBCentralManageralloc]initWithDelegate:selfqueue:nil];

// 保存接收数据

_data = [[NSMutableDataalloc]init];

}

- (void)viewWillDisappear:(BOOL)animated

{

[self.centralManagerstopScan];

[self.activityIndicatorViewstopAnimating];

NSLog(@"扫描停止");

[superviewWillDisappear:animated];

}

- (void)didReceiveMemoryWarning

{

[superdidReceiveMemoryWarning];

}

#pragma mark - Central Methods

//设置成功回调方法

- (void)centralManagerDidUpdateState:(CBCentralManager*)central

{

if(central.state!= CBCentralManagerStatePoweredOn) {

return;

}

//开始扫描

[selfscan];

}

/** 通过制定的128位的UUID,扫描外设

*/

- (void)scan

{

//扫描

[self.centralManagerscanForPeripheralsWithServices:@[[CBUUIDUUIDWithString:TRANSFER_SERVICE_UUID]]

options:@{ CBCentralManagerScanOptionAllowDuplicatesKey :@YES}];

[self.activityIndicatorViewstartAnimating];

self.scanLabel.hidden=NO;

NSLog(@"Scanning started");

}

/** 停止扫描

*/

- (void)stop

{

[self.centralManagerstopScan];

[self.activityIndicatorViewstopAnimating];

self.scanLabel.hidden=YES;

self.textView.text=@"";

NSLog(@"Scanning stoped");

}

//扫描成功调用此方法

- (void)centralManager:(CBCentralManager*)centraldidDiscoverPeripheral:(CBPeripheral*)peripheraladvertisementData:(NSDictionary*)advertisementDataRSSI:(NSNumber*)RSSI

{

// 过滤信号强度范围

if(RSSI.integerValue> -15) {

return;

}

if(RSSI.integerValue< -35) {

return;

}

NSLog(@"发现外设 %@ at %@", peripheral.name, RSSI);

if(self.discoveredPeripheral!= peripheral) {

self.discoveredPeripheral= peripheral;

NSLog(@"连接外设 %@", peripheral);

[self.centralManagerconnectPeripheral:peripheraloptions:nil];

}

}

- (void)centralManager:(CBCentralManager*)centraldidFailToConnectPeripheral:(CBPeripheral*)peripheralerror:(NSError*)error

{

NSLog(@"连接失败 %@. (%@)", peripheral, [errorlocalizedDescription]);

[selfcleanup];

}

//连接外设成功

- (void)centralManager:(CBCentralManager*)centraldidConnectPeripheral:(CBPeripheral*)peripheral

{

NSLog(@"外设已连接");

// Stop scanning

[selfstop];

NSLog(@"扫描停止");

[self.datasetLength:0];//重置data属性

peripheral.delegate=self;//设置外设对象的委托为self

[peripheraldiscoverServices:@[[CBUUIDUUIDWithString:TRANSFER_SERVICE_UUID]]];

}

/** 服务被发现

*/

//发现服务成功

- (void)peripheral:(CBPeripheral*)peripheraldidDiscoverServices:(NSError*)error

{

if(error) {

NSLog(@"Error discovering services: %@", [errorlocalizedDescription]);

[selfcleanup];

return;

}

// 发现特征

for(CBService*service in peripheral.services) {

[peripheraldiscoverCharacteristics:@[[CBUUIDUUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]forService:service];

}

}

//发现特征成功

- (void)peripheral:(CBPeripheral*)peripheraldidDiscoverCharacteristicsForService:(CBService*)serviceerror:(NSError*)error

{

if(error) {

NSLog(@"发现特征错误: %@", [errorlocalizedDescription]);

[selfcleanup];

return;

}

for(CBCharacteristic*characteristic in service.characteristics) {

if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {

// 预定特征

[peripheralsetNotifyValue:YESforCharacteristic:characteristic];

}

}

}

//特征状态发生变化

- (void)peripheral:(CBPeripheral*)peripheraldidUpdateValueForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error

{

if(error) {

NSLog(@"发现特征错误:: %@", [errorlocalizedDescription]);

return;

}

NSString*stringFromData = [[NSStringalloc]initWithData:characteristic.valueencoding:NSUTF8StringEncoding];

// 判断是否为数据结束

if([stringFromDataisEqualToString:@"EOM"]) {

// 显示数据

[self.textViewsetText:[[NSStringalloc]initWithData:self.dataencoding:NSUTF8StringEncoding]];

// 取消特征预定

[peripheralsetNotifyValue:NOforCharacteristic:characteristic];

// 断开外设

[self.centralManagercancelPeripheralConnection:peripheral];

}

// 接收数据追加到data属性中

[self.dataappendData:characteristic.value];

NSLog(@"Received: %@", stringFromData);

}

//特征值发生变化

- (void)peripheral:(CBPeripheral*)peripheraldidUpdateNotificationStateForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error

{

if(error) {

NSLog(@"特征通知状态变化错误: %@", error.localizedDescription);

}

// 如果没有特征传输过来则退出

if(![characteristic.UUIDisEqual:[CBUUIDUUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {

return;

}

// 特征通知已经开始

if(characteristic.isNotifying) {

NSLog(@"特征通知已经开始 %@", characteristic);

}

// 特征通知已经停止

else{

NSLog(@"特征通知已经停止 %@", characteristic);

[self.centralManagercancelPeripheralConnection:peripheral];

}

}

//与外设连接断开时回调

- (void)centralManager:(CBCentralManager*)centraldidDisconnectPeripheral:(CBPeripheral*)peripheralerror:(NSError*)error

{

NSLog(@"外设已经断开");

self.discoveredPeripheral=nil;

//外设已经断开情况下,重新扫描

[selfscan];

}

/** 清除方法

*/

- (void)cleanup

{

// 如果没有连接则退出

if(!self.discoveredPeripheral.isConnected) {

return;

}

// 判断是否已经预定了特征

if(self.discoveredPeripheral.services!=nil) {

for(CBService*service inself.discoveredPeripheral.services) {

if(service.characteristics!=nil) {

for(CBCharacteristic*characteristic in service.characteristics) {

if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {

if(characteristic.isNotifying) {

//停止接收特征通知

[self.discoveredPeripheralsetNotifyValue:NOforCharacteristic:characteristic];

//断开与外设连接

[self.centralManagercancelPeripheralConnection:self.discoveredPeripheral];

return;

}

}

}

}

}

}

//断开与外设连接

[self.centralManagercancelPeripheralConnection:self.discoveredPeripheral];

}

@end

外设角色编程实现过程

1.设置CBPeripheraManager

2.设置服务与特征

3.发布服务与特征

4.广播服务

5.发送数据

[objc]view plaincopy

print?

#import 

#import 

#define TRANSFER_SERVICE_UUID           @"D63D44E5-E798-4EA5-A1C0-3F9EEEC2CDEB"

#define TRANSFER_CHARACTERISTIC_UUID    @"1652CAD2-6B0D-4D34-96A0-75058E606A98"

#define NOTIFY_MTU      20

@interfaceViewController : UIViewController  

@property(strong,nonatomic) CBPeripheralManager       *peripheralManager;//用来管理BLE的外设设备

@property(strong,nonatomic) CBMutableCharacteristic   *transferCharacteristic;//特征类

@property(strong,nonatomic) NSData                    *dataToSend;

@property(nonatomic,readwrite) NSInteger              sendDataIndex;

@property(weak,nonatomic) IBOutletUITextView*textView;

- (IBAction)valueChanged:(id)sender;

@end

[objc]view plaincopy

print?

@implementationViewController

- (void)viewDidLoad

{

[superviewDidLoad];

//设置CBPeripheralManager

_peripheralManager = [[CBPeripheralManageralloc]initWithDelegate:selfqueue:nil];

}

- (void)viewWillDisappear:(BOOL)animated

{

[self.peripheralManagerstopAdvertising];

[superviewWillDisappear:animated];

}

#pragma mark - Peripheral Methods

//外设设置成功回调此方法

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager*)peripheral

{

if(peripheral.state!= CBPeripheralManagerStatePoweredOn) {

return;

}

NSLog(@"BLE打开");

// 初始化特征

self.transferCharacteristic= [[CBMutableCharacteristicalloc]

initWithType:[CBUUIDUUIDWithString:TRANSFER_CHARACTERISTIC_UUID]

properties:CBCharacteristicPropertyNotify

value:nil

permissions:CBAttributePermissionsReadable];

// 初始化服务

CBMutableService*transferService = [[CBMutableServicealloc]

initWithType:[CBUUIDUUIDWithString:TRANSFER_SERVICE_UUID]

primary:YES];

// 添加特征到服务

transferService.characteristics= @[self.transferCharacteristic];

// 发布服务与特征

[self.peripheralManageraddService:transferService];

}

- (void)peripheralManager:(CBPeripheralManager*)peripheral

didAddService:(CBService*)service

error:(NSError*)error {

NSLog(@"添加服务");

if(error) {

NSLog(@"添加服务失败: %@", [errorlocalizedDescription]);

}

}

- (IBAction)valueChanged:(id)sender {

UISwitch* advertisingSwitch = (UISwitch*)sender;

if(advertisingSwitch.on) {

// 开始广播

[self.peripheralManagerstartAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUIDUUIDWithString:TRANSFER_SERVICE_UUID]] }];

}

else{

[self.peripheralManagerstopAdvertising];

}

}

//远程中心预定数据回调该方法

- (void)peripheralManager:(CBPeripheralManager*)peripheralcentral:(CBCentral*)centraldidSubscribeToCharacteristic:(CBCharacteristic*)characteristic

{

NSLog(@"中心已经预定了特征");

self.dataToSend= [self.textView.textdataUsingEncoding:NSUTF8StringEncoding];

self.sendDataIndex=0;

[selfsendData];

}

- (void)peripheralManager:(CBPeripheralManager*)peripheralcentral:(CBCentral*)centraldidUnsubscribeFromCharacteristic:(CBCharacteristic*)characteristic {

NSLog(@"中心没有从特征预定");

}

- (void)sendData {

//发送数据结束标识

staticBOOLsendingEOM =NO;

if(sendingEOM) {

BOOLdidSend = [self.peripheralManagerupdateValue:[@"EOM"dataUsingEncoding:NSUTF8StringEncoding]forCharacteristic:self.transferCharacteristiconSubscribedCentrals:nil];

if(didSend) {

sendingEOM =NO;

NSLog(@"Sent: EOM");

}

return;

}

if(self.sendDataIndex>=self.dataToSend.length) {

return;

}

BOOLdidSend =YES;

while(didSend) {

NSInteger amountToSend =self.dataToSend.length-self.sendDataIndex;

if(amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU;

NSData*chunk = [NSDatadataWithBytes:self.dataToSend.bytes+self.sendDataIndexlength:amountToSend];

//发送数据

didSend = [self.peripheralManagerupdateValue:chunkforCharacteristic:self.transferCharacteristiconSubscribedCentrals:nil];

if(!didSend) {

return;

}

NSString*stringFromData = [[NSStringalloc]initWithData:chunkencoding:NSUTF8StringEncoding];

NSLog(@"Sent: %@", stringFromData);

self.sendDataIndex+= amountToSend;

if(self.sendDataIndex>=self.dataToSend.length) {

sendingEOM =YES;

BOOLeomSent = [self.peripheralManagerupdateValue:[@"EOM"dataUsingEncoding:NSUTF8StringEncoding]forCharacteristic:self.transferCharacteristiconSubscribedCentrals:nil];

if(eomSent) {

sendingEOM =NO;

NSLog(@"Sent: EOM");

}

return;

}

}

}

//发送数据失败后(发送数据的队列已经满了)重新发送

- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager*)peripheral {

[selfsendData];

}

- (void)didReceiveMemoryWarning {

[superdidReceiveMemoryWarning];

}

@end

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

推荐阅读更多精彩内容