iOS套接字连接小票打印机

作者: c6e16b2e3a16 | 来源:发表于2015-11-20 23:33 被阅读4592次

    底部附demo链接
    最近在开发iOS连接打印机打印小票的功能,找了很多资料,本身相关资料就少,而且还全都是c#,java的.项目是用swift写的(OC思路差不多),现整理如下.

    准备工作:Xcode7.1,swift2.0,佳博GP80106 wifi打印机(根据打印机的不同,有些指令可能会有差异,但基本相同,用的都是ESC/POS指令)

    前提:在同一个局域网下,设置好打印机,设置好host,port

    一. Socket连接打印机

    使用CocoaAsyncSocket,wifi连接打印机.具体连接方法不是本文主要内容,可参考CocoaAsyncSocket的使用

    https://github.com/robbiehanson/CocoaAsyncSocket

    这个是OC库,所以要将AsyncSocket.h 包含到桥接文件中PrijectName-Bridging-Header.h

    //ViewController.swift
    import AsyncSocke
    var asyncSocket:AsyncSocket?
    //...
    //假设已经连接成功
    

    二. 编写之前,先来看看socket是如何发送指令的:

    asyncSocket.writeData(data: NSData!, withTimeout: NSTimeInterval, tag: Int)
    

    它是将所有指令数据写入到一个数据对象中,再发送到连接的设备(打印机),那么首先创建一个NSData对象,来储存指令

    let sendData = NSMutableData(capacity: 0)!
    asyncSocket.writeData(sendData, withTimeout: -1, tag: 0)
    

    最后将指令发送,因此在这里,关键就是构建sendData对象

    先来创建一个通用方法,将每一条指令都写入sendData中(如果现在不知道怎么回事,看下去就明白了)

    func addBytesCommand(command:UnsafePointer, length:Int){
          self.sendData.appendBytes(command, length: length)
    }
    

    三. 举几个例子,来演示一下如何发送指令

    根据编程手册,"横向和纵向移动单位"在很多设置间距的地方有使用到,那么先来解决这条指令.

    1. GS P x y设置横向和纵向移动单位

    [格式]

    ASCII码 GS P x y
    十六进制码 1D 50 x y
    十进制码 29 80 x y

    [范围] 0≤x≤255 0≤y≤255
    [描述] •分别将横向移动单位近似设置成25.4/ x mm(1/ x英寸)纵向移动单位设置成25.4/ y mm(1/ y英寸)。

    • 当x和y为0时,x和y被设置成默认值,默认值x=200,y=200。

    先来解释一下,GS, P就是ASCII码,下面对应的是十六进制和十进制,这里使用十六进制

    func printDotDistance(x:UInt8, y:UInt8){
           var char:[UInt8] = [0x1D,0x50]
           char.append(x)
           char.append(y)
          //步骤2中创建的通用数据写入方法
           addBytesCommand(char, length: char.count)
    }
    

    直接使用指令中参数有时会让你不知所云,当我们将这个接口提供给别人用的时候,他们或许并不知道x,y是什么意思.所以很有必要将参数设置成大家都明白的意思(之后也会看到其他方法),改动如下

    /**
    设置横向和纵向移动单位
    - parameter horizontal: 横向移动单位
    - parameter vertical:  纵向移动单位
    */
    
    func printDotDistance(w w:Float, h:Float){
           var char = [0x1D,0x50]
           char.append(Int(25.4/w))
           char.append(Int(25.4/h))
           addBytesCommand(char, length: char.count)
    }
    

    w,h是我希望设置的左右或上下移动的单位距离,单位mm.根据0≤x≤255,0≤y≤255和"移动单位近似设置成25.4/ x mm" 的规定,上述方法中w,h也是有范围的,不要越界了,不然指令无效,会变成默认设置

    下面再来看一条

    2.GS L nL nH 设置左边距

    [格式]

    ASCII码 GS L nL nH
    十六进制码 1D 4C nL nH
    十进制码 29 76 nL nH

    [范围] 0≤nL≤255,0≤nH≤255
    [描述] •用nL和nH设置左边距;
    •左边距设置为[( nL + nH × 256)×横向移动单位]]英寸。
    [默认值] nL = 0, nH = 0

    这里用到了刚才设置的"横向移动单位",我先调用以下方法,就将横向纵向移动单位设置成了0.1mm

    printDotDistance(w: 0.1, h: 0.1)
    

    和指令一一样,如果直接将nL,nH设置成参数,使用者不易读,因此参数需要转换下.很容易发现,nL就是模(余数),nH就是商

    /**
    设置左边距
    - parameter margin: 做边距,单位mm
    */
    func printLeftMargin(margin:CGFloat){
           var char:[UInt8] = [0x1D,0x4C]
           char.append(UInt8(margin%256))
           char.append(UInt8(margin/256))
           addBytesCommand(char, length: char.count)
    }
    

    3.文字打印

    /**
    
    添加文字
    
    - parameter text: 字符串
    
    */
    
    func printAddText(text:String){
    
    //文字编码转为GB_18030_2000
    
    let gbkeEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
    let data = text.dataUsingEncoding(gbkeEncoding)!
    let size = data.length
    let textData = malloc(size)
    data.getBytes(textData, length:size)
    addBytesCommand(textData, length: size)
    free(textData)
    }
    

    4.打印图片

    打印图片的方法是在github上找的,项目地址

    ThermalPrinterKit

    我用了其中转图片的方法,使用OC写的,因为项目急,直接用了.等有时间,转成swift,再帖上来.

    选择位图模式:ESC * m nL nH d1... dk

    ASCII码 ESC * m nL nH d1...dk
    十六进制码 1B 2A m nL nH d1...dk
    十进制码 27 42 m nL nH d1...dk

    [范围] m = 0, 1, 32, 33,0≤nL≤255,0≤nH≤3,0≤d≤255

    /**
    选择位图模式
    - parameter bitmap:    位图
    */
    
    func printBitmapModel(bitmap:UIImage){
    let data = IGThermalSupport.imageToThermalData(bitmap)//ThermalPrinterKit这个库中的方法
    let size = data.length
    let picData = malloc(size)
    data.getBytes(picData, length:size)
    addBytesCommand(picData, length: size)
    free(picData)
    }
    

    打印二维码,可以先生成二维码图片,再使用上面的方法写入数据.

    5.打印小票

    最后别忘了使用

    asyncSocket.writeData(sendData, withTimeout: -1, tag: 0)
    

    将数据发送给打印机

    四.注意点

    1. 为了方便使用,可以将socket连接、打印机管理方法分别封装,再封装一个小票管理类直接使用.
    2. ESC/POS指令中所有参数都是UInt8类型的,有时候可能是参数类型错误,将类型强转为UInt8(para)试试,可能就成功了
    3. 第一次开发打印机,如果有错误,欢迎指正交流.

    五.demo

    1.最近整理出了一个demo,是用OC写的,写了主要的几个方法
    https://github.com/songxiaam/MMPrinterDemo
    2.swift版demo下载
    https://pan.baidu.com/s/1nuKIKIH

    六.交流群

    刚建了个群,有兴趣的可以加群讨论下
    482958890

    相关文章

      网友评论

      • 22aa2e428a07:大神能发我最新的demo吗,我的邮箱756786809@qq.com
      • 97565376120e:楼主,标签打印机的指令在iOS中要怎么处理呢 用的是TSPL指令,有研究过吗
      • 扑腾的蛾子:您好,提示 写入成功 但是打印机没有反应,是怎末回事呢
      • liangZhen:楼主很赞,很好的一个开源,有一个小问题,希望楼主能解答一下,socket的传输内容的长度应该是有限制的,如果一段需要打印的信息很大,例如多张图片等情况,socket传输是否可靠?打印机能否完全打印?
      • 石缝小草:n = 1:传送打印机状态
        n = 2:传送脱机状态
        n = 3:传送错误状态
        n = 4:传送纸传感器状态

        像这些状态 打印机都会回馈 但不知道在哪里接受
      • 石缝小草:楼主 打印机已经连接成功 打印命令也下达 但由于打印机自身的原因没有打印(比如没纸 没有盖盖子) 想问的是怎么获取打印机没有打印所反馈的信息呢
      • d976e6bc9ea9:文章质量很高,谢谢分享。
      • 8bfca968135d:现在我们的需求时多个打印机选择某个打印,想知道怎么获取到打印机名字,并且选择打印机?
        8bfca968135d:@hello_me 好的 谢谢
        c6e16b2e3a16:@许你一世柔情 好像没有指令获取打印机指令.打印机的IP是唯一的,可以用这个选择
      • 落马洲:请问可以用xcode模拟器运行这个demo吗
      • Init_ZSJ:楼主你好,我最近也在做打印机打印小票,之前使用佳博的蓝牙打印机实现,后来老板说不行,要用网络的,我想用网口的打印机通过局域网连接传输数据打印,但是我技术有限实现不了,打电话去佳博官网,官网技术人员说他们技术也实现不了我笑了😄。对于你使用的wifi连接打印机我还没买,想买个实验一下,但是有点疑惑。移动端(我使用的是ipad)的wifi是直接连接打印机还是通过连接打印机所在的网段进行传输数据的呢?如果是直接连接打印机的wifi的话,那是不是移动端就不能再通过wifi连接移动网络的wifi呢,毕竟ipad设置的wifi只能连接一个wifi源,对于wifi打印机的连接原理能不能简单说明一下呢?谢谢楼主了
        c6e16b2e3a16:@Init_ZSJ 1
        Init_ZSJ:@hello_me 有点乱了,捋捋。1.ipad连接路由器,wifi打印机连接路由器 。 2. ipad直接连接wifi打印机的wifi。 你告诉我wifi打印机属于哪一种?
        c6e16b2e3a16:@Init_ZSJ 简单来说是两个步骤1.连接打印机.2.发送指令.对于网口/wifi打印机,使用socket连接,我demo中使用的是CocoaAsyncSocket这个第三方库.连接时,首先要配置好打印机的ip,创建连接时需要这个ip.这是在同一局域网下.如果需要实现远程连接打印/网络打印,则需要将打印机接入外网,或者有一个中转设备接收数据后再发送给打印机.iPad没有直接连接打印机wifi的功能,是将iPad和wifi打印机连在同一局域网下(同一路由下).
      • 猫粮_fy:求一份demo哦,楼主老师,18810950973@163.com
        c6e16b2e3a16:@猫粮_fy 文章底部有链接
      • 06b76cdccbc8:请问这个使用的话是针对7.0以下的还是所有设备都可以啊
        c6e16b2e3a16:写的demo是7.0以上的,应该都可以
      • adf61a070c47:有问题call你QQ了 。
      • itlingmao:楼主, 帮忙给我一份你的DEMO吧, 我想看看你那里有没有办法, 在打印前进行一个预览的效果. 邮箱 itlingmao@163.com
        c6e16b2e3a16:@elf精灵 预览需要你自定义打印视图,应该是模拟的,创建label,image等添加到view上。demo在GitHub上可以下载
      • Bob_Blog:楼主demo太给力了 :smile:
      • Freedom_Coco:找了半天资料后,终于找到一个适合自己的文章,下载demo后,运行起来后更开心。请问下楼主,如果要打印网页,怎么打印,项目很急。你的代码我还没看懂,难了点。
        Freedom_Coco:@hello_me 因为在想,既然都让打印动了,看有什么办法将网页打印下来。这样就嗨翻天了。苹果自带的Airprint太局限了。
        Freedom_Coco:@hello_me 现在就是想通过打印机将网页打印下来,这样一个功能。找了很多的资料都不行。看到楼主的文章是唯一可以让打印机动的代码,楼主有什么办法么。
        c6e16b2e3a16:这是小票打印机的,你是要把整个网页打印到小票上?
      • Freedom_Coco:找了半天资料后,终于找到一个适合自己的文章,下载demo后,运行起来后更开心。请问下楼主,如果要打印网页,怎么打印,项目很急。你的代码我还没看懂,难了点。
      • Freedom_Coco:找了半天资料后,终于找到一个适合自己的文章,下载demo后,运行起来后更开心。请问下楼主,如果要打印网页,怎么打印,项目很急。你的代码我还没看懂,难了点。
      • 判若两人丶:支持一下
      • iOS_YXT:楼主老师,用了你的demo搞定了,赞一个 :kissing_heart:
        c6e16b2e3a16:@iOS_YXT 很高兴能帮到你:smile:
      • 08e6622fa29d:或者说你对CoreBluetooth 有了解么?
        CoreBluetooth 和 socket连接 哪个好一点?
        我们公司安卓的是一个外国人,他就用的socket连接 做的。
        不过他已经做完成了(说是用了第三方库)。
      • 08e6622fa29d:楼主可否创建一个qq群,或者能否告诉我qq。
        我最近也在做 微型打印机(58mm 和 80mm的)。
        目前用的是OC 的CoreBluetooth 框架写的。
        使用的是一款,80mm的 热敏打印机。
        现在可以打印文字,二维码,条形码,但是打印不了图片。
        touchofsun:@一江烟花 请问下你二维码是怎么打印的呢?
        c6e16b2e3a16:@一江烟花 刚建了个群:482958890,欢迎交流
      • gyjshow:m_imageData[result_index++] = 29;
        m_imageData[result_index++] = 51;
        m_imageData[result_index++] = 24;
        m_imageData[result_index++] = 27;
        m_imageData[result_index++] = 42;
        m_imageData[result_index++] = 33;
        m_imageData[result_index++] = width%256;
        m_imageData[result_index++] = width/256;

        前八个字节 参数值不一致(文档规定的),你这个算法就不能打印出来了!!!
        咨询一下
        gyjshow:主要是打印位图的算法有些搞不清楚。按照文档的参数值,把图片转成需要的data.
        一下是java的(实用于android):使用光栅位图打印!https://github.com/yefengfreedom/BtPrinter/blob/master/app/src/main/java/com/yefeng/night/btprinter/print/PrintPic.java
        c6e16b2e3a16:@gyjshow 我试了下果然打不出来了.我开始是用swift写的,这个打印图片的方法我是在github上找得,在swift中使用没问题.我再研究下,如果解决了,也希望分享下方法.
      • 土土的BBer:楼主方便的话也给我一份吧,seclery@qq.com ,谢谢。
        c6e16b2e3a16:@土土的BBer 刚刚整理出了一个demo,https://github.com/songxiaam/MMPrinterDemo
      • 不知晓:楼主,求份Demo 1069661410@qq.com,谢谢
      • 幸福的李雨龙:跪求demo,分享一下,不知道楼主的是那款打印机,我们在开发佳博的小票打印机app :pray:
        幸福的李雨龙: @hello_me lylapp@163.com
        谢谢大神
        c6e16b2e3a16:@幸福的李雨龙 我们用的也是佳博,还没有整理出demo,你留个邮箱,我把关键的几个文件发给你
      • 升鲜宝:我也求一份demo,楼主方便的话给我一份 823092482@qq.com 谢谢.
      • 最后剩下的还是自己:已收到,谢谢 :smiley:
      • 最后剩下的还是自己:我也求一份demo,楼主方便的话给我一份 2901962186@qq.com
      • f3d530f94c75:求楼主demo 449035798@qq.com 另外想咨询下,在设置字符间距的时候为什么只有英文生效,而汉字无效,还有下划线模式?
      • a812e3d605d1:楼主,我也求一份demo 麻烦你了 13710121681@163.com
        a812e3d605d1:@hello_me IGThermalSupport.h IGThermalSupport.m 就这两个文件旧可以了吗 楼主 :flushed:
        a812e3d605d1:@hello_me 请教楼主 那个图片打印的第三方框架需要导入哪些文件呢?
        c6e16b2e3a16:@luotianguantou 因为我们公司的项目还在修改当中,暂时没做demo,我把主要的几个文件发给你了,希望对你有帮助.有问题可以再交流.
      • hhhhxy:你好,我也想求一份demo,huangxinyu1213@163.com,谢谢
        hhhhxy:@hello_me 收到了,十分感谢楼主
        c6e16b2e3a16:@iOS_huangxy 因为我们公司的项目还在修改当中,暂时没做demo,我把主要的几个文件发给你了,希望对你有帮助.有问题可以再交流.
      • zmp1123:能分享下这部分的demo吗,包括Socket连接的,谢谢了
        c6e16b2e3a16:@zmp1123 发给你了,有问题再交流.
        zmp1123:@hello_me 841777471@qq.com,谢谢了啊
        c6e16b2e3a16:@zmp1123 项目还在开发中,没有完全封装好。你留个邮箱我发给你个现在的demo。

      本文标题:iOS套接字连接小票打印机

      本文链接:https://www.haomeiwen.com/subject/bmglhttx.html