Setup Printer Termal Bluetooth Panda 58mm di Flutter

Pakai satu paket untuk transport dan satu untuk konten. print_bluetooth_thermal menangani pengaktifan Bluetooth, daftar perangkat terpasang, penyambungan lewat alamat MAC, dan penulisan byte, sementara esc_pos_utils_plus menyusun daftar byte ESC/POS. Tambahkan permission_handler untuk Android 12 ke atas. Hindari menumpuk dua plugin pencetakan serba-bisa karena keduanya akan berebut adapter.
Di pengaturan Android. Perangkat serial Bluetooth Classic harus di-bonding lebih dulu di tingkat sistem operasi; aplikasi Anda kemudian menyambung ke perangkat yang sudah terpasang lewat alamat MAC-nya. Aplikasi yang mencoba bonding secara programatik cenderung berhasil di satu model perangkat dan gagal membingungkan di model berikutnya.
Sering kali tidak secara langsung. Apple tidak membuka Bluetooth Classic serial port profile untuk aplikasi pihak ketiga — aksesori membutuhkan sertifikasi MFi atau External Accessory framework — sehingga printer yang langsung terpasang di Android bisa tidak terjangkau dari iOS kecuali ia juga menyediakan antarmuka Bluetooth Low Energy. Pastikan hal ini sebelum menjanjikan rilis iOS.
Angka resmi lininya cukup konvensional: model meja PRJ-58D mencetak hingga 100 mm per detik pada kertas 57,5 mm lewat USB dan Bluetooth dengan port laci uang RJ-11, sedangkan model portabel PRJ-R58B-II beresolusi 230 dpi dan mencetak sekitar 50 sampai 90 mm per detik dengan baterai. Keduanya menerima perintah ESC/POS.
Tiga penyebab umum: printer tidur setelah beberapa menit menganggur, baterainya melemah saat menarik arus pencetakan, atau perangkat Bluetooth lain mendapat prioritas di tablet. Perlakukan connect sebagai operasi yang bisa gagal, sambung ulang dan coba sekali lagi secara otomatis, dan tampilkan status koneksi yang bisa disentuh di app bar.

Ringkasan Utama
Printer Bluetooth Panda 58 mm berbicara ESC/POS lewat Bluetooth Classic serial port profile. Di Flutter, pola yang andal adalah satu paket untuk transport dan satu untuk konten: print_bluetooth_thermal untuk koneksi dan menulis byte, esc_pos_utils_plus untuk menyusunnya, dengan pairing dilakukan lebih dulu di pengaturan Android.
Printer Panda ada di mana-mana di ritel Indonesia. Ia duduk di meja warung, di dalam tas kurir, dan di balik loket PPOB, harganya sebagian kecil dari Epson meja, dan ia adalah printer yang paling sering diminta didukung oleh aplikasi POS Indonesia. Ia juga alasan banyak developer Flutter menemukan bahwa mencetak lewat Bluetooth bukan satu masalah melainkan tiga: izin, pairing, dan protokol.
Ini setup yang bertahan bagi saya di beberapa perangkat dan versi Android, ditulis dalam urutan yang seharusnya Anda kerjakan, bukan urutan yang dipakai dokumentasi paketnya.
Panda adalah merek, bukan protokol, dan hal yang berguna dari lini ini justru betapa konvensionalnya ia. Membaca spesifikasi resmi model-model umum sudah memberi hampir semua yang Anda butuhkan sebelum menulis kode.
Poin terakhir itu layak direnungkan. Anda tidak sedang menulis kode Panda; Anda menulis kode ESC/POS lalu memilih transport. Kalau abstraksi Anda mencerminkan hal itu, berpindah merek di kemudian hari hanya memakan satu nilai konfigurasi, bukan penulisan ulang.

