Android进阶——安卓调用ESC/POS打印机打印实例

前言

前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用socket连接,来实现打印功能。写了个Demo,分享一下。

工具:一台打印机(芯烨XP-80XX),一台安卓测试机

开发环境:Android Studio 1.5

需求:点击按钮,实现打印小票功能,小票上除必要文字外,还要有二维码。

封装了一个Pos打印工具类:

package com.example.haoguibao.myapplication; 

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket; 

/**
 * Created by haoguibao on 16/2/18.
 * Description : 封装Pos机打印工具类
 * Revision :
 */
public class Pos {
  //定义编码方式
  private static String encoding = null; 

  private Socket sock = null;
  // 通过socket流进行读写
  private OutputStream socketOut = null;
  private OutputStreamWriter writer = null; 

  /**
   * 初始化Pos实例
   *
   * @param ip 打印机IP
   * @param port 打印机端口号
   * @param encoding 编码
   * @throws IOException
   */
  public Pos(String ip, int port, String encoding) throws IOException {
    sock = new Socket(ip, port);
    socketOut = new DataOutputStream(sock.getOutputStream());
    this.encoding = encoding;
    writer = new OutputStreamWriter(socketOut, encoding);
  } 

  /**
   * 关闭IO流和Socket
   *
   * @throws IOException
   */
  protected void closeIOAndSocket() throws IOException {
    writer.close();
    socketOut.close();
    sock.close();
  } 

  /**
   * 打印二维码
   *
   * @param qrData 二维码的内容
   * @throws IOException
   */
  protected void qrCode(String qrData) throws IOException {
    int moduleSize = 8;
    int length = qrData.getBytes(encoding).length; 

    //打印二维码矩阵
    writer.write(0x1D);// init
    writer.write("(k");// adjust height of barcode
    writer.write(length + 3); // pl
    writer.write(0); // ph
    writer.write(49); // cn
    writer.write(80); // fn
    writer.write(48); //
    writer.write(qrData); 

    writer.write(0x1D);
    writer.write("(k");
    writer.write(3);
    writer.write(0);
    writer.write(49);
    writer.write(69);
    writer.write(48); 

    writer.write(0x1D);
    writer.write("(k");
    writer.write(3);
    writer.write(0);
    writer.write(49);
    writer.write(67);
    writer.write(moduleSize); 

    writer.write(0x1D);
    writer.write("(k");
    writer.write(3); // pl
    writer.write(0); // ph
    writer.write(49); // cn
    writer.write(81); // fn
    writer.write(48); // m 

    writer.flush(); 

  } 

  /**
   * 进纸并全部切割
   *
   * @return
   * @throws IOException
   */
  protected void feedAndCut() throws IOException {
    writer.write(0x1D);
    writer.write(86);
    writer.write(65);
    //    writer.write(0);
    //切纸前走纸多少
    writer.write(100);
    writer.flush(); 

    //另外一种切纸的方式
    //    byte[] bytes = {29, 86, 0};
    //    socketOut.write(bytes);
  } 

  /**
   * 打印换行
   *
   * @return length 需要打印的空行数
   * @throws IOException
   */
  protected void printLine(int lineNum) throws IOException {
    for (int i = 0; i < lineNum; i++) {
      writer.write("\n");
    }
    writer.flush();
  } 

  /**
   * 打印换行(只换一行)
   *
   * @throws IOException
   */
  protected void printLine() throws IOException {
    writer.write("\n");
    writer.flush();
  } 

  /**
   * 打印空白(一个Tab的位置,约4个汉字)
   *
   * @param length 需要打印空白的长度,
   * @throws IOException
   */
  protected void printTabSpace(int length) throws IOException {
    for (int i = 0; i < length; i++) {
      writer.write("\t");
    }
    writer.flush();
  } 

