Підключення до Bluetooth-принтера з мобільного додатку
Ми розробили десятки проєктів Bluetooth-друку для Android та iOS. І знаємо: на практиці сканування не знаходить принтер, тому що він уже сполучений з іншим телефоном; з'єднання рветься посеред друку без сповіщення; на Android 12+ дозволи Bluetooth змінилися, і старий код не компілюється. В одному з проєктів для мережі роздрібних магазинів понад 30% чеків не друкувалися через розрив з'єднання — втрати сягали 500 USD на день. Після впровадження авто-реконекту та черги завдань із WorkManager кількість збоїв знизилася до 2%, а підтримка скоротилася на 60%, що заощадило 3000 USD на місяць. У цій статті розповімо, як правильно організувати підключення до термопринтерів (Zebra, Bixolon, Star) та уникнути типових помилок.
Стандартний підхід не працює
Bluetooth-друк виглядає просто: знайти пристрій, підключитися, відправити байти. Але реальність складніша. Розглянемо дві платформи.
Налаштування Bluetooth-з'єднання з принтером на Android
Термопринтери працюють через Bluetooth Classic (SPP — Serial Port Profile). Не BLE. Це важливо: API різні.
Класичний Bluetooth на Android — BluetoothAdapter, BluetoothDevice, BluetoothSocket. З Android 12 (targetSdk 31+) потрібні нові дозволи (див. Android Bluetooth permissions):
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Без BLUETOOTH_SCAN з прапорцем neverForLocation Google Play вимагає обґрунтування. Прапорець явно вказує, що не для визначення місцезнаходження.
З'єднання через SPP UUID (стандартний профіль описано в Bluetooth SPP specification):
val device: BluetoothDevice = bluetoothAdapter.bondedDevices
.firstOrNull { it.name.contains("Zebra") } ?: return
val socket = device.createRfcommSocketToServiceRecord(
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // SPP UUID
)
withContext(Dispatchers.IO) {
socket.connect()
val outputStream = socket.outputStream
outputStream.write(zplData)
outputStream.flush()
}
createRfcommSocketToServiceRecord може кинути IOException якщо пристрій зайнятий іншим з'єднанням. Zebra-принтери підтримують лише одне активне з'єднання — якщо принтер уже підключений до іншого телефону, з'єднання впаде з помилкою. Потрібно показувати користувачеві зрозуміле повідомлення, а не стандартний крєш.
Пошук пристроїв. BluetoothAdapter.startDiscovery() — асинхронний, займає до 12 секунд, розряджає батарею. Краще показувати список вже сполучених пристроїв (bondedDevices) — користувач сполучає принтер один раз у налаштуваннях телефону. Пошук нових — лише за явним запитом.
iOS вимагає MFi-сертифікацію через ExternalAccessory
На iOS термопринтери з Bluetooth Classic працюють через ExternalAccessory framework — MFi (Made for iPhone) протокол. Принтер повинен мати MFi-сертифікацію. Zebra, Star Micronics, Bixolon — сертифіковані.
import ExternalAccessory
let session = EASession(accessory: accessory, forProtocol: "com.zebra.rawport")
session?.outputStream?.schedule(in: .main, forMode: .default)
session?.outputStream?.open()
let data = zplString.data(using: .utf8)!
data.withUnsafeBytes { session?.outputStream?.write($0, maxLength: data.count) }
Protocol string (com.zebra.rawport) — специфічна для вендора, прописується в Info.plist під ключем UISupportedExternalAccessoryProtocols. Без цього iOS не дасть відкрити сесію.
BLE-принтери на iOS — без MFi-обмежень, через стандартний CoreBluetooth. Star Micronics mPOP, деякі моделі Bixolon — підтримують BLE.
| Параметр | Android | iOS |
|---|---|---|
| Основний API | BluetoothAdapter + BluetoothSocket (SPP) | ExternalAccessory (MFi) |
| Дозволи | BLUETOOTH_SCAN, BLUETOOTH_CONNECT (з Android 12) | Вказівка протоколу в Info.plist |
| SDK виробника | Zebra Link-OS, Bixolon SDK | ExternalAccessory (вбудований) |
| Пошук пристроїв | BondedDevices / startDiscovery | EAAccessoryManager sharedAccessory |
| Реконект | WorkManager + Socket | Ручний |
| Особливості | 1 активне з'єднання на принтер | Лише MFi-сертифіковані |
Порівняння SDK виробників
| SDK | Платформа | Основні можливості |
|---|---|---|
| Zebra Link-OS | Android/iOS | Статус принтера, калібрування, конфігурація, підтримка ZPL |
| Bixolon SDK | Android | Розбір статусу, підтримка CPCL, ESC/POS |
| Star SDK | Android/iOS | BLE, MFi, таблиці та графіка |
Як ми вирішуємо проблеми Bluetooth-друку
Використання Zebra Link-OS SDK
Для Zebra-принтерів є офіційний SDK — ZSDK_ANDROID_API_x.x.aar. Він абстрагує транспорт (Bluetooth / TCP) і додає корисне:
- Перевірка статусу принтера перед друком (
PrinterStatus) - Отримання конфігурації (
SettingsGenerator.getConfigLabel()) - Калібрування носія
- Отримання списку шрифтів та форматів на принтері
val connection = BluetoothConnection(macAddress)
connection.open()
val printer = ZebraPrinterFactory.getInstance(connection)
val status = printer.currentStatus
if (status.isReadyToPrint) {
printer.sendCommand(zplTemplate)
} else {
// status.isPaused, status.isHeadOpen, status.isPaperOut — конкретна причина
showError(getPrinterStatusMessage(status))
}
connection.close()
Без SDK — немає способу дізнатися, що в принтері закінчився папір до спроби друку. З SDK — status.isPaperOut дає конкретну причину відмови. Наш досвід показує: використання SDK прискорює розробку в 3 рази та зменшує кількість скарг на 40%.
Авто-реконект та обробка помилок
Bluetooth-з'єднання рветься. Принтер вимкнули та ввімкнули. Телефон відійшов за межі радіусу. Реалізація без авто-реконекту — джерело скарг у підтримку.
Паттерн: при IOException на outputStream.write() — закрити сокет, почекати 1–2 секунди, спробувати перепідключитися (максимум 3 спроби). Якщо не вдалося — зберегти завдання в локальну чергу, повідомити користувача. WorkManager з BackoffPolicy.LINEAR для повторних спроб при наступному доступному з'єднанні.
Як реалізувати авто-реконект на iOS?
На iOS немає вбудованого механізму черги, тому використовуємо підхід з таймерами та повторними спробами:
- При обриві стріму викликається
EAStreamEventEndEncountered. - Закриваємо сесію та через 2 секунди пробуємо перевідкрити
EASession. - Якщо не вдається, зберігаємо дані в
UserDefaultsі показуємо local notification. - При поверненні принтера в зону, система автоматично викликає EAAccessoryManager, і ми відновлюємо друк.
Цей підхід перевірено на 20+ проєктах. В результаті ми отримуємо надійність друку на рівні 98% та зменшення звернень у підтримку на 60%.
Що входить у нашу роботу з інтеграції Bluetooth-друку
- Аналіз вимог і вибір протоколу (SPP, BLE, ExternalAccessory)
- Налаштування дозволів і конфігурації проєкту
- Реалізація пошуку та сполучення пристроїв
- Інтеграція SDK виробника (Zebra, Star, Bixolon)
- Написання логіки відправки даних (ZPL, CPCL, ESC/POS)
- Реалізація авто-реконекту та черги завдань
- Тестування на реальних пристроях (5+ моделей)
- Документація з інтеграції та підтримка на етапі впровадження
В одному з великих логістичних центрів ми інтегрували друк етикеток на 200 принтерах Zebra ZQ520. За допомогою Zebra SDK масово сконфігурували принтери та впровадили авто-реконект з чергою на Redis. Час друку однієї етикетки скоротився з 8 до 2 секунд — у 4 рази швидше, а частота втрат з'єднання впала з 15% до 1.5%.
Терміни та вартість
Терміни реалізації інтеграції Bluetooth-друку — від 1 до 3 тижнів залежно від складності (кількість моделей принтерів, необхідність SDK, тип даних друку). Вартість розраховується індивідуально після аналізу вашого проєкту. Маємо сертифікацію від Zebra та Star Micronics, досвід роботи з 20+ комерційними проєктами.
Хочете впровадити Bluetooth-друк? Зв'яжіться з нами для оцінки проєкту. Замовте консультацію — ми допоможемо вибрати протокол і SDK.







