我想在我的应用程序中按下按钮并将 pdf 文档发送到打印机直接打印(不显示来自打印框架 Android 4.4 的系统 android 预览)。我该怎么做?我试图通过 Socket 连接到打印机。没问题,没有例外,但我的打印机没有响应,也没有打印任何内容。
也许我需要在手机上为混凝土打印机设置驱动程序?但是怎么做,我在哪里可以得到这样的驱动程序?
已编辑
我想在我的应用程序中按下按钮并将 pdf 文档发送到打印机直接打印(不显示来自打印框架 Android 4.4 的系统 android 预览)。我该怎么做?我试图通过 Socket 连接到打印机。没问题,没有例外,但我的打印机没有响应,也没有打印任何内容。
也许我需要在手机上为混凝土打印机设置驱动程序?但是怎么做,我在哪里可以得到这样的驱动程序?
已编辑
我编写了一个类来帮助将 PDF 文件直接打印到网络打印机,并提供其 IP。它应该适用于大多数打印机,只要它们支持 PJL 命令。
public class PrintService {
private static PrintListener printListener;
public enum PaperSize {
A4,
A5
}
public static void printPDFFile(final String printerIP, final int printerPort,
final File file, final String filename, final PaperSize paperSize, final int copies) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
Socket socket = null;
DataOutputStream out = null;
FileInputStream inputStream = null;
try {
socket = new Socket(printerIP, printerPort);
out = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream());
inputStream = new FileInputStream(file);
byte[] buffer = new byte[3000];
final char ESC = 0x1b;
final String UEL = ESC + "%-12345X";
final String ESC_SEQ = ESC + "%-12345\r\n";
out.writeBytes(UEL);
out.writeBytes("@PJL \r\n");
out.writeBytes("@PJL JOB NAME = '" + filename + "' \r\n");
out.writeBytes("@PJL SET PAPER=" + paperSize.name());
out.writeBytes("@PJL SET COPIES=" + copies);
out.writeBytes("@PJL ENTER LANGUAGE = PDF\r\n");
while (inputStream.read(buffer) != -1)
out.write(buffer);
out.writeBytes(ESC_SEQ);
out.writeBytes("@PJL \r\n");
out.writeBytes("@PJL RESET \r\n");
out.writeBytes("@PJL EOJ NAME = '" + filename + "'");
out.writeBytes(UEL);
out.flush();
} catch (IOException e) {
e.printStackTrace();
if (printListener != null)
printListener.networkError();
} finally {
try {
if (inputStream != null)
inputStream.close();
if (out != null)
out.close();
if (socket != null)
socket.close();
if (printListener != null)
printListener.printCompleted();
} catch (IOException e) {
e.printStackTrace();
if (printListener != null)
printListener.networkError();
}
}
}
});
t.start();
}
public static void setPrintListener(PrintListener list) {
printListener = list;
}
public interface PrintListener {
void printCompleted();
void networkError();
}
}
@Cristian 用 AsyncTask 实现回答。使用此实现,您可以针对 PrintServiceListener 回调执行 UI 操作。
public class CustomPrinterService extends AsyncTask<Void, Void, Boolean> {
public enum PaperSize {
A4,
A5
}
private static final String TAG = "CustomPrinterService";
private PrintServiceListener mPrintServiceListener;
private String mPrinterIP;
private String mFilename;
private int mPrinterPort;
private int mNumberOfCopies;
private File mFile;
private PaperSize mPaperSize;
public CustomPrinterService(final String printerIP, final int printerPort, final File file,
final String filename, final PaperSize paperSize, final int copies) {
mPrinterIP = printerIP;
mPrinterPort = printerPort;
mFile = file;
mFilename = filename;
mPaperSize = paperSize;
mNumberOfCopies = copies;
}
@Override
protected Boolean doInBackground(Void... voids) {
Boolean result = null;
Socket socket = null;
DataOutputStream out = null;
FileInputStream inputStream = null;
try {
socket = new Socket(mPrinterIP, mPrinterPort);
out = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream());
inputStream = new FileInputStream(mFile);
byte[] buffer = new byte[3000];
final char ESC = 0x1b;
final String UEL = ESC + "%-12345X";
final String ESC_SEQ = ESC + "%-12345\r\n";
out.writeBytes(UEL);
out.writeBytes("@PJL \r\n");
out.writeBytes("@PJL JOB NAME = '" + mFilename + "' \r\n");
out.writeBytes("@PJL SET PAPER=" + mPaperSize.name());
out.writeBytes("@PJL SET COPIES=" + mNumberOfCopies);
out.writeBytes("@PJL ENTER LANGUAGE = PDF\r\n");
while (inputStream.read(buffer) != -1)
out.write(buffer);
out.writeBytes(ESC_SEQ);
out.writeBytes("@PJL \r\n");
out.writeBytes("@PJL RESET \r\n");
out.writeBytes("@PJL EOJ NAME = '" + mFilename + "'");
out.writeBytes(UEL);
out.flush();
} catch (Exception exception) {
Log.d(TAG, exception.toString());
result = false;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (out != null) {
out.close();
}
if (socket != null) {
socket.close();
}
if (result == null) {
result = true;
}
} catch (Exception exception) {
Log.d(TAG, exception.toString());
result = false;
}
}
return result;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
if (mPrintServiceListener != null) {
mPrintServiceListener.onPrintCompleted();
}
} else {
if (mPrintServiceListener != null) {
mPrintServiceListener.onNetworkError();
}
}
}
public void setPrintServiceListener(PrintServiceListener listener) {
mPrintServiceListener = listener;
}
public interface PrintServiceListener {
void onPrintCompleted();
void onNetworkError();
}
}
除了 Gokula 的回答:
也可以在设备上不保存文件的情况下执行此操作。就我而言,我使用字节数组或 base 64 来打印图像。
kotlin 中的代码 =)
打印机控制器调用
override fun write(content: String, address: String?) {
address?.let {
val policy: StrictMode.ThreadPolicy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
Base64.decode("Base64 image content goes here", Base64.DEFAULT).printByDeviceIp(address)
}
}
打印机扩展
fun ByteArray.printByDeviceIp(address: String) {
try {
val socket = Socket(address, PRINTER_DEFAULT_PORT)
val output = DataOutputStream(socket.getOutputStream())
val buffer = ByteArray(PRINTER_BUFFER_SIZE)
val inputStream = ByteArrayInputStream(this)
output.writeBytes(UEL)
output.writeBytes(PRINT_META_JOB_START)
output.writeBytes(PRINT_META_JOB_NAME)
output.writeBytes(PRINT_META_JOB_PAPER_TYPE)
output.writeBytes(PRINT_META_JOB_COPIES)
output.writeBytes(PRINT_META_JOB_LANGUAGE)
while (inputStream.read(buffer) != -1)
output.write(buffer)
output.writeBytes(ESC_SEQ)
output.writeBytes(UEL)
output.flush()
inputStream.close()
output.close()
socket.close()
} catch (e: Exception) {
when(e) {
is SocketException -> Log.e(this.javaClass.name, "Network failure: ${e.message}")
is SocketTimeoutException -> Log.e(this.javaClass.name, "Timeout: ${e.message}")
is IOException -> Log.e(this.javaClass.name, "Buffer failure: ${e.message}")
else -> Log.e(this.javaClass.name, "General failure: ${e.message}")
}
}
打印机作业常量
private const val PRINT_META_JOB_LABEL = "@PJL"
private const val PRINT_META_BREAK = "\r\n"
private const val ESCAPE_KEY = 0x1b.toChar()
const val UEL = "$ESCAPE_KEY%-12345X"
const val ESC_SEQ = "$ESCAPE_KEY%-12345 $PRINT_META_BREAK"
const val PRINT_META_JOB_START = "$PRINT_META_JOB_LABEL $PRINT_META_BREAK"
const val PRINT_META_JOB_NAME = "$PRINT_META_JOB_LABEL JOB NAME = 'INBOUND_FINISH' $PRINT_META_BREAK"
const val PRINT_META_JOB_PAPER_TYPE = "$PRINT_META_JOB_LABEL SET PAPER = A4"
const val PRINT_META_JOB_COPIES = "$PRINT_META_JOB_LABEL SET COPIES = 1"
const val PRINT_META_JOB_LANGUAGE = "$PRINT_META_JOB_LABEL ENTER LANGUAGE = PDF $PRINT_META_BREAK"
const val PRINTER_DEFAULT_PORT: Int = 9100
const val PRINTER_BUFFER_SIZE: Int = 3000