Skip to content

Java SDK

The Java SDK supports native Android applications and connects to printers over Bluetooth Classic / SPP.

The SDK is published on the GitLab Maven Registry.

repositories {
maven {
url 'https://gitlab.com/api/v4/projects/35052067/packages/maven'
}
}

Choose the dependencies for the command languages you need:

dependencies {
// CPCL Commands
implementation 'com.printer.psdk:fat-generic-cpcl-bluetooth-classic:0.1.8-GA'
// ESC Commands
implementation 'com.printer.psdk:fat-generic-esc-bluetooth-classic:0.1.8-GA'
// TSPL Commands
implementation 'com.printer.psdk:fat-generic-tspl-bluetooth-classic:0.1.8-GA'
}
// Option 1: Find by Bluetooth scanning
BluetoothDevice device = getIntent().getParcelableExtra("device");
// Option 2: Using MAC Find by address
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter()
.getRemoteDevice(bluetoothAddress);
Connection connection = ClassicBluetooth.getInstance()
.createConnection(device, new ConnectListener() {
@Override
public void onConnectSuccess(ConnectedDevice connectedDevice) {
// Connected
Log.d("PSDK", "Connected: " + connectedDevice.getName());
}
@Override
public void onConnectFailed(Exception e) {
// Connection failed
Log.e("PSDK", "Connection failed: " + e.getMessage());
}
@Override
public void onDisconnect() {
// Disconnected
Log.d("PSDK", "Disconnected");
}
});
DataListener.with(connectedDevice).listen(new ListenAction() {
@Override
public void action(byte[] bytes) {
// Handle data returned by the printer
String response = new String(bytes);
Log.d("PSDK", "Printer response: " + response);
}
});

ESC commands are widely used by thermal receipt printers. See the ESC command reference for details.

Recommended sequence:

  1. Wake the printer
  2. Enable the printer
  3. Print the image
  4. Position the paper (not needed for continuous paper)
  5. End the print job
GenericESC esc = PrintUtil.getInstance().esc();
esc.wakeup();
esc.enable();
esc.image(EImage.builder()
.image(new AndroidSourceImage(bitmap))
// .compress(true) // Enable compression for printers that support it
.build());
esc.position();
esc.stopJob();
safeWrite(esc);
esc.wakeup();
esc.enable();
esc.image(EImage.builder()
.image(new AndroidSourceImage(bitmap))
.build());
esc.position();
esc.stopJob();
// Set shutdown timeout (Units: Minutes, Integer values only)
esc.setShutdownTime(10);
// Set print density (0:Low density 1:Medium density 2:High density)
esc.thickness(3);
esc.paperType(
EPaperType.builder()
.type(EPaperType.Type.CONTINUOUS_REEL_PAPER)
.build()
);
esc.paperTypeQ3(
EGetPaperTypeQ3.builder()
.type(EGetPaperTypeQ3.Type.GAP)
.build()
);
// Query printer information
esc.info();
// Query printer status
esc.state();
// Query battery level
esc.batteryVolume();
// Query Bluetooth name
esc.name();
// Query firmware version
esc.printerVersion();
// Query MAC Address
esc.mac();
// Query SN Number
esc.sn();
// Query printer model
esc.model();

When an abnormal condition occurs, the printer sends a two-byte status message to the application.

HeaderStatus typeMeaning
0xFF0x00Printer normal
0xFF0x01Overheated
0xFF0x02Cover open
0xFF0x04Out of paper
0xFF0x08Low voltage

The device sends a report when the detected paper does not match the paper type configured by the application:

HeaderStatus typeMeaning
0xFE0x01Fanfold black mark paper
0xFE0x02Continuous roll paper
0xFE0x03Adhesive gap labels
HeaderStatus typeMeaning
0xFD0x01Start clearing the current page’s print job
0xFD0x02Current print job cleared

CPCL commands are used by portable label printers. See the CPCL command reference for details.

GenericCPCL cpcl = CPCL.generic(connectedDevice);
cpcl.page(new CPCLPage().width(576).height(400))
.text(new CPCLText().x(50).y(50).content("商品标签"))
.barcode(new CBar().x(50).y(150).content("1234567890"))
.print(new CPrint())
.write();
GenericCPCL cpcl = CPCL.generic(connectedDevice);
cpcl.page(new CPage().width(576).height(400).copies(1))
// Set bold
.bold(true)
// Print title text
.text(CText.builder()
.font(Font.TSS24)
.textX(50).textY(30)
.content("商品标签")
.build())
.bold(false)
// Draw a separator line
.line(CLine.builder()
.x1(30).y1(70)
.x2(546).y2(70)
.width(2)
.build())
// Product information
.text(CText.builder()
.font(Font.TSS24)
.textX(30).textY(90)
.content("名称: 有机苹果")
.build())
.text(CText.builder()
.font(Font.TSS24)
.textX(30).textY(130)
.content("规格: 500g/袋")
.build())
.text(CText.builder()
.font(Font.TSS24)
.textX(30).textY(170)
.content("价格: ¥25.90")
.bold(true)
.build())
// 1D barcode
.bar(CBar.builder()
.x(80).y(220)
.codeType(CodeType.CODE128)
.height(50)
.lineWidth(1)
.content("6901234567890")
.build())
// QR code
.qrcode(CQRCode.builder()
.x(400).y(90)
.width(5)
.level(CorrectLevel.M)
.content("https://example.com/product")
.build())
// Rectangular outline
.box(CBox.builder()
.x1(20).y1(20)
.x2(556).y2(380)
.width(2)
.build())
.print(new CPrint())
.write();
Font enum-dot matrix sizeDescription
Font.TSS161616-dot matrix font
Font.TSS202020-dot matrix font
Font.TSS242424-dot matrix font (recommended)
Font.TSS282828-dot matrix font
Font.TSS323232-dot matrix font
Font.TSS24_MAX14824-dot font at 2× scale
Font.TSS24_MAX27224-dot font at 3× scale
Type enumDescription
CodeType.CODE128Code 128 (recommended)
CodeType.CODE39Code 39
CodeType.CODE93Code 93
CodeType.EAN8EAN-8
CodeType.EAN13EAN-13
CodeType.UPCAUPC-A
CodeType.UPCEUPC-E
CodeType.CODABARCodabar
CodeType.I2OF5Interleaved 2 of 5
// Query printer status
cpcl.status().write();
// Query SN Number
cpcl.sn().write();
// Query printer model
cpcl.model().write();
// Query firmware version
cpcl.version().write();
// Query battery level
cpcl.batteryVolume().write();

