iOS之藍牙打印機

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

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

.首先你得先能和你玩具-藍牙打印機連接上并且確定藍牙打印機并且能給藍牙打印機透傳數據,這里科普一下藍牙協議這個玩意藍牙協議分為藍牙2.0和藍牙4.0;

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

1.藍牙2.0

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

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

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

.h中代碼如下

#import#import@interface ExternalAccessoryManager : NSObject

//會話渠道

@property (nonatomic,strong) EASession *session;

//代表打印機

@property (nonatomic,strong) EAAccessory *accessory;

//藍牙設備列

@property (nonatomic,strong) NSMutableArray *deviceArr;

/**

藍牙2.0協議管理單例

@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];

//? ? ? ? ? ? // 硬件的協議字符串和硬件廠商提供的一致,這個就是我們要找的設備了!

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

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

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

//? ? ? ? ? ? ? ? NSLog(@"打印機協議%@",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];

//有打印設備并且有打印內容

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

self.printData = data;

self.accessory = accessory;

[self openSession];

}

}

}

}

//打開傳輸通道

- (BOOL)openSession {

// 根據已經連接的EAAccessory對象和這個協議(反向域名字符串)來創建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設備未能創建會話");

}

return (nil != self.session);

}

//NSStreamDelegate

// delegate回調的方法

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

switch (eventCode) {

//沒有事件

case NSStreamEventNone:

break;

//事件打開完成

case NSStreamEventOpenCompleted:

break;

//有數據傳過來

case NSStreamEventHasBytesAvailable:{

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

// 接收到硬件數據了,根據指令定義對數據進行解析。

}

break;

//有可用控件(發送內容)

case NSStreamEventHasSpaceAvailable:{

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

// 可以發送數據給硬件了

[self writeToDevice];

}

break;

//事件發生錯誤

case NSStreamEventErrorOccurred:{

}

break;

//事件結束后

case NSStreamEventEndEncountered:{

//寫入數據成功后關閉通道

[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(@"內容編碼%@",dateStr);

if (length > 0) {

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

}

}

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

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

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

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

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

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

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

# HLBluetooth介紹用block改寫后,使用大致分為三步:* 獲取藍牙模塊的狀態* 掃描藍牙外設* 連接、掃描服務、掃描特性、掃描描述。因為連接、掃描服務、掃描特性、掃描描述也是屬于不同的階段,所以在block返回時,也有階段值返回。

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

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

# HLPrinter介紹藍牙打印機模板可以打印的格式有* 單行文字格式```[printer appendText:title alignment:HLTextAlignmentCenter fontSize:HLFontSizeTitleBig];[printer appendText:str1 alignment:HLTextAlignmentCenter]; ```* 左標題右參數格式```[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"];```* 三列數據格式```[printer appendLeftText:@"商品" middleText:@"數量" 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.lxweimin.com/p/90cc08d11b5a)打印機的指令有ASCII、10進制和16進制三種,我使用的是16進制。```? ? Byte QRSize [] = {0x1D,0x28,0x6B,0x03,0x00,0x31,0x43,size}; // 這是16進制,其中最后一個size是10進制數,轉換為NSData后,會被轉換為16進制。? ? Byte QRSize [] = {29,40,107,3,0,49,67,size}; // 這是10進制。```# 補充一些參數:>據佳博的一技術人員提供的一些參數:

漢字是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藍牙打印機開發)。

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

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

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

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

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

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

好了文筆不好就寫到這吧

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容