公司最近幫一家物流公司做一個員工使用的APP,需要用到藍(lán)牙去連接設(shè)備打印運(yùn)單信息久又,下面記錄一些在對接藍(lán)牙打印時(shí)候遇到的問題巫延,也總結(jié)一下其他技術(shù)文章中的一些知識點(diǎn)供大家參考效五,網(wǎng)上也有別人做好的第三方BabyBluetooth,這個第三方也可以在我們找的幾種設(shè)備上正常打印炉峰,同學(xué)們可以去看看這個怎么使用畏妖,有問題的地方希望大家提出來。
一疼阔、關(guān)于藍(lán)牙開發(fā)的一些重要的理論概念:
1戒劫、服務(wù)(services):藍(lán)牙外設(shè)對外廣播的時(shí)候一定會有一個服務(wù),有些時(shí)候也可以是有多個服務(wù)婆廊,服務(wù)下面包含一些特性迅细,服務(wù)可以理解成一個模塊的窗口;
2淘邻、特征(characteristic):特征存在于服務(wù)下面的茵典,一個服務(wù)下面可以有多個特征,特征可以理解成具體實(shí)現(xiàn)功能的窗口宾舅,一般的特性都會有value统阿,也就是特征值,是特征和外界交互的最小單位贴浙;
3砂吞、UUID:藍(lán)牙上的唯一標(biāo)示符,為了區(qū)分不同服務(wù)和特征崎溃,就用UUID來表示蜻直。
二、藍(lán)牙連接的主要步驟
1袁串、創(chuàng)建一個CBCentralManager實(shí)例來進(jìn)行藍(lán)牙管理概而;
2、使用CBCentralManager對象搜索掃描外圍設(shè)備囱修;
3赎瑰、連接外圍設(shè)備;
4破镰、獲得外圍設(shè)備的服務(wù)餐曼;
5、獲得服務(wù)的特征鲜漩;
6源譬、從外圍設(shè)備讀取數(shù)據(jù);
7孕似、給外圍設(shè)備發(fā)送(寫入)數(shù)據(jù)踩娘。
三、藍(lán)牙連接和數(shù)據(jù)讀寫的具體步驟
1喉祭、導(dǎo)入蘋果系統(tǒng)藍(lán)牙框架<CoreBluetooth/CoreBluetooth.h>
2养渴、遵循兩個藍(lán)牙框架相關(guān)的協(xié)議<CBCentralManagerDelegate,CBPeripheralDelegate>
3雷绢、新建兩個實(shí)例屬性,一個特征屬性
@property (nonatomic, strong) CBCentralManager *centralManager; //中心管理者
@property (nonatomic, strong) CBPeripheral *peripheral; //連接到的外設(shè)
@property (nonatomic, strong) CBCharacteristic *characteristic; //特征
4理卑、實(shí)例化CBCentralManager對象進(jìn)行藍(lán)牙管理
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; //創(chuàng)建實(shí)例進(jìn)行藍(lán)牙管理
在實(shí)例化該對象之后翘紊,就會觸發(fā)下面這個必須實(shí)現(xiàn)的代理方法,否則在實(shí)例化之后會閃退藐唠,在該方法里面也可以獲取到藍(lán)牙的狀態(tài)霞溪,可以在此處提示用戶去打開藍(lán)牙
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
NSString * state = nil;
switch ([central state])
{
case CBCentralManagerStateUnsupported:
state = @"The platform/hardware doesn't support Bluetooth Low Energy.";
break;
case CBCentralManagerStateUnauthorized:
state = @"The app is not authorized to use Bluetooth Low Energy.";
break;
case CBCentralManagerStatePoweredOff:
state = @"Bluetooth is currently powered off.";
break;
case CBCentralManagerStatePoweredOn:
state = @"work";
break;
case CBCentralManagerStateUnknown:
default:
;
}
}
客戶的需求里面有下次進(jìn)入該界面自動連接設(shè)備的功能,開始做的時(shí)候是實(shí)例化之后馬上開始連接之前的設(shè)備中捆,但是總是連接不上。實(shí)際上等這個回調(diào)函數(shù)調(diào)用之后就可以連接了坊饶,包括去搜索也是一樣泄伪,如果大家操作相關(guān)功能之后沒有效果,可能是這個函數(shù)還沒調(diào)用的原因匿级,怎么連接之前的設(shè)備一會會講到蟋滴。
5.掃描藍(lán)牙設(shè)備(根據(jù)SERVICE_UUID來掃描外設(shè),如果不設(shè)置則掃描所有藍(lán)牙設(shè)備)
[central scanForPeripheralsWithServices:nil options:nil];
執(zhí)行掃描動作之后痘绎,如果掃描到外設(shè)了津函,就會自動回調(diào)下面的協(xié)議方法
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
/*這邊可以打印設(shè)備的名稱,我們可以先將所有搜索到的設(shè)備都存儲起來顯示到UI上孤页,根據(jù)選擇來連接
搜索到的設(shè)備會重復(fù)尔苦,所以需要過濾
peripheral.name
*/
if(![self.deviceLists containsObject: peripheral]){
[self.deviceLists addObject: peripheral];
}
}
6.連接外圍設(shè)備
選擇設(shè)備進(jìn)行連接
[central connectPeripheral:peripheral options:nil];
連接外圍設(shè)備,中心管理者連接外設(shè)成功行施,如果連接成功就會回調(diào)這個協(xié)議方法
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
/連接成功之后允坚,可以進(jìn)行服務(wù)和特性的發(fā)現(xiàn)。 停止中心管理設(shè)備的掃描動作蛾号,要不然在你和已經(jīng)連接好的外設(shè)進(jìn)行數(shù)據(jù)溝通時(shí)稠项,如果又有一個外設(shè)進(jìn)行廣播且符合你的連接條件,那么你的iOS設(shè)備也會去連接這個設(shè)備(因?yàn)閕OS BLE4.0是支持一對多連接的)鲜结,導(dǎo)致數(shù)據(jù)的混亂展运。
//停止掃描
[self.centralManager stopScan];
// 設(shè)置外設(shè)的代理
peripheral.delegate = self;
// 根據(jù)UUID來尋找服務(wù)
//[peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
//外設(shè)發(fā)現(xiàn)服務(wù),傳nil代表不過濾精刷,一次性讀出外設(shè)的所有服務(wù)
[peripheral discoverServices:nil];
}
/** 連接失敗的回調(diào) */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"%s, line = %d, %@=連接失敗", __FUNCTION__, __LINE__, peripheral.name);
}
/** 斷開連接 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
NSLog(@"%s, line = %d, %@=斷開連接", __FUNCTION__, __LINE__, peripheral.name);
// 斷開連接可以設(shè)置重新連接
[central connectPeripheral:peripheral options:nil];
}
7拗胜、獲取外圍設(shè)備服務(wù)和特征
peripheral調(diào)用discoverServices方法之后,在下面的回調(diào)函數(shù)中發(fā)現(xiàn)服務(wù)
/** 發(fā)現(xiàn)服務(wù) */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
// 遍歷出外設(shè)中所有的服務(wù)
for (CBService *service in peripheral.services) {
//查找服務(wù)中所有的特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
peripheral調(diào)用查詢對應(yīng)服務(wù)下面的特征之后贬养,會在下面的回調(diào)函數(shù)中返回
/** 發(fā)現(xiàn)特征 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if (error==nil) {
for (CBCharacteristic *characteristic in service.characteristics){
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"49535343-8841-43F4-A8D4-ECBE34729BB3"]]){
self. characteristic = characteristic;
}else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"49535343-1E4D-4BD9-BA61-23C647249616"]]){
[peripheral setNotifyValue:TRUE forCharacteristic:characteristic];
}
self.peripheral = peripheral;
}
}
}
到現(xiàn)在打印所需要的所有內(nèi)容都獲取到了挤土,就可以往打印機(jī)發(fā)送數(shù)據(jù)了
8、從外圍設(shè)備讀取數(shù)據(jù)
凡是從藍(lán)牙傳過來的數(shù)據(jù)都要經(jīng)過這個回調(diào)误算,簡單的說這個方法就是你拿數(shù)據(jù)的唯一方法仰美,你可以判斷是否 從外圍設(shè)備讀數(shù)據(jù)
/** 接收到數(shù)據(jù)回調(diào) */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSData *data = characteristic.value; //獲取到的數(shù)據(jù)
NSLog(@"bbb-----%@----",data); //打印出來應(yīng)該是<01a5>這樣的數(shù)據(jù)迷殿,可以通過下面的方式去判斷一些自己想要的邏輯
Byte * resultByte = (Byte *)[data bytes];
if(data.length>=1){
if(resultByte[0]==16){ //16代表前兩位的值
NSLog(@"---打印機(jī)打開---");
}else if (resultByte[0]==1){ //01
NSLog(@"----打印機(jī)缺紙-----");
}
}
//下面的處理方式我沒處理過,大家可以試試
//self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
9咖杂、向藍(lán)牙設(shè)備寫數(shù)據(jù)
Byte byte[] = {0x1B,0x68};//打印機(jī)狀態(tài)指令
NSData *data = [[NSData alloc] initWithBytes:byte length:3];
if(self.peripheral&&self.characteristic) {
NSLog(@"發(fā)送獲取狀態(tài)指令");
[peripheral writeValue:data forCharacteristic: characteristic type:CBCharacteristicWriteWithResponse];
}
這里說明怎么連接上一次或者之前連接的設(shè)備庆寺,可以保存之前設(shè)備的標(biāo)識,進(jìn)入App之后通過這個標(biāo)識實(shí)例化服務(wù)來進(jìn)行鏈接诉字;通過這種方式不行的同學(xué)可以試試保存這個標(biāo)識懦尝,下次進(jìn)入的時(shí)候后臺掃描設(shè)備,判斷那個設(shè)備的標(biāo)識和存儲的一樣壤圃,連接表示一樣的那個...
//這個是需要保存的標(biāo)識
NSString *connectId = peripheral.identifier.UUIDString;
//進(jìn)入App之后獲取存儲的標(biāo)識進(jìn)行初始化服務(wù)
NSUUID *identifier = [[NSUUID UUID]initWithUUIDString: connectId];
CBPeripheral *peri = [[self.centralManager retrievePeripheralsWithIdentifiers:@[identifier]] firstObject];
if (peri == nil) {
return;
}
if(peri.state==CBPeripheralStateConnected){
[self alertMs:@"設(shè)備已被連接"];
return;
}
[centralManager connectPeripheral:peri options:@{CBConnectPeripheralOptionNotifyOnConnectionKey : @YES}];
關(guān)于藍(lán)牙打印的知識暫時(shí)分享到這里陵霉,下面貼出參考的文章
藍(lán)牙的連接和數(shù)據(jù)的讀寫