TSPL commands are used by label and barcode printers. See the TSPL command reference for details.

GenericTSPL tspl = TSPL.generic(connectedDevice);
tspl.page(new TPage().width(60).height(40))
.gap(true)
.direction(TDirection.builder()
.direction(Direction.UP)
.mirror(Mirror.NO_MIRROR)
.build())
.cls()
.text(TText.builder()
.x(50).y(50)
.font(Font.TSS24)
.content("标签内容")
.build())
.print(1)
.write();
GenericTSPL tspl = TSPL.generic(connectedDevice);
tspl.page(new TPage().width(60).height(40))
.gap(true)
.direction(TDirection.builder()
.direction(Direction.UP)
.mirror(Mirror.NO_MIRROR)
.build())
.density(8)
.speed(4)
.cls()
// Title
.text(TText.builder()
.x(180).y(30)
.font(Font.TSS24)
.xmulti(2).ymulti(2)
.content("商品标签")
.build())
// Separator line
.bar(TBar.builder()
.x(30).y(80)
.width(420).height(2)
.build())
// Product information
.text(TText.builder()
.x(30).y(100)
.font(Font.TSS24)
.content("品名: 有机苹果")
.build())
.text(TText.builder()
.x(30).y(140)
.font(Font.TSS24)
.content("规格: 500g/袋")
.build())
.text(TText.builder()
.x(30).y(180)
.font(Font.TSS24)
.isBold(true)
.content("价格: ¥25.90")
.build())
// 1D barcode
.barcode(TBarCode.builder()
.x(80).y(220)
.codeType(CodeType.CODE_128)
.height(60)
.showType(ShowType.BELOW)
.content("6901234567890")
.build())
// QR code
.qrcode(TQRCode.builder()
.x(380).y(90)
.cellWidth(4)
.correctLevel(CorrectLevel.M)
.content("https://example.com")
.build())
// Border
.box(TBox.builder()
.x(20).y(20)
.xEnd(460).yEnd(310)
.lineWidth(2)
.build())
.print(1)
.write();
// Set page dimensions (Units: mm)
tspl.page(new TPage().width(60).height(40));
// Set gap paper
tspl.gap(true);
// Set black mark paper
tspl.bline();
// Set continuous paper
tspl.continuous();
// Set print direction
tspl.direction(TDirection.builder()
.direction(Direction.UP) // UP/DOWN
.mirror(Mirror.NO_MIRROR) // NO_MIRROR/MIRROR
.build());
// Set density (0-15)
tspl.density(8);
// Set speed (1-6)
tspl.speed(4);
// Clear the buffer
tspl.cls();
// Filled rectangle
tspl.bar(TBar.builder()
.x(50).y(100)
.width(200).height(2)
.build());
// Rectangular outline
tspl.box(TBox.builder()
.x(50).y(50)
.xEnd(300).yEnd(200)
.lineWidth(2)
.build());
// Diagonal line
tspl.line(TLine.builder()
.x(50).y(50)
.xEnd(300).yEnd(200)
.lineWidth(2)
.build());
// Draw a circle
tspl.circle(TCircle.builder()
.x(200).y(200)
.diameter(100)
.lineWidth(2)
.build());
// Ellipse
tspl.ellipse(TEllipse.builder()
.x(200).y(200)
.width(150).height(80)
.lineWidth(2)
.build());
// Inverted area
tspl.reverse(TReverse.builder()
.x(50).y(50)
.width(200).height(100)
.build());
// Query printer status
tspl.state().write();
// Query SN Number
tspl.sn().write();
// Query battery level
tspl.batteryVolume().write();
// Query firmware version
tspl.version().write();
// Set shutdown timeout (Minutes)
tspl.setOffTime(30);
// Get shutdown timeout
tspl.getOffTime();
// Set thermal transfer mode
tspl.ribbon(true);
// Set direct thermal mode
tspl.ribbon(false);
// Enable cutter
tspl.cut(true);
// Enable tear-off
tspl.tear(true);
// Enable peel-off
tspl.peel(true);
// Learn paper
tspl.detect();
// Print a self-test page
tspl.selfTest();
Font enumFont nameDescription
Font.TSS12TSS12.BF212-dot matrix
Font.TSS16TSS16.BF216-dot matrix
Font.TSS20TSS20.BF220-dot matrix
Font.TSS24TSS24.BF224-dot matrix (recommended)
Font.TSS28TSS28.BF228-dot matrix
Font.TSS32TSS32.BF232-dot matrix
Type enumDescription
CodeType.CODE_128Code 128 (recommended)
CodeType.CODE_39Code 39
CodeType.CODE_93Code 93
CodeType.CODE_ITFITF
CodeType.CODE_EAN8EAN-8
CodeType.CODE_EAN13EAN-13
CodeType.CODE_UPCAUPC-A
CodeType.CODE_UPCEUPC-E
CodeType.CODE_CODABARCodabar

Add the following to AndroidManifest.xml:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

For complete examples, see: