Zebra Official RFID API3 v2.0.5.275 & ZIOTC Sled SDK

Zebra RFID API3 Android SDK & Guide

Complete engineering manual for integrating Zebra MC3300R, MC3390R handhelds and RFD40, RFD90, and RFD8500 Bluetooth sleds into Android Studio. Includes ready-to-import Gradle configurations, Android 12+ Bluetooth permissions, trigger listeners, and ready sample apps.

CORE LIBRARY rfidapi3lib.aar
SLED TRANSPORT ZIOTC LLRP Sled
TRIGGER EVENT HandheldEvent
TEST APK ZIOTC Mobile 2.0
Zebra RFID API 3 guide image
Hardware Support

Supported Zebra RFID Handhelds & Sleds

The Zebra RFID API3 SDK v2.0.5.275 supports both integrated enterprise mobile terminals and modular wireless Bluetooth/eConnex sleds:

MC33

MC3300R / MC3390R

Premium all-in-one Android handheld terminal with integrated UHF reader. Internal high-speed serial bus transport with up to 900 tags/sec read rate.

Transport: SERIAL (Internal Bus)
RFD40

Zebra RFD40 / RFD40+

Standard and premium UHF sled connecting to Zebra TC21/TC26 or third-party smartphones via eConnex 8-pin physical adaptor or Bluetooth 5.3 BLE.

Transport: BLUETOOTH / USB eConnex
RFD90

Zebra RFD90 Ultra-Rugged

Heavy industrial IP65/IP67 UHF sled designed for manufacturing, yard management, and harsh distribution centers. 1300+ tags/sec long-range read.

Transport: BLUETOOTH / USB / Wi-Fi
8500

Zebra RFD8500 Sled

Widely deployed Bluetooth Classic UHF RFID and 1D/2D barcode sled compatible with Android, iOS, and Windows tablets for retail inventory.

Transport: BLUETOOTH (SPP)
Step-by-Step Blueprint

How to Integrate Zebra RFID API3 in Android Studio

Follow this guide to configure Gradle dependencies, declare Android 12+ Bluetooth permissions, and manage asynchronous tag reader callbacks.

1

Gradle Dependency Setup & Duplicate Class Prevention

Place rfidapi3lib-2.0.5.275.aar and rfidapi3ziotcllrplib-2.0.5.275.aar inside your app/libs/ directory. Crucially, exclude rfidapi3llrplib to prevent duplicate class symbol collisions:

app/build.gradle (or build.gradle.kts) Gradle Config
dependencies {
    // Include all AARs in libs but exclude rfidapi3llrplib to avoid duplicate LLRPClient classes
    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: ['rfidapi3llrplib-*.aar'])
    
    // Required networking & async dependencies used by Zebra ZIOTC sled protocols
    implementation 'org.nanohttpd:nanohttpd:2.3.1'
    implementation 'org.java-websocket:Java-WebSocket:1.6.0'
}
2

Android 12+ Bluetooth Runtime Permissions & Proguard Rules

Connecting to Zebra RFD40 or RFD8500 Bluetooth sleds on Android 12 through Android 14 requires modern Bluetooth permissions. Add these to your manifest and protect Zebra JNI interfaces from Proguard obfuscation:

AndroidManifest.xml
<!-- Bluetooth permissions for RFD40 / RFD8500 sleds -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
proguard-rules.pro
# Preserve Zebra RFID API3 classes and internal host services
-keep public class com.zebra.rfid.** { *; }
-keep public class com.zebra.rfidhost.** { *; }
-keep public class com.zebra.rfidserial.** { *; }

-dontwarn com.zebra.rfid.api3.**
-dontwarn android.os.ServiceManager
3

Complete Kotlin Implementation (Readers Init, Connection & Tag Stream)

Below is the complete, tested Kotlin integration service managing Zebra reader discovery, antenna RF power configuration, asynchronous tag callbacks, and clean teardown:

ZebraRfidService.kt Production Code
package com.rfidsoftwares.demo.zebra

import android.content.Context
import android.util.Log
import com.zebra.rfid.api3.*

class ZebraRfidService(private val context: Context) : RfidEventsListener {

    private var readers: Readers? = null
    private var availableRFIDReaderList: ArrayList<ReaderDevice>? = null
    private var readerDevice: ReaderDevice? = null
    private var rfidReader: RFIDReader? = null
    private var isConnected = false

    fun initialize() {
        Thread {
            try {
                // Discover all attached readers (Internal Serial + Bluetooth Sleds)
                readers = Readers(context, ENUM_TRANSPORT.ALL)
                availableRFIDReaderList = readers?.GetAvailableRFIDReaderList()

                if (!availableRFIDReaderList.isNullOrEmpty()) {
                    // Select first detected reader device
                    readerDevice = availableRFIDReaderList?.get(0)
                    rfidReader = readerDevice?.rfidReader

                    // Establish hardware session
                    rfidReader?.connect()
                    isConnected = true
                    Log.i("ZebraRFID", "Connected to Zebra reader: ${rfidReader?.hostName}")

                    configureReader()
                } else {
                    Log.w("ZebraRFID", "No Zebra RFID readers detected.")
                }
            } catch (e: Exception) {
                Log.e("ZebraRFID", "Hardware connection exception", e)
            }
        }.start()
    }

