How do I print to a Bluetooth thermal printer in Android?

In this example we are going to create a simple Android application to print texts to a Bluetooth thermal printer. We’ll be using the Android library for ESC/POS Thermal Printer to develop this example.

We begin by creating an Android project with an Empty Activity. After the project is created we need to edit the app/build.gradle to add the required dependencies and the repository from which it will be downloaded.

...
...

dependencies {
    ...
    ...
    implementation 'com.github.dantsu:escpos-thermalprinter-android:2.0.11'
}

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

Next, add the permission to access Bluetooth in the AndriodManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.kodejava.android">

    <uses-permission android:name="android.permission.BLUETOOTH" />

    ...
    ...
</manifest>

Let’s now jump to the code snippet that will actually print our store receipt to the printer. The steps are quite simple.

After added the uses-permission in the AndroidManigest.xml we also need to check permission in the application, you’ll do it like this.

if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH}, MainActivity.PERMISSION_BLUETOOTH);
}

Open the connection to Bluetooth printer by calling the selectFirstPaired() method of the BluetoothPrintersConnections class. This will give us an instance of BluetoothConnection. If the connection is good we create an instance of EscPosPrinter by passing some parameters like the connection, printer dpi, width in millimeter and the printer’s number of character per line.

BluetoothConnection connection = BluetoothPrintersConnections.selectFirstPaired();
EscPosPrinter printer = new EscPosPrinter(connection, 203, 48f, 32);

The next step is to prepare the text to be printed and called the printFormattedText() of the printer object and pass the text to be printed.

String text = "[C]Hello World!\n";
printer.printFormattedText(text);

Here is the full code snippet for our application.

package org.kodejava.android;

import android.Manifest;
import android.content.pm.PackageManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.dantsu.escposprinter.EscPosPrinter;
import com.dantsu.escposprinter.connection.bluetooth.BluetoothConnection;
import com.dantsu.escposprinter.connection.bluetooth.BluetoothPrintersConnections;
import com.dantsu.escposprinter.textparser.PrinterTextParserImg;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    public static final int PERMISSION_BLUETOOTH = 1;

    private final Locale locale = new Locale("id", "ID");
    private final DateFormat df = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss a", locale);
    private final NumberFormat nf = NumberFormat.getCurrencyInstance(locale);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void doPrint(View view) {
        try {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH}, MainActivity.PERMISSION_BLUETOOTH);
            } else {
                BluetoothConnection connection = BluetoothPrintersConnections.selectFirstPaired();
                if (connection != null) {
                    EscPosPrinter printer = new EscPosPrinter(connection, 203, 48f, 32);
                    final String text = "[C]<img>" + PrinterTextParserImg.bitmapToHexadecimalString(printer,
                            this.getApplicationContext().getResources().getDrawableForDensity(R.drawable.logo,
                                    DisplayMetrics.DENSITY_LOW, getTheme())) + "</img>\n" +
                            "[L]\n" +
                            "[L]" + df.format(new Date()) + "\n" +
                            "[C]================================\n" +
                            "[L]<b>Effective Java</b>\n" +
                            "[L]    1 pcs[R]" + nf.format(25000) + "\n" +
                            "[L]<b>Headfirst Android Development</b>\n" +
                            "[L]    1 pcs[R]" + nf.format(45000) + "\n" +
                            "[L]<b>The Martian</b>\n" +
                            "[L]    1 pcs[R]" + nf.format(20000) + "\n" +
                            "[C]--------------------------------\n" +
                            "[L]TOTAL[R]" + nf.format(90000) + "\n" +
                            "[L]DISCOUNT 15%[R]" + nf.format(13500) + "\n" +
                            "[L]TAX 10%[R]" + nf.format(7650) + "\n" +
                            "[L]<b>GRAND TOTAL[R]" + nf.format(84150) + "</b>\n" +
                            "[C]--------------------------------\n" +
                            "[C]<barcode type='ean13' height='10'>202105160005</barcode>\n" +
                            "[C]--------------------------------\n" +
                            "[C]Thanks For Shopping\n" +
                            "[C]https://kodejava.org\n" +
                            "[L]\n" +
                            "[L]<qrcode>https://kodejava.org</qrcode>\n";

                    printer.printFormattedText(text);
                } else {
                    Toast.makeText(this, "No printer was connected!", Toast.LENGTH_SHORT).show();
                }
            }
        } catch (Exception e) {
            Log.e("APP", "Can't print", e);
        }
    }
}

