Send inquiry

Development for Zebras, or how not to be kicked

QR and barcodes are now standard in thousands of different industries, as are the applications that work with them. But what to do if a regular phone does not meet the requirements for endurance, durability, or provided functions? Zebra scanners can be a solution.

These are various proprietary devices with the Android operating system. You can find or create a combination of hardware and software for each situation. However, during development, it is necessary to take into account certain specifics. These are the topics of this more professional article.

Design of the app

It is true that design is usually not the first word that comes to mind in connection with a working app. But when you create an app for these scanners, it's the first thing you need to consider. Especially if they are used somewhere in a warehouse. Nowadays, when phone manufacturers are competing in the size and resolution of the display, it is easy to forget that a large diagonal may not represent a usable space. The resolution of the scanners at the lower end of the price spectrum corresponds to the dazzling MDPI. It's logical - a worse panel means savings in production and lower energy consumption during operation, but at the same time, unfortunately, it pushes the design guidelines back to 2010.

DataWedge vs EMDK 

Zebra scanners allow applications to communicate with hardware in two ways: DataWedge and the Enterprise Mobility Developer Kit. While DataWedge makes it easier to implement common situations, thus simplifying and speeding up development, when using EMDK, the programmer must handle everything himself. Everyone learns the same when opening the official EMDK documentation, where the first line refers to the benefits of using DataWedge.

However, each coin has two sides, which is true in this case as well. Although DataWedge allows for rapid development, the user (or device administrator) must then set up a supporting application over which the developer has no control. In addition to the need to set up each scanner, this creates a potential source of difficult-to-debug problems, especially in the hands of an inquisitive end user. Using the EMDK means more work during development, but for use, it is only necessary to install the application. In addition, the developer has full control over when and what code will be accepted - and if something goes wrong, it's clear where the bug is. For these reasons, we have chosen EMDK for the development of our applications.

The choice is clear ... Or not?

EMDK and its peculiarities

Like any software, EMDK is constantly evolving. However, choosing the right version is a bit trickier than finding the latest one. Each version of the EMDK supports different versions of Android, so you need to know if the client does not plan to use older scanner models. The following code samples will use EMDK version 7.6.10.

If the application is to work on ordinary telephones or other devices without a hardware barcode scanner, it is necessary to solve the reading of these codes with the camera. However, the EMDK uses hardware drivers for the camera. Result? It is not possible to receive codes from the camera and hardware scanner at the same time.

Enough talk, let's look at the code

First of all, we need to add an EMDK dependency to the manifest ...

<uses-library android:name="com.symbol.emdk" />

...and add EMDK to gradle

compileOnly "com.symbol:emdk:7.6.10"

Then we can get a reference to EMDKManager...

EMDKManager.getEMDKManager(context, object : EMDKManager.EMDKListener {
            override fun onOpened(emdkManager: EMDKManager?) {
                //reference obtained, we can proceed with binding actual devices
                initScanner((emdkManager?.getInstance(EMDKManager.FEATURE_TYPE.BARCODE) as? BarcodeManager) ?: return)
            }

            override fun onClosed() {
                //clear all references, since manager is about to be destroyed
            }
        })

…and initialize the scanner itself

fun initScanner(barcodeManager: BarcodeManager) {
    barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT)
            ?.apply {
                addDataListener {
                    if (it.result == ScannerResults.SUCCESS) {
                        for (code in it.scanData) {
                            //do what you will with scanned code
                        }
                    }
                }
                addStatusListener {
                    if (it.state == StatusData.ScannerStates.IDLE && !isReadPending) {
                        read()
                    }
                }
                try {
                    enable() //start scanning immediately                   
                } catch (e: Exception) {
                    //here we should handle cases like already running camera, that block the device from initializing
                }
            }
}


Once we have a reference to the scanner, we can abort the scan with the disable () method and resume it with enable (), similar to initialization. When we no longer need the scanner, it is a good idea to release the reference

fun releaseScanner(it: Scanner) {
    it.disable()
    it.release()
}

If we want the application to work on regular phones, then we must add a line to the manifest

<uses-library android:name="com.symbol.emdk" android:required="false" />

and then run the application to see if it is a supported device

fun Context.isEMDKAvailable() =
        try {
            Build.MANUFACTURER.contains("Zebra Technologies")
                    && packageManager.getPackageInfo("com.symbol.emdk.emdkservice", 0) != null
        } catch (e: Exception) {
            false
        }

Do you have any experience with Zebra? We will be pleased with your observations. Let us know, for example, on contact Facebook. And if you need an app for Zebras, don't get kicked by them. We will be happy to help you with the development.

The article was prepared by Vojta, our senior Android developer.