iOS之藍牙打印機

最近競品公司出了一個接入藍牙打印機的功能,作為競爭對手公司肯定不能少所以就給我分了任務宾濒,搞定藍牙打印機

首先介紹一個公司的藍牙打印功能設想,因為公司已經(jīng)具備了wife打印機的打印功能而且非常完善皆看,于是就在想是不是可以吧藍牙當一個wife去使用這樣工作量能少N倍啊龙誊,想到這里那就很簡單了找資料開始搞

.首先你得先能和你玩具-藍牙打印機連接上并且確定藍牙打印機并且能給藍牙打印機透傳數(shù)據(jù)韭寸,這里科普一下藍牙協(xié)議這個玩意藍牙協(xié)議分為藍牙2.0和藍牙4.0春哨;

首先你得清楚一點支持藍牙2.0協(xié)議的設備和藍牙4.0的區(qū)別,那就是藍牙2.0的設備只能手動去建立藍牙連接 而4.0設備卻可以被簡單的程序掃描到并且建立連接恩伺,為什么2.0設備沒有被拋棄呢赴背,這樣能確保你的藍牙設備非常安全的比如蘋果的很多藍牙設備都是2.0的

1.藍牙2.0

iOS開發(fā)中藍牙2.0協(xié)議使用ExternalAccessory這個基礎庫 由于2.0協(xié)議的特殊所以你使用遵循2.0協(xié)議的藍牙設備的時候需要得知該設備藍牙協(xié)議名稱

只有在這里加了這個藍牙協(xié)議名稱你才能找到你的設備

具體視線代碼如下,不建議直接復制 因為個人寫的有殘缺 ?但是主要的功能都已經(jīng)實現(xiàn)

.h中代碼如下

#import#import@interface ExternalAccessoryManager : NSObject

//會話渠道

@property (nonatomic,strong) EASession *session;

//代表打印機

@property (nonatomic,strong) EAAccessory *accessory;

//藍牙設備列

@property (nonatomic,strong) NSMutableArray *deviceArr;

/**

藍牙2.0協(xié)議管理單例

@return self

*/

+ (instancetype)shareExternalAccessoryManager;

//得到比索隆2.0藍牙外設

- (NSArray *)getConnectBuleToolthDevice;

//打印

- (void)printMsgData:(NSData *)data;

@end

.m文件代碼如下

#import "ExternalAccessoryManager.h"static ExternalAccessoryManager * g_ExternalAccessoryManager = nil;@interface ExternalAccessoryManager (){

}

@property (nonatomic,strong) NSData *printData;

@end

@implementation ExternalAccessoryManager

+ (instancetype)shareExternalAccessoryManager{

static dispatch_once_t oneceToken;

dispatch_once(&oneceToken, ^{

g_ExternalAccessoryManager = [[self alloc] init];

});

return g_ExternalAccessoryManager;

}

- (id)init{

self = [super init];

if (self) {

self.deviceArr = [NSMutableArray array];

}

return self;

}

- (NSArray *)getConnectBuleToolthDevice{

EAAccessoryManager *accessoryManager = [EAAccessoryManager sharedAccessoryManager];

NSArray *connectedAccessories = [accessoryManager connectedAccessories];

for (EAAccessory *accessory in connectedAccessories) {

//找到比索隆打印機

if ([@"com.bixolon.protocol" isEqualToString:[accessory.protocolStrings firstObject]] == YES) {

[self.deviceArr addObject:accessory];

}

}

return connectedAccessories;

}

//打印

