前言
前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用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();
- }
- }
- }
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流进行输出打印,它们的打印指令都是一样的,可以下载打印手册,针对不同的设置,使用不同的打印指令即可。
某打印指令文档,仅供参考 : http://download.csdn.net/detail/haovip123/9702573