之前在基礎(chǔ)知識(shí)介紹過(guò)BLE應(yīng)用的兩種流程,如圖:
- central模式用的都是左邊的類(lèi),而peripheral模式用的是右邊的類(lèi)
peripheral模式的流程
- 1.引入CoreBluetooth框架,初始化peripheralManager
- 2.設(shè)置peripheralManager中的內(nèi)容
- 3.開(kāi)啟廣播advertising
- 4.對(duì)central的操作進(jìn)行響應(yīng)
- 4.1 讀characteristics請(qǐng)求
- 4.2 寫(xiě)characteristics請(qǐng)求
- 4.4 訂閱和取消訂閱characteristics
準(zhǔn)備環(huán)境
具體操作步驟
1.引入CoreBluetooth框架,初始化peripheralManager
#import <CoreBluetooth/CoreBluetooth.h>
@interface XMGBLEPeripheralViewController () <CBPeripheralManagerDelegate>
@property (nonatomic, strong) CBPeripheralManager *pMgr; /**< 外設(shè)管理者 */
@end
@implementation XMGBLEPeripheralViewController
// 懶加載
- (CBPeripheralManager *)pMgr
{
if (!_pMgr) {
_pMgr = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
}
return _pMgr;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 調(diào)用get方法初始化,初始化后CBPeripheralManager狀態(tài)改變會(huì)調(diào)用代理方法peripheralManagerDidUpdateState:
// 模擬器永遠(yuǎn)也不會(huì)是CBPeripheralManagerStatePoweredOn狀態(tài)
[self pMgr];
}
2.設(shè)置peripheralManager中的內(nèi)容
- 創(chuàng)建characteristics及其description,
- 創(chuàng)建service,把characteristics添加到service中,
- 再把service添加到peripheralManager中
#pragma mark - CBPeripheralManagerDelegate
// CBPeripheralManager初始化后會(huì)觸發(fā)的方法
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
// 提示設(shè)備成功打開(kāi)
[SVProgressHUD showSuccessWithStatus:@"xmg設(shè)備打開(kāi)成功~"];
// 配置各種服務(wù)入CBPeripheralManager
[self yf_setupPMgr];
}else
{
// 提示設(shè)備打開(kāi)失敗
[SVProgressHUD showErrorWithStatus:@"失敗!"];
}
}
#pragma mark - 私有方法
- (void)yf_setupPMgr
{
// 特征描述的UUID
CBUUID *characteristicUserDescriptionUUID = [CBUUID UUIDWithString:CBUUIDCharacteristicUserDescriptionString];
// 特征的通知UUID
CBUUID *notifyCharacteristicUUID = [CBUUID UUIDWithString:notiyCharacteristicStrUUID];
// 特征的讀寫(xiě)UUID
CBUUID *readwriteCharacteristicUUID = [CBUUID UUIDWithString:readwriteCharacteristicStrUUID];
// 特征的只讀UUID
CBUUID *readCharacteristicUUID = [CBUUID UUIDWithString:readwriteCharacteristicStrUUID];
CBUUID *ser1UUID = [CBUUID UUIDWithString:Service1StrUUID];
CBUUID *ser2UUID = [CBUUID UUIDWithString:Service2StrUUID];
// 初始化一個(gè)特征的描述
CBMutableDescriptor *des1 = [[CBMutableDescriptor alloc] initWithType:characteristicUserDescriptionUUID value:@"xmgDes1"];
// 可通知的特征
CBMutableCharacteristic *notifyCharacteristic = [[CBMutableCharacteristic alloc] initWithType:notifyCharacteristicUUID // UUID
properties:CBCharacteristicPropertyNotify // 枚舉:通知
value:nil // 數(shù)據(jù)先不傳
permissions:CBAttributePermissionsReadable]; // 枚舉:可讀
// 可讀寫(xiě)的特征
CBMutableCharacteristic *readwriteChar = [[CBMutableCharacteristic alloc] initWithType:readwriteCharacteristicUUID
properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite
value:nil
permissions:CBAttributePermissionsReadable | CBAttributePermissionsWriteable];
[readwriteChar setDescriptors:@[des1]]; // 設(shè)置特征的描述
// 只讀特征
CBMutableCharacteristic *readChar = [[CBMutableCharacteristic alloc] initWithType:readCharacteristicUUID
properties:CBCharacteristicPropertyRead
value:nil
permissions:CBAttributePermissionsReadable];
// 初始化服務(wù)1
CBMutableService *ser1 = [[CBMutableService alloc] initWithType:ser1UUID primary:YES];
// 為服務(wù)設(shè)置倆特征(通知, 帶描述的讀寫(xiě))
[ser1 setCharacteristics:@[notifyCharacteristic, readwriteChar]];
// 初始化服務(wù)2,并且添加一個(gè)只讀特征
CBMutableService *ser2 = [[CBMutableService alloc] initWithType:ser2UUID primary:YES];
ser2.characteristics = @[readChar];
// 添加服務(wù)進(jìn)外設(shè)管理者
// 添加操作會(huì)觸發(fā)代理方法peripheralManager:didAddService:error:
[self.pMgr addService:ser1];
[self.pMgr addService:ser2];
}
3.開(kāi)啟廣播
// 添加服務(wù)進(jìn)CBPeripheralManager時(shí)會(huì)觸發(fā)的方法
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
// 由于添加了兩次ser,所以方法會(huì)調(diào)用兩次
static int i = 0;
if (!error) {
i++;
}
// 當(dāng)?shù)诙芜M(jìn)入方法時(shí)候,代表兩個(gè)服務(wù)添加完畢,此時(shí)要用到2,由于沒(méi)有擴(kuò)展性,所以新增了可變數(shù)組,記錄添加的服務(wù)數(shù)量
if (i == self.servieces.count) {
// 廣播內(nèi)容
NSDictionary *advertDict = @{CBAdvertisementDataServiceUUIDsKey: [self.servieces valueForKeyPath:@"UUID"],
CBAdvertisementDataLocalNameKey:LocalNameKey};
// 發(fā)出廣播,會(huì)觸發(fā)peripheralManagerDidStartAdvertising:error:
[peripheral startAdvertising:advertDict];
}
}
// 開(kāi)始廣播觸發(fā)的代理
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
}
>>>>>>>>分割線>>>>下面是修改的地方
@property (nonatomic, strong) NSMutableArray *servieces; /**< 服務(wù)可變數(shù)組 */
// 自定義服務(wù)
- (NSMutableArray *)servieces
{
if (!_servieces) {
_servieces = [NSMutableArray array];
}
return _servieces;
}
#pragma mark - 私有方法
- (void)yf_setupPMgr
{
...
// 初始化服務(wù)1
CBMutableService *ser1 = [[CBMutableService alloc] initWithType:ser1UUID primary:YES];
// 為服務(wù)設(shè)置倆特征(通知, 帶描述的讀寫(xiě))
[ser1 setCharacteristics:@[notifyCharacteristic, readwriteChar]];
[self.servieces addObject:ser1];
// 初始化服務(wù)2,并且添加一個(gè)只讀特征
CBMutableService *ser2 = [[CBMutableService alloc] initWithType:ser2UUID primary:YES];
ser2.characteristics = @[readChar];
[self.servieces addObject:ser2];
// 添加服務(wù)進(jìn)外設(shè)管理者
// 添加操作會(huì)觸發(fā)代理方法peripheralManager:didAddService:error:
if (self.servieces.count) {
for (CBMutableService *ser in self.servieces) {
[self.pMgr addService:ser];
}
}
}
4.對(duì)central的操作做出響應(yīng)
- 4.1 讀characteristics請(qǐng)求
- 4.2 寫(xiě)characteristics請(qǐng)求
- 4.3 訂閱和取消訂閱characteristics
// 外設(shè)收到讀的請(qǐng)求,然后讀特征的值賦值給request
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request
{
NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);
// 判斷是否可讀
if (request.characteristic.properties & CBCharacteristicPropertyRead) {
NSData *data = request.characteristic.value;
request.value = data;
// 對(duì)請(qǐng)求成功做出響應(yīng)
[self.pMgr respondToRequest:request withResult:CBATTErrorSuccess];
}else
{
[self.pMgr respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
}
}
// 外設(shè)收到寫(xiě)的請(qǐng)求,然后讀request的值,寫(xiě)給特征
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests
{
NSLog(@"%s, line = %d, requests = %@", __FUNCTION__, __LINE__, requests);
CBATTRequest *request = requests.firstObject;
if (request.characteristic.properties & CBCharacteristicPropertyWrite) {
NSData *data = request.value;
// 此處賦值要轉(zhuǎn)類(lèi)型,否則報(bào)錯(cuò)
CBMutableCharacteristic *mChar = (CBMutableCharacteristic *)request.characteristic;
mChar.value = data;
// 對(duì)請(qǐng)求成功做出響應(yīng)
[self.pMgr respondToRequest:request withResult:CBATTErrorSuccess];
}else
{
[self.pMgr respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
}
}
// 與CBCentral的交互
// 訂閱特征
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"%s, line = %d, 訂閱了%@的數(shù)據(jù)", __FUNCTION__, __LINE__, characteristic.UUID);
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(yf_sendData:)
userInfo:characteristic
repeats:YES];
self.timer = timer;
/* 另一種方法 */
// NSTimer *testTimer = [NSTimer timerWithTimeInterval:2.0
// target:self
// selector:@selector(yf_sendData:)
// userInfo:characteristic
// repeats:YES];
// [[NSRunLoop currentRunLoop] addTimer:testTimer forMode:NSDefaultRunLoopMode];
}
// 取消訂閱特征
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"%s, line = %d, 取消訂閱了%@的數(shù)據(jù)", __FUNCTION__, __LINE__, characteristic.UUID);
[self.timer invalidate];
self.timer = nil;
}
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
{
NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);
}
// 計(jì)時(shí)器每隔兩秒調(diào)用的方法
- (BOOL)yf_sendData:(NSTimer *)timer
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yy:MM:dd:HH:mm:ss";
NSString *now = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"now = %@", now);
// 執(zhí)行回應(yīng)central通知數(shù)據(jù)
return [self.pMgr updateValue:[now dataUsingEncoding:NSUTF8StringEncoding]
forCharacteristic:timer.userInfo
onSubscribedCentrals:nil];
}