Bluetooth bukan satu hal, dan perbedaannya menentukan paket Flutter mana yang sama sekali bisa berbicara dengan printer Anda.
| Transport | Berjalan di mana | Artinya bagi aplikasi Anda |
|---|---|---|
| Bluetooth Classic, serial port profile | Android, Windows, dan sebagian besar printer 58 mm murah termasuk Panda | Pairing sekali di pengaturan sistem, lalu hubungkan lewat alamat MAC dan alirkan byte |
| Bluetooth Low Energy | iOS dan printer yang lebih baru yang menyediakan write characteristic | Tanpa dialog pairing, tetapi Anda harus menemukan service dan menulis dalam potongan kecil |
| USB | Android dengan OTG, Windows, Linux | Paling cepat dan paling andal, tetapi mengikat printer secara fisik ke satu perangkat |
| Wi-Fi atau Ethernet | Model meja, jarang pada model portabel | Soket TCP ke port cetak mentah, tanpa melibatkan tumpukan Bluetooth sama sekali |
Konsekuensi terpentingnya ada di iOS. Apple tidak pernah membuka Bluetooth Classic serial port profile untuk aplikasi pihak ketiga — aksesorinya perlu sertifikasi MFi atau External Accessory framework — sehingga printer yang langsung jalan di Android bisa jadi tidak terjangkau dari iPhone kecuali ia juga menyediakan antarmuka low energy. Putuskan hal ini sebelum menjanjikan rilis iOS.
Pilihan paket dalam satu kalimat: pakai print_bluetooth_thermal untuk koneksi dan esc_pos_utils_plus untuk konten. Pemisahan ini ada karena keduanya memecahkan masalah yang tidak berhubungan, dan mencampur paket serba-bisa dengan generator byte kedua adalah cara aplikasi berakhir mengirim dua setelan code page berbeda dalam satu struk.
Tiga paket sudah menutup seluruh pekerjaan. Dua di antaranya adalah pemisahan transport dan konten di atas; yang ketiga adalah model izin runtime Android, yang tidak bisa Anda hindari di Android 12 ke atas.
# pubspec.yaml — the two-package split most Flutter POS apps end up with
dependencies:
print_bluetooth_thermal: ^1.2.2 # transport: discovery, connect, writeBytes
esc_pos_utils_plus: ^2.0.4 # content: builds the ESC/POS byte list
permission_handler: ^11.3.1 # Android 12+ runtime permissionsTahan diri menambahkan paket keempat. Setiap plugin tambahan di ranah ini membawa pendapatnya sendiri soal pemindaian, platform channel-nya sendiri, dan definisi koneksinya sendiri — dan dua di antaranya dalam satu aplikasi akan berebut adapter.
Alurnya sengaja lurus: aktifkan, hubungkan, susun, tulis, putuskan. Hampir semua bug pencetakan Bluetooth yang muncul sesekali yang pernah saya kejar berasal dari mengerjakan langkah-langkah ini dalam urutan berbeda, atau dari melewatkan pemutusan koneksi.
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
/// Discover, connect, print, disconnect. Deliberately linear: the failure
/// modes of a 58 mm Bluetooth printer are all about ordering.
Future<void> printTestReceipt(String macAddress) async {
if (!await PrintBluetoothThermal.bluetoothEnabled) {
throw StateError('Bluetooth is off');
}
final connected = await PrintBluetoothThermal.connect(
macPrinterAddress: macAddress,
);
if (!connected) throw StateError('Could not connect to $macAddress');
try {
final profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm58, profile);
final bytes = <int>[
...generator.text(
'TOKO SUMBER REJEKI',
styles: const PosStyles(
align: PosAlign.center,
bold: true,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
),
...generator.text('Jl. Diponegoro 12',
styles: const PosStyles(align: PosAlign.center)),
...generator.hr(),
...generator.row([
PosColumn(text: 'Kopi Susu', width: 8),
PosColumn(
text: '25.000',
width: 4,
styles: const PosStyles(align: PosAlign.right),
),
]),
...generator.feed(2),
...generator.cut(),
];
await PrintBluetoothThermal.writeBytes(bytes);
} finally {
await PrintBluetoothThermal.disconnect;
}
}Dua detail menanggung beban. Capability profile adalah yang memetakan maksud generator ke dialek perintah printer tertentu, jadi memuatnya sekali lalu memakainya ulang menjaga struk tetap konsisten secara internal. Dan pemutusan koneksi harus ada di blok finally: koneksi yang tertinggal terbuka setelah exception memblokir transaksi berikutnya, dan solusi versi kasir adalah merestart aplikasi.
Jangan mencoba melakukan pairing printer dari dalam aplikasi. Di Android, perangkat serial klasik harus dipasangkan lebih dulu lewat pengaturan sistem; aplikasi Anda kemudian menghubungi perangkat yang sudah ter-bonding lewat alamat MAC. Aplikasi yang mencoba bonding secara programatik berhasil di satu perangkat dan gagal membingungkan di perangkat berikutnya.

Pemasangan di lapangan jauh lebih sering gagal di tahap pairing daripada di kode. Urutan inilah yang kini saya tuliskan ke lembar setup toko.
Menyimpan MAC per perangkat penting di toko dengan banyak kasir. Dua tablet yang menyinkronkan akun yang sama jika tidak akan berebut satu alamat printer, dan masing-masing diam-diam mencetak ke printer milik yang lain.
Taruh chip status printer yang terlihat di app bar — terhubung, terputus, sedang mencetak — dan buat ia bisa disentuh untuk menyambung ulang. Itu mengubah panggilan dukungan paling umum menjadi sesuatu yang diselesaikan kasir dalam dua detik tanpa menelepon siapa pun.
Printer Bluetooth yang lancar di meja Anda gagal dengan tiga cara yang bisa ditebak di dalam toko.
Tak satu pun dari ini eksotis, dan ketiganya tidak terlihat saat pengembangan karena meja kerja punya charger, tanpa perangkat pesaing, dan seorang developer yang menekan tombol cetak setiap tiga puluh detik.
Membuat aplikasi Flutter mencetak ke printer Panda 58 mm sebagian besar soal menghormati batas: pengaturan sistem memiliki pairing, satu paket memiliki koneksi, paket lain memiliki byte, dan kode Anda memiliki percobaan ulang. Bangun dalam urutan itu dan printer berhenti menjadi bagian paling rapuh dari produk Anda.