Android進(jìn)階——安卓調(diào)用ESC/POS打印機(jī)打印實(shí)例
前言
前一段時(shí)間由于工作需要,要研究一下安卓程序調(diào)用打印機(jī)打印小票,并且要求不能使用藍(lán)牙調(diào)用,研究了一下,可以利用socket連接,來(lái)實(shí)現(xiàn)打印功能。寫(xiě)了個(gè)Demo,分享一下。
工具:一臺(tái)打印機(jī)(芯燁XP-80XX),一臺(tái)安卓測(cè)試機(jī)
開(kāi)發(fā)環(huán)境:Android Studio 1.5
需求:點(diǎn)擊按鈕,實(shí)現(xiàn)打印小票功能,小票上除必要文字外,還要有二維碼。
封裝了一個(gè)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機(jī)打印工具類
* Revision :
*/
public class Pos {
//定義編碼方式
private static String encoding = null;
private Socket sock = null;
// 通過(guò)socket流進(jìn)行讀寫(xiě)
private OutputStream socketOut = null;
private OutputStreamWriter writer = null;
/**
* 初始化Pos實(shí)例
*
* @param ip 打印機(jī)IP
* @param port 打印機(jī)端口號(hào)
* @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);
}
/**
* 關(guān)閉IO流和Socket
*
* @throws IOException
*/
protected void closeIOAndSocket() throws IOException {
writer.close();
socketOut.close();
sock.close();
}
/**
* 打印二維碼
*
* @param qrData 二維碼的內(nèi)容
* @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();
}
/**
* 進(jìn)紙并全部切割
*
* @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 需要打印的空行數(shù)
* @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();
}
/**
* 打印空白(一個(gè)Tab的位置,約4個(gè)漢字)
*
* @param length 需要打印空白的長(zhǎng)度,
* @throws IOException
*/
protected void printTabSpace(int length) throws IOException {
for (int i = 0; i < length; i++) {
writer.write("\t");
}
writer.flush();
}
/**
* 打印空白(一個(gè)漢字的位置)
*
* @param length 需要打印空白的長(zhǎng)度,
* @throws IOException
*/
protected void printWordSpace(int length) throws IOException {
for (int i = 0; i < length; i++) {
writer.write(" ");
}
writer.flush();
}
/**
* 打印位置調(diào)整
*
* @param position 打印位置 0:居左(默認(rèn)) 1:居中 2:居右
* @throws IOException
*/
protected void printLocation(int position) throws IOException {
writer.write(0x1B);
writer.write(97);
writer.write(position);
writer.flush();
}
/**
* 絕對(duì)打印位置
*
* @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();
}
/**
* 初始化打印機(jī)
*
* @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) {
//常規(guī)粗細(xì)
writer.write(0x1B);
writer.write(69);
writer.write(0xF);
writer.flush();
} else {
//加粗
writer.write(0x1B);
writer.write(69);
writer.write(0);
writer.flush();
}
}
}
其中,打印機(jī)的IP和端口號(hào)從打印機(jī)的屬性設(shè)置處可查。
MainActivity中進(jìn)行調(diào)用:
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) {
// 開(kāi)啟一個(gè)子線程
new Thread() {
public void run() {
try {
pos = new Pos("IP", 9100, "GBK"); //第一個(gè)參數(shù)是打印機(jī)網(wǎng)口IP
//初始化打印機(jī)
pos.initPos();
//初始化訂單數(shù)據(jù)
initData();
pos.bold(true);
pos.printTabSpace(2);
pos.printWordSpace(1);
pos.printText("**測(cè)試店鋪");
pos.printLocation(0);
pos.printTextNewLine("----------------------------------------------");
pos.bold(false);
pos.printTextNewLine("訂 單 號(hào):1005199");
pos.printTextNewLine("用 戶 名:15712937281");
pos.printTextNewLine("桌 號(hào):3號(hào)桌");
pos.printTextNewLine("訂單狀態(tài):訂單已確認(rèn)");
pos.printTextNewLine("訂單日期:2016/2/19 12:34:53");
pos.printTextNewLine("付 款 人:線下支付(服務(wù)員:寶哥)");
pos.printTextNewLine("服 務(wù) 員:1001");
pos.printTextNewLine("訂單備注:不要辣,少鹽");
pos.printLine(2);
pos.printText("品項(xiàng)");
pos.printLocation(20, 1);
pos.printText("單價(jià)");
pos.printLocation(99, 1);
pos.printWordSpace(1);
pos.printText("數(shù)量");
pos.printWordSpace(3);
pos.printText("小計(jì)");
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("測(cè)試菜品" + 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;
}
}
打印小票樣品如圖:

小結(jié):
對(duì)于調(diào)用打印機(jī),不論使用Java語(yǔ)言還是其他語(yǔ)言,思路都是一樣的,利用Socket連接上打印機(jī)以后,通過(guò)IO流進(jìn)行輸出打印,它們的打印指令都是一樣的,可以下載打印手冊(cè),針對(duì)不同的設(shè)置,使用不同的打印指令即可。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)PDF預(yù)覽打印功能
- Android gradle插件打印時(shí)間戳的方法詳解
- Android編程實(shí)現(xiàn)計(jì)算兩個(gè)日期之間天數(shù)并打印所有日期的方法
- Android中如何安全地打印日志詳解
- Mac 下 Android Studio 不打印日志的解決辦法
- Android jni調(diào)試打印char陣列的實(shí)例詳解
- Android下的POS打印機(jī)調(diào)用的簡(jiǎn)單實(shí)現(xiàn)
- Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(ESC/POS指令篇)
- Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(藍(lán)牙連接篇)
- Android打印機(jī)--小票打印格式及模板設(shè)置實(shí)例代碼
- Android手機(jī)通過(guò)藍(lán)牙連接佳博打印機(jī)的實(shí)例代碼
- Android實(shí)現(xiàn)系統(tǒng)打印功能
相關(guān)文章
關(guān)于Android內(nèi)存緩存LruCache的使用及其源碼解析
LruCache作為內(nèi)存緩存,使用強(qiáng)引用方式緩存有限個(gè)數(shù)據(jù),當(dāng)緩存的某個(gè)數(shù)據(jù)被訪問(wèn)時(shí),它就會(huì)被移動(dòng)到隊(duì)列的頭部,本文詳細(xì)介紹了關(guān)于Android內(nèi)存緩存LruCache的使用及其源碼解析,需要的朋友可以參考下2023-05-05
Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Android Studio輕松構(gòu)建自定義模板的步驟記錄
這篇文章主要給大家介紹了關(guān)于Android Studio輕松構(gòu)建自定義模板的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10
Android PopupWindow全屏詳細(xì)介紹及實(shí)例代碼
這篇文章主要介紹了 Android PopupWindow全屏詳細(xì)介紹及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android實(shí)現(xiàn)多線程下載圖片的方法
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)多線程下載圖片的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
android編程實(shí)現(xiàn)對(duì)話框的封裝實(shí)例
這篇文章主要介紹了android編程實(shí)現(xiàn)對(duì)話框的封裝,以實(shí)例形式分析了Android針對(duì)對(duì)話框的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11