  /**
   * 打印空白(一个汉字的位置)
   *
   * @param length 需要打印空白的长度,
   * @throws IOException
   */
  protected void printWordSpace(int length) throws IOException {
    for (int i = 0; i < length; i++) {
      writer.write(" ");
    }
    writer.flush();
  } 

  /**
   * 打印位置调整
   *
   * @param position 打印位置 0:居左(默认) 1:居中 2:居右
   * @throws IOException
   */
  protected void printLocation(int position) throws IOException {
    writer.write(0x1B);
    writer.write(97);
    writer.write(position);
    writer.flush();
  } 

  /**
   * 绝对打印位置
   *
   * @throws IOException
   */
  protected void printLocation(int light, int weight) throws IOException {
    writer.write(0x1B);
    writer.write(0x24);
    writer.write(light);
    writer.write(weight);
    writer.flush();
  } 

  /**
   * 打印文字
   *
   * @param text
   * @throws IOException
   */
  protected void printText(String text) throws IOException {
    String s = text;
    byte[] content = s.getBytes("gbk");
    socketOut.write(content);
    socketOut.flush();
  } 

  /**
   * 新起一行,打印文字
   *
   * @param text
   * @throws IOException
   */
  protected void printTextNewLine(String text) throws IOException {
    //换行
    writer.write("\n");
    writer.flush(); 

    String s = text;
    byte[] content = s.getBytes("gbk");
    socketOut.write(content);
    socketOut.flush();
  } 

  /**
   * 初始化打印机
   *
   * @throws IOException
   */
  protected void initPos() throws IOException {
    writer.write(0x1B);
    writer.write(0x40);
    writer.flush();
  } 

  /**
   * 加粗
   *
   * @param flag false为不加粗
   * @return
   * @throws IOException
   */
  protected void bold(boolean flag) throws IOException {
    if (flag) {
      //常规粗细
      writer.write(0x1B);
      writer.write(69);
      writer.write(0xF);
      writer.flush();
    } else {
      //加粗
      writer.write(0x1B);
      writer.write(69);
      writer.write(0);
      writer.flush();
    }
  }
}

其中,打印机的IP和端口号从打印机的属性设置处可查。

MainActivity中进行调用:

package com.example.haoguibao.myapplication; 

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button; 

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List; 

public class MainActivity extends AppCompatActivity {
  //订单菜品集合
  private List<FoodsBean> foodsBean; 

  private Pos pos; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); 

    Button bt_print = (Button) findViewById(R.id.button); 

    bt_print.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) { 

        // 开启一个子线程
        new Thread() {
          public void run() {
            try {
              pos = new Pos("IP", 9100, "GBK");  //第一个参数是打印机网口IP 

              //初始化打印机
              pos.initPos(); 

              //初始化订单数据
              initData(); 

              pos.bold(true);
              pos.printTabSpace(2);
              pos.printWordSpace(1);
              pos.printText("**测试店铺"); 

              pos.printLocation(0);
              pos.printTextNewLine("----------------------------------------------");
              pos.bold(false);
              pos.printTextNewLine("订 单 号:1005199");
              pos.printTextNewLine("用 户 名:15712937281");
              pos.printTextNewLine("桌  号:3号桌");
              pos.printTextNewLine("订单状态:订单已确认");
              pos.printTextNewLine("订单日期:2016/2/19 12:34:53");
              pos.printTextNewLine("付 款 人:线下支付(服务员:宝哥)");
              pos.printTextNewLine("服 务 员:1001");
              pos.printTextNewLine("订单备注:不要辣,少盐");
              pos.printLine(2); 

              pos.printText("品项");
              pos.printLocation(20, 1);
              pos.printText("单价");
              pos.printLocation(99, 1);
              pos.printWordSpace(1);
              pos.printText("数量");
              pos.printWordSpace(3);
              pos.printText("小计");
              pos.printTextNewLine("----------------------------------------------"); 

              for (FoodsBean foods : foodsBean) {
                pos.printTextNewLine(foods.getName());
                pos.printLocation(20, 1);
                pos.printText(foods.getPrice());
                pos.printLocation(99, 1);
                pos.printWordSpace(1);
                pos.printText(foods.getNumber());
                pos.printWordSpace(3);
                pos.printText(foods.getSum());
              } 

              pos.printTextNewLine("----------------------------------------------"); 

              pos.printLocation(1);
              pos.printLine(2);
              //打印二维码
              pos.qrCode("http://blog.csdn.net/haovip123"); 

              //切纸
              pos.feedAndCut(); 

              pos.closeIOAndSocket();
              pos = null;
            } catch (UnknownHostException e) {
              e.printStackTrace();
            } catch (IOException e) {
              e.printStackTrace();
            }
          } 

        }.start(); 

      }
    });
  } 

  private void initData() {
    foodsBean = new ArrayList<>(); 

    for (int i = 0; i < 4; i++) {
      FoodsBean fb = new FoodsBean();
      fb.setName("测试菜品" + i);
      fb.setPrice("90.00");
      fb.setNumber("1" + i);
      fb.setSum("10" + i + ".00");
      foodsBean.add(fb);
    }
  }
} 