- (void)printMsgData:(NSData *)data{

// search our device

for (EAAccessory *accessory in self.deviceArr) {

if ([@"com.bixolon.protocol" isEqualToString:[accessory.protocolStrings firstObject]] == YES) {

//? ? ? ? ? ? NSMutableString *info = [[NSMutableString alloc] init];

//? ? ? ? ? ? // 硬件的協(xié)議字符串和硬件廠商提供的一致晶渠,這個就是我們要找的設備了凰荚!

//? ? ? ? ? ? // log:可以打印一下該硬件的相關資訊

//? ? ? ? ? ? for (NSString *proStr in accessory.protocolStrings) {

//? ? ? ? ? ? ? ? [info appendFormat:@"protocolString = %@\n", proStr];

//? ? ? ? ? ? ? ? NSLog(@"打印機協(xié)議%@",proStr);

//? ? ? ? ? ? }

//? ? ? ? ? ? [info appendFormat:@"\n"];

//? ? ? ? ? ? [info appendFormat:@"manufacturer = %@\n", accessory.manufacturer];

//? ? ? ? ? ? [info appendFormat:@"name = %@\n", accessory.name];

//? ? ? ? ? ? [info appendFormat:@"modelNumber = %@\n", accessory.modelNumber];

//? ? ? ? ? ? [info appendFormat:@"serialNumber = %@\n", accessory.serialNumber];

//? ? ? ? ? ? [info appendFormat:@"firmwareRevision = %@\n", accessory.firmwareRevision];

//? ? ? ? ? ? [info appendFormat:@"hardwareRevision = %@\n", accessory.hardwareRevision];

//有打印設備并且有打印內(nèi)容

if (accessory && data.length > 0) {

self.printData = data;

self.accessory = accessory;

[self openSession];

}

}

}

}

//打開傳輸通道