    private fun configureReader() {
        try {
            // Subscribe to inventory read events & pistol trigger events
            rfidReader?.Events?.addEventsListener(this)
            rfidReader?.Events?.setHandheldEvent(true)
            rfidReader?.Events?.setTagReadEvent(true)
            rfidReader?.Events?.setAttachTagDataWithReadEvent(true)

            // Configure RF Power to 270 (27.0 dBm) on Antenna 1
            val rfConfig = rfidReader?.Config?.Antennas?.getAntennaRfConfig(1)
            rfConfig?.transmitPowerIndex = 270
            rfidReader?.Config?.Antennas?.setAntennaRfConfig(1, rfConfig)
        } catch (e: Exception) {
            Log.e("ZebraRFID", "Error configuring antenna parameters", e)
        }
    }

    fun startInventory() {
        if (!isConnected || rfidReader == null) return
        try {
            rfidReader?.Actions?.Inventory?.perform()
            Log.i("ZebraRFID", "Zebra inventory sweep active.")
        } catch (e: Exception) {
            Log.e("ZebraRFID", "Failed to start inventory", e)
        }
    }

    fun stopInventory() {
        if (!isConnected || rfidReader == null) return
        try {
            rfidReader?.Actions?.Inventory?.stop()
            Log.i("ZebraRFID", "Zebra inventory sweep stopped.")
        } catch (e: Exception) {
            Log.e("ZebraRFID", "Failed to stop inventory", e)
        }
    }

    // Tag read notification callback from Zebra API3 engine
    override fun eventReadNotify(e: RfidReadEvents?) {
        val myTags = rfidReader?.Actions?.getReadTags(100)
        if (myTags != null) {
            for (tag in myTags) {
                val epc = tag.tagID
                val rssi = tag.peakRSSI
                Log.d("ZebraRFID", "Tag Scanned: EPC=$epc | PeakRSSI=$rssi dBm")
            }
        }
    }

    // Hardware status events (including pistol grip trigger clicks)
    override fun eventStatusNotify(statusEvents: RfidStatusEvents?) {
        if (statusEvents?.statusEventType == STATUS_EVENT_TYPE.HANDHELD_TRIGGER_EVENT) {
            val triggerData = statusEvents.handheldTriggerEventData
            if (triggerData.handheldEvent == HANDHELD_TRIGGER_EVENT_TYPE.HANDHELD_TRIGGER_PRESSED) {
                startInventory()
            } else if (triggerData.handheldEvent == HANDHELD_TRIGGER_EVENT_TYPE.HANDHELD_TRIGGER_RELEASED) {
                stopInventory()
            }
        }
    }

    fun disconnect() {
        try {
            if (isConnected) {
                rfidReader?.Events?.removeEventsListener(this)
                rfidReader?.disconnect()
                isConnected = false
            }
        } catch (e: Exception) {
            Log.e("ZebraRFID", "Error disconnecting reader", e)
        }
    }
}
Real-World Troubleshooting

Top 5 Zebra Developer Pitfalls & Solutions

Field-tested solutions to the most frustrating build issues, runtime crashes, and Bluetooth drops in Zebra RFID development.

ISSUE 01

Duplicate class LLRPClient Error in Android Studio Gradle Build

Symptom: Build terminates with Duplicate class com.mot.rfid.api3.LLRPClient found in modules rfidapi3llrplib.aar and rfidapi3ziotcllrplib.aar.

Root Cause: rfidapi3ziotcllrplib.aar already includes all necessary LLRP client definitions for Bluetooth sleds. Importing both files into Gradle causes classloader collision.

// Fix in build.gradle: Exclude rfidapi3llrplib explicitly
implementation fileTree(dir: 'libs', include: ['*.aar'], exclude: ['rfidapi3llrplib-*.aar'])
ISSUE 02

GetAvailableRFIDReaderList() Returns Empty on Android 12+

Symptom: Sled is paired and connected in Android OS Bluetooth settings, but Zebra API3 detects 0 available readers.

Root Cause: Android 12 introduced granular Bluetooth permissions. If BLUETOOTH_CONNECT and BLUETOOTH_SCAN permissions are not approved by the user at runtime, the Zebra SDK cannot open Bluetooth sockets.

// Fix: Request runtime permissions prior to initializing Readers()
val permissions = arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
ActivityCompat.requestPermissions(activity, permissions, REQUEST_BT_CODE)
ISSUE 03

Pistol Trigger Presses Missed or Ignored by Application

Symptom: Physical trigger clicks on the MC3300R or RFD40 sled handle do not trigger scanning.

Root Cause: Handheld trigger events are turned off by default in the Zebra SDK to save serial bandwidth. You must explicitly activate rfidReader.Events.setHandheldEvent(true).

// Fix: Explicitly enable trigger events and subscribe listener
rfidReader.Events.setHandheldEvent(true)
rfidReader.Events.addEventsListener(this)
ISSUE 04