The following image is the result of our code snippet printed on 48 mm thermal printer.

Android Bluetooth Thermal Printer

Android Bluetooth Thermal Printer

You can find the complete source code in the following repository Android Bluetooth Thermal Printer Example. For more information on formatted text syntax guideline you can visit the project documentation website.

Wayan

12 Comments

  1. Misi Pak Wayan.

    Mau nanya, bagaimana caranya agar bisa ngeprint dari web browser. Dengan kata lain, kirim perintah print dari app yang berbasis web ke app android yang menggunakan librari (Dantsu ESC/POS) ini?

    Terimakasih atas pencerahannya.

    Reply
    • Halo Mas Sadi,

      Ini maksudnya dari web browser itu apakah aplikasi berbasis web di android atau gimana mas? Ketika buka aplikasi web di android, trus misalnya menekan tombol print, lalu akan membuka aplikasi android untuk melakukan pencetakan? apa seperti itu?

      Reply
      • Iya betul pak.., seperti itu, jadi aplikasi di androidnya web based, seperti halnya website pada umumnya, dan aplikasi printernya saya pake dari library yang tertera diatas, dantsu esc pos. Tapi saya masih belum faham cara memberikan perintah cetak dari web nya.

        Terimakasih pak Wayan.

  2. Halo Pak Wayan, Izin bertanya Pak, bagaimana caranya menambahkan Loop Vertical Image lalu baru disampingnya data-data yang ingin di print, seperti pada struk BCA dan bagaimana penerapannya jika datanya dinamis dan satu lagi pak, bagaimana mengatur ukuran font dan lebar ukurannya jika menggunakan library pada tutorial di artikel ini?

    Misal:

    var fomatedText: String? = null
    
    when (printTemplate.ITEM_TYPE) {
        PrintTypeEnum.PRINT_LABEL_CENTER_BOLD.code -> {
            formatedText = "[C]<b>DataHere</b>"
        }
        PrintTypeEnumTemplate.PRINT_BRANCH_NAME.code -> {
            formatedText = "[C]DataHere"
        }
    }
    
    printer.printFormattedText(formatedText)
    

    Mohon bimbingannya Pak 🙂

    Reply
    • Hi Rizki,

      Setahu saya untuk loop vertikal image ini biasanya sudah tercetak atau pre-printed di kertasnya. Saya sendiri belum pernah mengimplementasi loop vertikal image ini secara manual. Di library ini sendiri kita memang tidak bisa membuat tulisan di baris yang berisikan tag <img></img>.

      Untuk mengatur ukuran font dengan library ini bisa menggunakan tag <font></font>, ukurannya bisa ditentukan dengan atribut size. Beberapa nilai yang bisa di set seperti:

      • normal
      • wide
      • tall
      • big

      Untuk detail format yang di support bisa di cek langsung ke websitenya

      Reply
      • Kalo untuk ukuran ketasnya sendiri ini automaticaly fit size ukuran printernya atau bisa dicustom Pak, terutama ukuran width nya

    • Halo Rizki,

      Kalau untuk ukuran cetakannya di printer dengan ukuran yang berbeda apakah bisa fit size-nya, ini saya juga belum tahu, kebetulan kemarin cobanya disatu printer aja 58mm, belum punya printer ukuran yang lebih besar jadi belum sempat coba 😀

      Reply
  3. What changes do i need to make inside code block doPrint(View view) so as to print PDF files and IMAGES from websites ?

    Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.