一、關于藍牙開發的一些重要的理論概念:
1.當前ios中開發藍牙所運使用的系統庫是。
2.藍牙外設必需為4.0及以上(2.0需要MFI認證),否則無法開發,藍牙4.0設施由于低耗電,所以也叫做BLE。
3.CoreBluetooth框架的核心其實是兩個東西,peripheral和central, 能了解成外設和中心,就是你的蘋果手機就是中心,外部藍牙稱為外設。
4.服務和特征(service characteristic):簡而言之,外部藍牙中它有若干個服務service(服務你能了解為藍牙所擁有的可以力),而每個服務service下擁有若干個特征characteristic(特征你能了解為解釋這個服務的屬性)。
5.Descriptor(形容)使用來形容characteristic變量的屬性。例如,一個descriptor能規定一個可讀的形容,或者者一個characteristic變量可接受的范圍,或者者一個characteristic變量特定的單位。
6.我們用的藍牙板塊是在淘寶買的, 大概十多元一個, ios大概每次能接受90個字節, 安卓大概每次能接收20個字節, 具體數字可可以會浮動, 應該是與藍牙板塊有關。
二、藍牙連接的主要步驟
1、創建一個CBCentralManager實例來進行藍牙管理;
2、搜索掃描外圍設備;
3、連接外圍設備;
4、獲得外圍設備的服務;
5、獲得服務的特征;
6、從外圍設備讀取數據;
7、給外圍設備發送(寫入)數據。
三、代碼
// 加入權限訪問, 否則上傳AppStore會因為權限不足失敗
WechatIMG4.jpeg
WechatIMG4.jpeg
初始化
#import
self.centralManager = [[CBCentralManager alloc] initWithDelegate:selfqueue:nil];
搜索掃描外圍設備
/**
?*? --? 初始化成功自動調用
?*? --? 必須實現的代理,用來返回創建的centralManager的狀態。
?*? --? 注意:必須確認當前是CBCentralManagerStatePoweredOn狀態才可以調用掃描外設的方法:
?scanForPeripheralsWithServices
?*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
? ? switch(central.state) {
? ? ? ? caseCBCentralManagerStateUnknown:
? ? ? ? ? ? NSLog(@">>>CBCentralManagerStateUnknown");
? ? ? ? ? ? break;
? ? ? ? caseCBCentralManagerStateResetting:
? ? ? ? ? ? NSLog(@">>>CBCentralManagerStateResetting");
? ? ? ? ? ? break;
? ? ? ? caseCBCentralManagerStateUnsupported:
? ? ? ? ? ? NSLog(@">>>CBCentralManagerStateUnsupported");
? ? ? ? ? ? break;
? ? ? ? caseCBCentralManagerStateUnauthorized:
? ? ? ? ? ? NSLog(@">>>CBCentralManagerStateUnauthorized");
? ? ? ? ? ? break;
? ? ? ? caseCBCentralManagerStatePoweredOff:
? ? ? ? ? ? NSLog(@">>>CBCentralManagerStatePoweredOff");
? ? ? ? ? ? break;
? ? ? ? caseCBCentralManagerStatePoweredOn:
? ? ? ? {
? ? ? ? ? ? NSLog(@">>>CBCentralManagerStatePoweredOn");
? ? ? ? ? ? // 開始掃描周圍的外設。
? ? ? ? ? ? /*
?? ? ? ? ? ? -- 兩個參數為Nil表示默認掃描所有可見藍牙設備。
?? ? ? ? ? ? -- 注意:第一個參數是用來掃描有指定服務的外設。然后有些外設的服務是相同的,比如都有FFF5服務,那么都會發現;而有些外設的服務是不可見的,就會掃描不到設備。
?? ? ? ? ? ? -- 成功掃描到外設后調用didDiscoverPeripheral
?? ? ? ? ? ? */
? ? ? ? ? ? [self.centralManager scanForPeripheralsWithServices:niloptions:nil];
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? break;
? ? }
}
#pragma mark 發現外設
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary*)advertisementData RSSI:(NSNumber *)RSSI{
? ? NSLog(@"Find device:%@", [peripheral name]);
? ? if(![_deviceDic objectForKey:[peripheral name]]) {
? ? ? ? NSLog(@"Find device:%@", [peripheral name]);
? ? ? ? if(peripheral!=nil) {
? ? ? ? ? ? if([peripheral name]!=nil) {
? ? ? ? ? ? ? ? if([[peripheral name] hasPrefix:@"根據設備名過濾"]) {
? ? ? ? ? ? ? ? ? ? [_deviceDic setObject:peripheral forKey:[peripheral name]];
? ? ? ? ? ? ? ? ? ? // 停止掃描, 看需求決定要不要加
? ? ? ? ? ? ? ? ? ? //? ? ? ? ? ? ? ? ? ? [_centralManager stopScan];
? ? ? ? ? ? ? ? ? ? // 將設備信息傳到外面的頁面(VC), 構成掃描到的設備列表
? ? ? ? ? ? ? ? ? ? if([self.delegate respondsToSelector:@selector(dataWithBluetoothDic:)]) {
? ? ? ? ? ? ? ? ? ? ? ? [self.delegate dataWithBluetoothDic:_deviceDic];
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
3.連接外圍設備
// 連接設備(.h中聲明出去的接口, 一般在點擊設備列表連接時調用)
- (void)connectDeviceWithPeripheral:(CBPeripheral *)peripheral
{
? ? [self.centralManager connectPeripheral:peripheral options:nil];
}
#pragma mark 連接外設--成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
? ? //連接成功后停止掃描,節省內存
? ? [central stopScan];
? ? peripheral.delegate =self;
? ? self.peripheral = peripheral;
? ? //4.掃描外設的服務
? ? /**
?? ? --? ? 外設的服務、特征、描述等方法是CBPeripheralDelegate的內容,所以要先設置代理peripheral.delegate = self
?? ? --? ? 參數表示你關心的服務的UUID,比如我關心的是"FFE0",參數就可以為@[[CBUUID UUIDWithString:@"FFE0"]].那么didDiscoverServices方法回調內容就只有這兩個UUID的服務,不會有其他多余的內容,提高效率。nil表示掃描所有服務
?? ? --? ? 成功發現服務,回調didDiscoverServices
?? ? */
? ? [peripheral discoverServices:@[[CBUUID UUIDWithString:@"你要用的服務UUID"]]];
? ? if([self.delegate respondsToSelector:@selector(didConnectBle)]) {
? ? ? ? // 已經連接
? ? ? ? [self.delegate didConnectBle];
? ? }
}
#pragma mark 連接外設——失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
? ? NSLog(@"%@", error);
}
#pragma mark 取消與外設的連接回調
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
? ? NSLog(@"%@", peripheral);
}
獲得外圍設備的服務
#pragma mark 發現服務回調
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
? ? //NSLog(@"didDiscoverServices,Error:%@",error);
? ? CBService *__nullablefindService =nil;
? ? // 遍歷服務
? ? for(CBService *serviceinperipheral.services)
? ? {
? ? ? ? //NSLog(@"UUID:%@",service.UUID);
? ? ? ? if([[service UUID] isEqual:[CBUUID UUIDWithString:@"你要用的服務UUID"]])
? ? ? ? {
? ? ? ? ? ? findService = service;
? ? ? ? }
? ? }
? ? NSLog(@"Find Service:%@",findService);
? ? if(findService)
? ? ? ? [peripheral discoverCharacteristics:NULLforService:findService];
}
#pragma mark 發現特征回調
/**
?--? 發現特征后,可以根據特征的properties進行:讀readValueForCharacteristic、寫writeValue、訂閱通知setNotifyValue、掃描特征的描述discoverDescriptorsForCharacteristic。
?**/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
? ? for(CBCharacteristic *characteristicinservice.characteristics) {
? ? ? ? if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"你要用的特征UUID"]]) {
? ? ? ? ? ? /**
?? ? ? ? ? ? -- 讀取成功回調didUpdateValueForCharacteristic
?? ? ? ? ? ? */
? ? ? ? ? ? self.characteristic = characteristic;
? ? ? ? ? ? // 接收一次(是讀一次信息還是數據經常變實時接收視情況而定, 再決定使用哪個)
? ? ? ? ? ? //? ? ? ? ? ? [peripheral readValueForCharacteristic:characteristic];
? ? ? ? ? ? // 訂閱, 實時接收
? ? ? ? ? ? [peripheral setNotifyValue:YESforCharacteristic:characteristic];
? ? ? ? ? ? // 發送下行指令(發送一條)
? ? ? ? ? ? NSData *data = [@"硬件工程師給我的指令, 發送給藍牙該指令, 藍牙會給我返回一條數據"dataUsingEncoding:NSUTF8StringEncoding];
? ? ? ? ? ? // 將指令寫入藍牙
? ? ? ? ? ? [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
? ? ? ? }
? ? ? ? /**
?? ? ? ? -- 當發現characteristic有descriptor,回調didDiscoverDescriptorsForCharacteristic
?? ? ? ? */
? ? ? ? [peripheral discoverDescriptorsForCharacteristic:characteristic];
? ? }
}
6.從外圍設備讀取數據
#pragma mark - 獲取值
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
? ? // characteristic.value就是藍牙給我們的值(我這里是json格式字符串)
? ? NSData *jsonData = [characteristic.value dataUsingEncoding:NSUTF8StringEncoding];
? ? NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
? ? // 將字典傳出去就可以使用了
}
#pragma mark - 中心讀取外設實時數據
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
? ? if(characteristic.isNotifying) {
? ? ? ? [peripheral readValueForCharacteristic:characteristic];
? ? }else{
? ? ? ? NSLog(@"Notification stopped on %@.? Disconnecting", characteristic);
? ? ? ? NSLog(@"%@", characteristic);
? ? ? ? [self.centralManager cancelPeripheralConnection:peripheral];
? ? }
}
給外圍設備發送(寫入)數據
// 上文中發現特征之后, 發送下行指令的時候其實就是向藍牙中寫入數據
// 例:
// 發送檢查藍牙命令
- (void)writeCheckBleWithBle
{
? ? _style =1;
? ? // 發送下行指令(發送一條)
? ? NSData *data = [@"硬件工程師提供給你的指令, 類似于5E16010203...這種很長一串"dataUsingEncoding:NSUTF8StringEncoding];
? ? [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
}
#pragma mark 數據寫入成功回調
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
? ? NSLog(@"寫入成功");
? ? if([self.delegate respondsToSelector:@selector(didWriteSucessWithStyle:)]) {
? ? ? ? [self.delegate didWriteSucessWithStyle:_style];
? ? }
}
另外
- (void)scanDevice
{
? ? if(_centralManager ==nil) {
? ? ? ? self.centralManager = [[CBCentralManager alloc] initWithDelegate:selfqueue:nil];
? ? ? ? [_deviceDic removeAllObjects];
? ? }
}
#pragma mark 斷開連接
- (void)disConnectPeripheral{
? ? /**
?? ? -- 斷開連接后回調didDisconnectPeripheral
?? ? -- 注意斷開后如果要重新掃描這個外設,需要重新調用[self.centralManager scanForPeripheralsWithServices:nil options:nil];
?? ? */
? ? [self.centralManager cancelPeripheralConnection:self.peripheral];
}
#pragma mark 停止掃描外設
- (void)stopScanPeripheral{
? ? [self.centralManager stopScan];
}