- (BOOL)openSession {

// 根據(jù)已經(jīng)連接的EAAccessory對象和這個協(xié)議(反向域名字符串)來創(chuàng)建EASession對象,并打開輸入褒脯、輸出通道

self.session = [[EASession alloc] initWithAccessory:self.accessory forProtocol:@"com.bixolon.protocol"];

if(self.session != nil) {

// open input stream? 接收

self.session.inputStream.delegate = self;

[self.session.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

[self.session.inputStream open];

// open output stream 傳輸

self.session.outputStream.delegate = self;

[self.session.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

[self.session.outputStream open];

}

else {

NSLog(@"2.0設備未能創(chuàng)建會話");

}

return (nil != self.session);

}

//NSStreamDelegate

// delegate回調(diào)的方法

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {

switch (eventCode) {

//沒有事件

case NSStreamEventNone:

break;

//事件打開完成

case NSStreamEventOpenCompleted:

break;

//有數(shù)據(jù)傳過來

case NSStreamEventHasBytesAvailable:{

//NSLog(@"Input stream is ready");

// 接收到硬件數(shù)據(jù)了便瑟,根據(jù)指令定義對數(shù)據(jù)進行解析。

}

break;

//有可用控件(發(fā)送內(nèi)容)

case NSStreamEventHasSpaceAvailable:{

//NSLog(@"Output stream is ready");

// 可以發(fā)送數(shù)據(jù)給硬件了

[self writeToDevice];

}

break;

//事件發(fā)生錯誤

case NSStreamEventErrorOccurred:{

}

break;

//事件結束后

case NSStreamEventEndEncountered:{

//寫入數(shù)據(jù)成功后關閉通道

[self.session.outputStream close];

}

break;

default:

break;

}

}

- (void)writeToDevice{

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"print_guide_airkiss"ofType:@"txt"];

self.printData = [NSData dataWithContentsOfFile:filePath];

NSInteger length = [self.printData length];

NSString *dateStr = [[NSString alloc] initWithData:self.printData encoding:NSUTF8StringEncoding];

NSLog(@"內(nèi)容編碼%@",dateStr);

if (length > 0) {

[self.session.outputStream write:[self.printData bytes] maxLength:length];

}

}

2.藍牙4.0就更簡單了? 它使用的是CoreBluetooth我在網(wǎng)上找到了一個大神封裝的關于打印方面的一個第三方使用很是方便 大家可以去看看這里附上大神demo的readeME ?這里可以很方便快捷的找到大神的數(shù)據(jù)

# HLBluetoothDemo# 提醒有部分開發(fā)人員番川,加群之后到涂,直接問設備掃描不到,服務掃描出錯颁督,特性掃描報錯践啄,怎么辦?對于這類問題适篙,要嚴厲批評往核,都是因為懶,沒有用心去看官方文檔或者關于CoreBluetooth的教程嚷节。

所以對于藍牙的連接處理流程不清晰的聂儒,嚴重建議先看[iOS CoreBluetooth 的使用講解](http://www.reibang.com/p/1f479b6ab6df)

自己動手寫Demo,把系統(tǒng)的CoreBluetooth的使用硫痰,以及藍牙的流程搞懂了衩婚,再開始做藍牙打印的功能。# 引言該項目中包含兩個部分的工具類`HLBluetooth` 和`HLPrinter`,藍牙操作和打印小票功能效斑。

> 如果只是做藍牙打印機打印小票的功能非春,可以看我的另一個工程[SEBLEPrinter](https://github.com/Halley-Wong/SEBLEPrinter)因為系統(tǒng)的藍牙操作庫是用delegate實現(xiàn)的,步驟比較繁多缓屠,操作很零散奇昙,需要寫一堆的代理方法,特別麻煩

所以我用block方式重寫了敌完,藍牙管理的所有代碼在HLBluetooth目錄中储耐。

又因為項目中要用藍牙控制打印機打印小票,我又把藍牙打印機的操作封裝了一下滨溉,所有代碼在HLPrinter目錄下什湘。

# HLBluetooth介紹用block改寫后长赞,使用大致分為三步:* 獲取藍牙模塊的狀態(tài)* 掃描藍牙外設* 連接、掃描服務闽撤、掃描特性得哆、掃描描述。因為連接哟旗、掃描服務贩据、掃描特性、掃描描述也是屬于不同的階段热幔,所以在block返回時乐设,也有階段值返回。

~~---------------------------------------------------------------------------------------------------------~~

除了上面這些代理方法改寫的block API之外绎巨,還有一些操作性方法近尚,比如:* 讀取特性值* 讀取描述值* 往特性中寫入數(shù)據(jù)* 往描述中寫入數(shù)據(jù)* 讀取信號數(shù)據(jù)* 取消藍牙連接...以上這些方法也提供block方式和一般的調(diào)用方式。

# HLPrinter介紹藍牙打印機模板可以打印的格式有* 單行文字格式```[printer appendText:title alignment:HLTextAlignmentCenter fontSize:HLFontSizeTitleBig];[printer appendText:str1 alignment:HLTextAlignmentCenter]; ```* 左標題右參數(shù)格式```[printer appendTitle:@"時間:" value:@"2016-04-27 10:01:50" valueOffset:150];[printer appendTitle:@"訂單:" value:@"4000020160427100150" valueOffset:150];[printer appendTitle:@"總計:" value:totalStr];[printer appendTitle:@"實收:" value:@"100.00"];```* 三列數(shù)據(jù)格式```[printer appendLeftText:@"商品" middleText:@"數(shù)量" rightText:@"單價" isTitle:YES];[printer appendLeftText:dict[@"name"] middleText:dict[@"amount"] rightText:dict[@"price"] isTitle:NO];```* 分隔線```[printer appendSeperatorLine];```* 圖片```[printer appendImage:[UIImage imageNamed:@"ico180"] alignment:HLTextAlignmentCenter maxWidth:300];```* 二維碼```[printer appendQRCodeWithInfo:@"www.baidu.com" size:10];[printer appendQRCodeWithInfo:@"www.baidu.com"];```* 條形碼```[printer appendBarCodeWithInfo:@"123456789012"];```# 效果圖![1.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/1.png) ![2.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/2.png)![03.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/03.png)![printer.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/printer.png)# 使用方式關于詳細的BLE使用方式和打印小票的功能场勤,在[這里有篇文章詳細說明](http://www.reibang.com/p/90cc08d11b5a)打印機的指令有ASCII戈锻、10進制和16進制三種,我使用的是16進制和媳。```? ? Byte QRSize [] = {0x1D,0x28,0x6B,0x03,0x00,0x31,0x43,size}; // 這是16進制格遭,其中最后一個size是10進制數(shù),轉換為NSData后留瞳,會被轉換為16進制拒迅。? ? Byte QRSize [] = {29,40,107,3,0,49,67,size}; // 這是10進制。```# 補充一些參數(shù):>據(jù)佳博的一技術人員提供的一些參數(shù):

漢字是24 x 24點陣她倘,字符是12 x 24璧微。

58mm 型打印機橫向寬度384個點。(可是我用文字設置相對位置測試確實368硬梁,囧)

80mm 型打印機橫向寬度576個點前硫。

1mm 大概是8個點。

# 更新修復部分型號打印亂碼荧止,亂碼后再次打印沒反應的Bug屹电。(2016-06-13,佳博 Gp-58MBIII和GP58MBIII和芯燁 XPrinter某型號測試通過) demo中也有一個使用的例子

如有使用錯誤或者更好的建議跃巡,請issues我危号。關于藍牙打印機的問題,也歡迎大家加入群:552735579(iOS藍牙打印機開發(fā))素邪。

具體4.0代碼請大家自己去根據(jù)https://github.com/Halley-Wong/SEBLEPrinter 簡單清晰明了 可以直接拿來使用的代碼

3.以上兩步做完之后就建立了你的app和藍牙設備之間的連接葱色,但是因為我是要打印所以那么還需要和服務器建立長連接實時接收服務器給的數(shù)據(jù)同時將數(shù)據(jù)透傳給藍牙打印機。關于打印機指令以及對應的什么模板 打印原理之類這些廠商都會給你提供文檔 ?之前沒有想到這樣解決打印之前我就是通過了解這些指令用一行行的代碼對其進行模板化 其中的辛酸苦辣簡直不是一句話能解釋通的 ?當然這只是一部分打印機 ?大多數(shù)打印機廠商提供的SDK還是很好用的 ?所以考驗你們老板對你是不是真心的時候到了?

這里我是使用MQTT協(xié)議對服務器進行連接的娘香,這個連接將有助與你詳細了解MQTT

https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html

關于MQTT在iOS中的具體使用見我的另一片文章在這里就不多說了 ?

所以總結一下我的app就是找到打印機并建立與打印機之間的聯(lián)系 ?同時與服務器建立長連接 ?那么這時候你就可以理解我的app和藍牙設備加起來這才是一個完整的打印機 ?然后這個打印機與服務器連接起來了 就可以接受服務器發(fā)送的打印指令了

好了文筆不好就寫到這吧

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苍狰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烘绽,更是在濱河造成了極大的恐慌淋昭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件安接,死亡現(xiàn)場離奇詭異翔忽,居然都是意外死亡,警方通過查閱死者的電腦和手機盏檐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門歇式,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胡野,你說我怎么就攤上這事材失。” “怎么了硫豆?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵龙巨,是天一觀的道長。 經(jīng)常有香客問我熊响,道長旨别,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任汗茄,我火速辦了婚禮秸弛,結果婚禮上,老公的妹妹穿的比我還像新娘洪碳。我一直安慰自己递览,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布偶宫。 她就那樣靜靜地躺著非迹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纯趋。 梳的紋絲不亂的頭發(fā)上憎兽,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音吵冒,去河邊找鬼纯命。 笑死,一個胖子當著我的面吹牛痹栖,可吹牛的內(nèi)容都是我干的亿汞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼揪阿,長吁一口氣:“原來是場噩夢啊……” “哼疗我!你這毒婦竟也來了咆畏?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤吴裤,失蹤者是張志新(化名)和其女友劉穎旧找,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體麦牺,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡钮蛛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了剖膳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魏颓。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吱晒,靈堂內(nèi)的尸體忽然破棺而出甸饱,到底是詐尸還是另有隱情,我是刑警寧澤枕荞,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布柜候,位于F島的核電站,受9級特大地震影響躏精,放射性物質(zhì)發(fā)生泄漏渣刷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一矗烛、第九天 我趴在偏房一處隱蔽的房頂上張望辅柴。 院中可真熱鬧,春花似錦瞭吃、人聲如沸碌嘀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽股冗。三九已至,卻和暖如春和蚪,著一層夾襖步出監(jiān)牢的瞬間止状,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工攒霹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怯疤,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓催束,卻偏偏與公主長得像集峦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容