Mobile App Development for RFID Inventory: EPC Deduplication & Offline Sync

Standard barcodes require line-of-sight and piece-by-piece scanning—inefficient for mass inventory. RFID lets you read 200 tags in three seconds by just walking along a shelf. We develop mobile apps that ingest a stream of EPC codes without loss, deduplicate them, and reconcile against the expected

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Mobile App Development for RFID Inventory: EPC Deduplication & Offline Sync
Medium
~5 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

Standard barcodes require line-of-sight and piece-by-piece scanning—inefficient for mass inventory. RFID lets you read 200 tags in three seconds by just walking along a shelf. We develop mobile apps that ingest a stream of EPC codes without loss, deduplicate them, and reconcile against the expected list—all in real time, even without internet. Our experience: 5 years in mobile development, over 30 projects in logistics and inventory.

For example, in a warehouse with metal shelving, UHF tags often fail to read due to reflections. We tune reader parameters: power, polarization, filters. In one project, we reduced miss rates from 15% to 2% by selecting antennas and configuring settings. This is especially important for metal surfaces where standard settings fail.

Problems We Solve

Duplicate reads—a single tag can be read 50+ times per session. Fast deduplication without UI blocking is needed. Offline mode—warehouses often lack Wi-Fi. The database must be local with later synchronization. Discrepancies—some tags may not be read due to damage or poor placement. We explicitly show found, missing, and extra items. This is critical for warehouses with metal shelves where UHF tags perform worse.

RFID scanning is 100x faster than manual entry or barcodes when checking hundreds of items. But without proper data handling, this advantage is lost.

How to Deduplicate EPC Tags Without Loss

The inventory session is a state machine with transitions: IDLE -> SCANNING -> PROCESSING -> COMPLETED, with pause capability. For each tag read, we update a MutableStateFlow with deduplication by EPC:

class InventorySession(private val expectedItems: List<InventoryItem>) { private val _scannedEpcs = MutableStateFlow<Set<String>>(emptySet()) val scannedEpcs: StateFlow<Set<String>> = _scannedEpcs.asStateFlow() val matchedItems = scannedEpcs.map { epcs -> expectedItems.filter { it.epc in epcs } }.stateIn(scope, SharingStarted.Eagerly, emptyList()) val missingItems = scannedEpcs.map { epcs -> expectedItems.filter { it.epc !in epcs } }.stateIn(scope, SharingStarted.Eagerly, emptyList()) val unexpectedEpcs = scannedEpcs.map { epcs -> val knownEpcs = expectedItems.map { it.epc }.toSet() epcs.filter { it !in knownEpcs } }.stateIn(scope, SharingStarted.Eagerly, emptyList()) fun onTagRead(epc: String) { _scannedEpcs.update { current -> current + epc } } fun reset() { _scannedEpcs.value = emptySet() } } 

Set<String> provides automatic deduplication. One EPC may arrive 50+ times, but the Set stores it once. Derived states (found, missing, extra) are computed reactively via map.

Why Offline Synchronization Is Critical for Warehouses

We ensure the app works without network. A local Room DB stores the expected list and results:

@Entity(tableName = "inventory_sessions") data class InventorySessionEntity( @PrimaryKey val sessionId: String, val locationId: String, val startedAt: Long, val completedAt: Long?, val status: String // "in_progress", "completed", "synced" ) @Entity(tableName = "scanned_tags") data class ScannedTagEntity( @PrimaryKey val epc: String, val sessionId: String, val firstSeenAt: Long, val readCount: Int ) 

readCount is the number of reads for a single tag per session. Anomalously low counts (1–2) when neighboring tags were read 20+ times indicate poor physical placement or damage—a useful QA metric.

After session completion, synchronization via WorkManager when network becomes available:

val syncRequest = OneTimeWorkRequestBuilder<InventorySyncWorker>() .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) .setInputData(workDataOf("session_id" to sessionId)) .build() workManager.enqueueUniqueWork("sync_$sessionId", ExistingWorkPolicy.KEEP, syncRequest) 

How to Display Results in Real Time

LazyColumn with key(item.epc)—animated addition of found items:

@Composable fun InventoryResultsScreen(session: InventorySession) { val matched by session.matchedItems.collectAsState() val missing by session.missingItems.collectAsState() val scanned by session.scannedEpcs.collectAsState() Column { LinearProgressIndicator( progress = { if (session.expectedItems.isEmpty()) 0f else matched.size.toFloat() / session.expectedItems.size } ) Text("Found: ${matched.size}/${session.expectedItems.size}") LazyColumn { items(matched, key = { it.epc }) { item -> InventoryItemRow(item = item, status = ItemStatus.FOUND) } items(missing, key = { it.epc }) { item -> InventoryItemRow(item = item, status = ItemStatus.MISSING) } } } } 

GS1 EPC Decoding

EPC is not just a hex string. A structured code like urn:epc:id:sgtin:0614141.107346.2017 contains company, item reference, and serial number. Decoding via SGTIN-96:

SGTIN-96 decoding code example
fun decodeSgtin96(epc: String): Sgtin96? { val bytes = epc.chunked(2).map { it.toInt(16) }.toByteArray() val bits = BigInteger(1, bytes) val header = bits.shiftRight(88).and(BigInteger.valueOf(0xFF)).toInt() if (header != 0x30) return null val filter = bits.shiftRight(85).and(BigInteger.valueOf(0x07)).toInt() val partition = bits.shiftRight(82).and(BigInteger.valueOf(0x07)).toInt() // further parsing per partition table } 

Ready-made libraries: com.gs4tr.epcis:epcis-rest-client or org.fosstrak.epcis:epcis-repository-client. For more, see GS1 EPC Tag Data Standard.

Comparison of RFID and Barcodes

Parameter Barcode RFID
Scan speed 1 item/s 200 tags in 3 s
Line-of-sight required Yes No
Data rewrite No Yes (some tags)
Interference resistance High Medium (metal, liquid)
Tag cost $0.01 $0.05–$0.50

RFID is 10–100x faster for bulk scanning but requires initial setup and hardware selection.

Comparison of EPC Decoding Methods

Method Performance GS1 Support Integration Complexity
Manual SGTIN-96 High (native) Full Medium
EPCIS library Medium (HTTP) Full Low
Cloud service Low (REST) Partial Minimal

For mobile apps, the first option is optimal—fewest dependencies and maximum speed.

What's Included in the Work

  • Architecture design of the inventory state machine
  • Development of the deduplication module using StateFlow
  • Offline storage implementation with Room
  • Synchronization setup via WorkManager
  • Integration with BLE reader (Zebra, custom)
  • GS1 EPC decoding and validation
  • Jetpack Compose UI with animated progress
  • Code signing, provisioning, publication to App Store and Google Play
  • Documentation and operator training

Evaluate how RFID inventory can reduce your warehouse time—get a consultation from our engineers.

Process

  1. Analytics—study warehouse processes, tag types, WMS.
  2. Prototype—MVP in 3–5 days with basic functionality.
  3. Development—iterative sprints of 2 weeks.
  4. QA—load testing with real readers.
  5. Deployment—publish to stores and handover.

Timeline

Mobile inventory app with Zebra/custom BLE reader, offline Room, GS1 decoding, and sync: from 5 days (simple warehouse, one reader, one tag type) to 2–3 weeks (multi-location, multiple tag types, custom EPC scheme, REST integration with WMS).

Contact us for a project estimate—we'll respond within a day. Request a consultation, and we'll show you how to implement RFID inventory in your warehouse. We guarantee compliance with App Store Review Guidelines and Google Play policies, as well as full support at all stages.