附:小票中菜品的Bean类

public class FoodsBean {
  private String name;
  private String price;
  private String number;
  private String sum; 

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getPrice() {
    return price;
  }
  public void setPrice(String price) {
    this.price = price;
  }
  public String getNumber() {
    return number;
  }
  public void setNumber(String number) {
    this.number = number;
  }
  public String getSum() {
    return sum;
  }
  public void setSum(String sum) {
    this.sum = sum;
  }
}

打印小票样品如图:

小结:

对于调用打印机,不论使用Java语言还是其他语言,思路都是一样的,利用Socket连接上打印机以后,通过IO流进行输出打印,它们的打印指令都是一样的,可以下载打印手册,针对不同的设置,使用不同的打印指令即可。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

    上一篇 主要介绍了如何通过蓝牙连接到打印机.这一篇,我们就介绍如何向打印机发送打印指令,来打印字符和图片. 1. 构造输出流 首先要明确一点,就是蓝牙连接打印机这种场景下,手机是 Client 端,打印机是 Server 端. 在上一篇的最后,我们从 BluetoothSocket 得到了一个OutputStream.这里我们做一层包装,得到一个OutputStreamWriter 对象: OutputStreamWriter writer = new OutputStreamWriter(ou

  • Android下的POS打印机调用的简单实现

    本文基于GP58系列,它可以兼容ESC/POS指令集,对EPSON的打印机通用. Android下的设备调试,如果设备提供了驱动,按照厂家的驱动调试即可:设备未提供驱动,只能按照通用的方法进行调试.这里采用的是调用USB接口来控制打印机输出. 1.首先获取USB管理器 public UsbAdmin(Context context) { mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); mPermi

  • Android 蓝牙连接 ESC/POS 热敏打印机打印实例(蓝牙连接篇)

    公司的一个手机端的 CRM 项目最近要增加小票打印的功能,就是我们点外卖的时候经常会见到的那种小票.这里主要涉及到两大块的知识: 蓝牙连接及数据传输 ESC/POS 打印指令 蓝牙连接不用说了,太常见了,这篇主要介绍这部分的内容.但ESC/POS 打印指令是个什么鬼?简单说,我们常见的热敏小票打印机都支持这样一种指令,只要按照指令的格式向打印机发送指令,哪怕是不同型号品牌的打印机也会执行相同的动作.比如打印一行文本,换行,加粗等都有对应的指令,这部分内容放在下一篇介绍. 本篇主要基于官方文档,相

  • Android进阶——安卓调用ESC/POS打印机打印实例

    前言 前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用socket连接,来实现打印功能.写了个Demo,分享一下. 工具:一台打印机(芯烨XP-80XX),一台安卓测试机 开发环境:Android Studio 1.5 需求:点击按钮,实现打印小票功能,小票上除必要文字外,还要有二维码. 封装了一个Pos打印工具类: package com.example.haoguibao.myapplication; import java.io.

  • Unity调用打印机打印图片

    本文实例为大家分享了Unity打印机打印图片的具体代码,供大家参考,具体内容如下 1.调用打印机首先就是要配置好打印机 就是电脑跟打印机已经连接好,有默认的打印机可以启动使用 2.调用方式 (1)使用外部第三方软件exe 代码如下:(就两句) string path = Application.dataPath + @"\Textures\002.png"; System.Diagnostics.Process.Start("mspaint.exe", path);

  • Android手机通过蓝牙连接佳博打印机的实例代码

    所使用的打印机为佳博打印机,支持蓝牙.wifi.usb我所使用的是通过蓝牙来连接. 在网上找到一个佳博官方针对安卓开发的App源码,但是各种的跳转,没有看太懂,所以又去问度娘,找到了一个不错的文章 Android对于蓝牙开发从2.0版本的sdk才开始支持,而且模拟器不支持,测试至少需要两部手机,所以制约了很多技术人员的开发. 1. 首先,要操作蓝牙,先要在AndroidManifest.xml里加入权限 // 管理蓝牙设备的权限 <uses-permissionandroid:name="

  • Android进阶之从IO到NIO的模型机制演进

    目录 引言 1 Basic IO模型 1.1 RandomAccessFile的缓冲区和BufferedInputStream缓冲区的区别 1.2 Basic IO模型底层原理 2 NIO模型 3 OKIO 引言 其实IO操作相较于服务端,客户端做的并不多,基本的场景就是读写文件的时候会使用到InputStream或者OutputStream,然而客户端能做的就是发起一个读写的指令,真正的操作是内核层通过ioctl指令执行读写操作,因为每次的IO操作都涉及到了线程的操作,因此会有性能上的损耗,那

  • Android进阶Handler应用线上卡顿监控详解

    目录 引言 1 Handler消息机制 1.1 方案确认 1.2 Looper源码 1.3 Blockcanary原理分析 1.4 Handler监控的缺陷 2 字节码插桩实现方法耗时监控 2.1 字节码插桩流程 2.2 引入ASM实现字节码插桩 2.3 Blockcanary的优化策略 引言 在上一篇文章中# Android进阶宝典 -- KOOM线上APM监控最全剖析,我详细介绍了对于线上App内存监控的方案策略,其实除了内存指标之外,经常有用户反馈卡顿问题,其实这种问题是最难定位的,因为不

  • Android进阶KOOM线上APM监控全面剖析

    目录 正文 1 Leakcanary为什么不能用于线上 1.1 Leakcanary原理简单剖析 1.2 小结 2 KOOM原理分析 2.1 KOOM引入 2.2 KOOM源码分析 2.2.1 trackOOM方法分析 2.2.2 HeapOOMTracker 2.2.3 ThreadOOMTracker 2.2.4 FastHugeMemoryOOMTracker 2.3 dump为何不能放在子线程 2.3.1 ForkJvmHeapDumper分析 2.3.2 C++层分析dumpHprof

  • Android进阶NestedScroll嵌套滑动机制实现吸顶效果详解

    目录 引言 1 自定义滑动布局,实现吸顶效果 1.1 滑动容器实现 1.2 嵌套滑动机制完成交互优化 1.2.1 NestedScrollingParent接口和NestedScrollingChild接口 1.2.2 预滚动阶段实现 1.2.3 滚动阶段实现 1.2.4 滚动结束 引言 在上一篇文章Android进阶宝典 -- 事件冲突怎么解决?先从Android事件分发机制开始说起中,我们详细地介绍了Android事件分发机制,其实只要页面结构复杂,联动众多就会产生事件冲突,处理不得当就是b

随机推荐