zsdk
Zebra Link OS SDK Flutter plugin.
This is a flutter plugin for the Link-OS Multiplatform SDK for Zebra
Features
| Feature | iOS (TCP/IP) | iOS (Bluetooth) | Android (TCP/IP) | Android (Bluetooth) |
|---|---|---|---|---|
| Print ZPL from String | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Print ZPL from file | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Print PDF from byte array | :x: | :x: | :x: | :x: |
| Print PDF from file | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Get printer settings | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Set printer settings | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Check printer status | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Print configuration label | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Run calibration | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Reboot printer | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Connection Types
- TCP/IP: Supported on both iOS and Android
- Bluetooth: Supported on both iOS and Android (requires additional setup)
Note:
Since v3.1.0+1 the plugin supports PDF direct printing on both iOS and Android, before this version, the PDF printing was only available on Android, and it was by using some kind of workaround converting the PDF to image and printing it as image, which was not reliable and caused some issues depending on the document dimensions, etc. Now the PDF Direct printing is the right way and according to the manufacturer, you just need to be sure your printing OS is >= Link-OS v6.3 and you have installed the Virtual Device for PDF Direct.
Steps:
iOS Setup
Podfile
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
Bluetooth Support (iOS)
If you want to use Bluetooth connectivity on iOS, you need to configure your app for MFi (Made for iPhone) accessories and configure the required permissions:
- Add the following keys to your
Info.plist:
<key>UISupportedExternalAccessoryProtocols</key>
<array>
<string>com.zebra.rawport</string>
</array>
<!-- Required for Bluetooth permission requests on iOS 13+ -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to connect to Zebra printers</string>
<key>NSBluetoothCentralUsageDescription</key>
<string>This app needs Bluetooth access to discover and connect to Zebra printers</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to communicate with Zebra printers in the background</string>
- If using
permission_handlerplugin, update yourPodfileto enable Bluetooth permissions. Ensure the following line is present in thepost_installblock:
'PERMISSION_BLUETOOTH=1',
-
Add the
ExternalAccessoryframework to your Xcode project (usually automatic via CocoaPods). -
Request Bluetooth permissions at runtime before using any Bluetooth features:
import 'package:permission_handler/permission_handler.dart';
Future<bool> requestBluetoothPermissions() async {
final btConnect = await Permission.bluetoothConnect.request();
final btScan = await Permission.bluetoothScan.request();
if (btConnect.isPermanentlyDenied || btScan.isPermanentlyDenied) {
// Permissions are permanently denied, open app settings
openAppSettings();
return false;
}
return btConnect.isGranted && btScan.isGranted;
}
Important Notes:
- iOS uses MFi (Made for iPhone) Bluetooth, which requires the ExternalAccessory framework
- On iOS, Bluetooth uses the printer's serial number instead of MAC address
- Use
getBondedDevices()to discover connected Zebra printers - theaddressfield contains the serial number - If permissions show as
permanentlyDenied, the user must enable them in Settings >App Name> Bluetooth - Always test permissions on a real iOS device; simulators don't support Bluetooth
Android Setup
TCP/IP Only
No setup required.
Bluetooth Support
If you want to use Bluetooth connectivity, you need to add the following permissions to your app's AndroidManifest.xml:
<!-- Bluetooth permissions for Android 11 and below -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- Bluetooth permissions for Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Optional: Only needed if you want to discover/scan for printers -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Note: You also need to request these permissions at runtime before using Bluetooth features. Consider using a package like permission_handler to handle runtime permission requests.
Bluetooth Device Identifier
The Bluetooth methods use the macAddress parameter:
- Android: Use the printer's MAC address (e.g.,
"AC:3F:A4:12:34:56") - iOS: Use the printer's serial number (obtained from
getBondedDevices())
How to use
Add dependency
# Add this line to your flutter project dependencies
zsdk: ^2.0.0+11
and run flutter pub get to download the library sources to your pub-cache.
Initialize a ZSDK object
final zsdk = ZSDK();
Start the printer calibration
zsdk.doManualCalibrationOverTCPIP(
address: '10.0.0.100',
port: 9100 //optional
)
Get printer settings
zsdk.getPrinterSettingsOverTCPIP(
address: '10.0.0.100',
port: 9100 //optional
).then(value) {
final printerSettings = PrinterResponse.fromMap(value).settings;
};
Set printer settings
zsdk.setPrinterSettingsOverTCPIP(
address: '10.0.0.100',
port: 9100, //optional
settings: PrinterSettings(
darkness: 10,
printSpeed: 6,
tearOff: 0,
mediaType: MediaType.MARK,
printMethod: PrintMethod.DIRECT_THERMAL,
printWidth: 568,
labelLength: 1202,
labelLengthMax: 39,
zplMode: ZPLMode.ZPL_II,
powerUpAction: PowerUpAction.NO_MOTION,
headCloseAction: HeadCloseAction.NO_MOTION,
labelTop: 0,
leftPosition: 0,
printMode: PrintMode.TEAR_OFF,
reprintMode: ReprintMode.OFF,
)
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Status status = printerResponse.statusInfo.status;
Cause cause = printerResponse.statusInfo.cause;
//Do something
}
}
Reset printer settings
zsdk.setPrinterSettingsOverTCPIP(
address: '10.0.0.100',
port: 9100, //optional
settings: PrinterSettings.defaultSettings()
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Status status = printerResponse.statusInfo.status;
Cause cause = printerResponse.statusInfo.cause;
//Do something
}
}
Check printer status
zsdk.checkPrinterStatusOverTCPIP(
address: '10.0.0.100',
port: 9100, //optional
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
Status status = printerResponse.statusInfo.status;
print(status);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Cause cause = printerResponse.statusInfo.cause;
print(cause);
}
}
Reboot printer
zsdk.rebootPrinter(
address: '10.0.0.100',
port: 9100, //optional
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
Status status = printerResponse.statusInfo.status;
print(status);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Cause cause = printerResponse.statusInfo.cause;
print(cause);
}
}
Print zpl file
zsdk.printZplFileOverTCPIP(
filePath: '/path/to/file.pdf',
address: '10.0.0.100',
port: 9100, //optional
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
Status status = printerResponse.statusInfo.status;
print(status);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Cause cause = printerResponse.statusInfo.cause;
print(cause);
}
}
Print zpl data
zsdk.printZplDataOverTCPIP(
data: '^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ',
address: '10.0.0.100',
port: 9100, //optional
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
Status status = printerResponse.statusInfo.status;
print(status);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Cause cause = printerResponse.statusInfo.cause;
print(cause);
}
}
Print pdf file
zsdk.printPdfFileOverTCPIP(
filePath: '/path/to/file.pdf',
address: '10.0.0.100',
port: 9100, //optional
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
Status status = printerResponse.statusInfo.status;
print(status);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Cause cause = printerResponse.statusInfo.cause;
print(cause);
}
}
Bluetooth Examples (Android only)
All Bluetooth methods mirror their TCP/IP counterparts, but use macAddress instead of address and port.
Example: Print ZPL over Bluetooth
zsdk.printZplDataOverBluetooth(
data: '^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ',
macAddress: 'AC:3F:A4:12:34:56',
).then(value) {
final printerResponse = PrinterResponse.fromMap(value);
if(printerResponse.errorCode == ErrorCode.SUCCESS) {
//Do something
} else {
Cause cause = printerResponse.statusInfo.cause;
print(cause);
}
}
All Bluetooth methods mirror their TCP/IP counterparts (e.g., printZplFileOverBluetooth, checkPrinterStatusOverBluetooth, etc.).
Tested Zebra Devices
- Zebra ZT411
- Zebra ZD500 Series
- ZD620
- ZQ620