OperationFailureException: Reader is not connected on App Resume

Symptom: When unlocking the screen or returning to the app, calling Actions.Inventory.perform() crashes with OperationFailureException.

Root Cause: Zebra sleds disconnect their physical or Bluetooth link when the hosting Activity pauses to conserve sled battery.

// Fix: Listen for DISCONNECTION_EVENT and re-establish connection in onResume()
if (rfidReader?.isConnected != true) {
    rfidReader?.connect()
    configureReader()
}
ISSUE 05

Memory Exhaustion & JNI Buffer Overflow During 1,000+ Tag Scans

Symptom: Scanning high-density retail racks causes progressive slowdowns and eventually crashes the app process.

Root Cause: In high-throughput sweeps, failing to drain the native buffer via Actions.getReadTags(100) results in JNI memory exhaustion.

// Fix: Drain in batches of up to 100 tags per event callback
val tags = rfidReader?.Actions?.getReadTags(100)
// Process tags on background dispatcher
Verified Binary Downloads

Zebra RFID API3 Libraries & Sample Code

Directly hosted with zero registration gating. Verify SHA-256 hashes against official Zebra release signatures.

Asset File Type Size SHA-256 Checksum Action
rfidapi3lib-2.0.5.275.aar Core Zebra RFID API3 Android Archive AAR 1.7 MB E01AB69906F0C7D22D9D... Download
rfidapi3ziotcllrplib-2.0.5.275.aar Zebra ZIOTC LLRP Sled Client Library for RFD40/RFD8500 AAR 3.3 MB 14C56934403855A79D19... Download
zebra-rfid-api3-android-bundle.zip Complete AAR Bundle: Core library + ZIOTC sled driver ZIP 5.1 MB 71F34962729175B3DBF1... Download
zebra-rfid-sample-apps.zip Ready-to-import HHSampleApp & ZIOTCSampleApp projects + APK ZIP 11.5 MB 48CB5589EFC70FA49363... Download
ZebraRfidService.kt Runnable standalone Kotlin background service Kotlin 4.1 KB Source Text Download

Zebra RFID API3 Frequently Asked Questions

Technical answers for Android developers, hardware integrators, and warehouse solution architects.

How do you fix Duplicate class LLRPClient errors between Zebra AAR files in Gradle?
This error occurs when both rfidapi3llrplib.aar and rfidapi3ziotcllrplib.aar are included in your libs/ folder. rfidapi3ziotcllrplib is the modern superset containing both Bluetooth sled protocols and core LLRP drivers. Exclude rfidapi3llrplib from your build.gradle implementation line: implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"), "exclude" to listOf("rfidapi3llrplib-*.aar")))).
Why does Readers.GetAvailableRFIDReaderList() return an empty list on Android 12+?
Android 12 (API 31+) requires granular runtime permissions for Bluetooth peripheral discovery. You must declare BLUETOOTH_SCAN and BLUETOOTH_CONNECT in AndroidManifest.xml and prompt the user via ActivityCompat.requestPermissions() before initializing Readers(context, ENUM_TRANSPORT.ALL). Without runtime approval, Zebra sled discovery fails silently.
How do you listen for Zebra pistol grip trigger press and release events?
Enable handheld event notifications via rfidReader.Events.setHandheldEvent(true) and subscribe your class to RfidEventsListener. In the eventStatusNotify(rfidStatusEvents) callback, check if rfidStatusEvents.statusEventType == STATUS_EVENT_TYPE.HANDHELD_TRIGGER_EVENT, then query HandheldTriggerEventData to start or stop inventory sweeps based on HANDHELD_TRIGGER_PRESSED and HANDHELD_TRIGGER_RELEASED.
How do you prevent OperationFailureException: Reader not connected after sleep or backgrounding?
Zebra readers automatically drop their hardware transport connection when the device sleeps or the activity enters the background to conserve battery. Register for DISCONNECTION_EVENT in your status listener, cleanly disconnect on onPause(), and implement an exponential-backoff reconnect routine inside onResume() before invoking Actions.Inventory.perform().
What is the difference between Zebra MC3300R integrated terminals and RFD40/RFD90 sleds?
Zebra MC3300R and MC3390R are integrated mobile computers where the UHF module communicates over an internal serial bus (/dev/ttyHSL0). RFD40, RFD90, and RFD8500 are modular sleds that connect over Bluetooth Classic, BLE, or direct eConnex USB-C pins using Zebra ZIOTC LLRP protocol wrappers.
Where can I download the complete Zebra HHSampleApp and ZIOTCSampleApp Android Studio projects?
We provide the complete zebra-rfid-sample-apps.zip bundle in our download catalog. It contains ready-to-import Android Studio projects for both integrated handhelds (HHSampleApp) and Bluetooth sleds (ZIOTCSampleApp), along with the pre-compiled test APK (ZIOTC_RFID_Mobile-2.0.5.275.apk).

Need an Enterprise Zebra RFID Application or ERP Integration?

Our engineering team builds custom Android APKs for Zebra MC3300R handhelds and RFD40/RFD90 sleds with sub-second SAP S/4HANA and Tally Prime inventory reconciliation.