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流進行輸出打印,它們的打印指令都是一樣的,可以下載打印手冊,針對不同的設置,使用不同的打印指令即可。


某打印指令文檔,僅供參考 : http://download.csdn.net/detail/haovip123/9702573

吐槽一下,資源下載積分,不是我設置的,csdn什麼積分計算算法給運算出來的,我都沒有權限更改,無語...



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章