Android Barcode Scanning Library Landscape
I am a developer on the Cartwheel team at Target, and one of the features of our app that our users are passionate about is the barcode scanner. With it, users can scan anything in a store to see if we have a Cartwheel offer for that product. Because this is one of our top features, we have spent a lot of time looking at the various options for scanning barcodes on Android.
Here I will provide an overview of the three most popular options out there right now- ZXing, ZBar, and Google’s Mobile Vision API. This is a qualitative look at these libraries, so I won’t attempt to provide benchmarks.
What we have found is that there isn’t a single clear winner right now. Each library has at least one major drawback. Selecting a library for your project requires knowing the relative strengths and weakness of these libraries so you can pick the one that best fits your use case.
ZXing (AKA Zerba Crossing) is the oldest of the three, it boasts the best maintenance record, and in my experience is also the most popular. It is a Google project from way back in 2007, and is still receiving regular updates.
The project consists of a core Java library that handles the decoding for all platforms, and a number of platform-specific apps (including Android, Glass, Java SE, and the web). You are probably already familiar with the Android app in the repository- it is the app known simply as Barcode Scanner.
That’s where we run into the first problem with ZXing, and it is a big one. There is no Android-specific library that manages the camera APIs. The “correct” way to use ZXing is to use the android-integration library to fire off an intent to launch the Barcode Scanner app.
We don’t want to ask our users to install two apps for one of our most popular features, so the integration library is not a viable solution. Instead we went with a popular approach: take the source code for the Android app, plop it into our application, and hack it apart to suit our needs. Of course this isn’t an ideal solution, particularly because it makes incorporating future ZXing updates more difficult.
There are some efforts out there such as ZXing Android Embedded and dm77's Barcode Scanner that aim to fix this. However, those suffer the same issue with updating the core ZXing libraries. Due to this and the fact that in the end still use the same underlying scanning libraries we didn’t explore these wrapper libraries much further.
One other issue we ran into with ZXing is that it only supports scanning barcodes that are in the same orientation as the camera. If you scan a barcode at a 90° angle, ZXing won’t pick it up. Even trying to coerce ZXing to support an Activity in portrait used to be a chore, but at least that was fixed recently.
Pros: Well-supported, reasonably quick, accurate
Cons: Most difficult to integrate, only supports one barcode orientation at a time.
ZXing worked well for us for a couple of years, but we decided to give ZBar a try after our colleagues on the Target app shared some good experiences with us.
ZBar was an enticing option because it is incredibly quick to detect barcodes and it supports barcodes in multiple orientations in the viewfinder. Indeed, ZBar is so quick that it often finds a barcode before the user stabilizes their phone and the camera focuses.
Like ZXing, ZBar consists of a core cross-platform barcode detector and platform-specific libraries leveraging the detector.
Unlike ZXing, ZBar is easy to integrate. It exists as a true Android library and hooks into the camera APIs and a SurfaceView without much hassle. Unfortunately ZBar hasn’t been maintained well. The last commit was in early 2012, and it is starting to show. Sadly you cannot get ZBar as a Maven dependency, so you are stuck manually updating the library.
ZBar is also severely lacking in documentation. The documentation past the instructions for including the library in Eclipse (ha!) is the sample project.
We had one last issue with ZBar. It seems as though ZBar is too quick to detect barcodes. Every now and then it detects a barcode but simply decodes the wrong number. Typically scanning a second time will result in the correct number, but I watched a friend scan an item five times once before it came up with the correct number. Since our users rely on the scanner to determine which (if any) products to purchase, this was a major problem.
Pros: Very quick, easy to integrate, supports barcodes in different orientations
Cons: Accuracy is poor, documentation is almost nonexistent, no longer actively maintained
We had high hopes for Google’s Mobile Vision API when Google announced it in late 2015. With Google’s prowess in the image processing field, we thought it would be a clear winner.
In some regards, we were right. So far in our testing it has proven to be fast and accurate. It can scan sideways barcodes just fine. The APIs are also flexible with the control you have over the camera and the UI you display to users.
Here’s the caveat: The core barcode scanning functionality is a native library that the Mobile Vision API needs to download to the device (yuck). That is something we could work with, but it gets worse. The Mobile Vision library won’t even attempt to download the native library if the user’s device reports that it is “low” on memory. “Low” could mean that as much as 10% of the user’s storage space is still free. Just to rub salt in the wound, the library doesn’t provide good feedback to you the developer that this is happening. When I first ran the Mobile Vision sample app on a test device, I just saw a camera preview that did nothing.
Even if Google offered proper feedback when it can’t download the library, this approach presents another issue. The user experience is terrible. How do we tell a user that they can’t scan barcodes until they delete some of their data? Users typically expect that apps come bundled with the core functionality ready to go. If I were using an app that presented me with this information, I would just uninstall it.
Google does have an interesting method of making downloading the library viable. Google offers a manifest flag that tells Google Play Services to download the native library when a user installs your app. This means the library may be available before the user opens your app. Again, this won’t work if the device is “low” on storage space.
The benefit to Google’s approach is that you should always have the latest version of the native library available. Because the library is shared between apps, you can also save on a little bit of storage space. However, I like to have some semblance of control over updates to my libraries, and I don’t believe that there are enough apps on my device with barcode scanning functionality to make the space savings worth the tradeoff.
Pros: Fast, accurate, flexible
Cons: Relies on a native library downloaded post-install to perform scanning. Library is not download if the device has “low” storage.
Choosing a barcode scanning library right now is an exercise in knowing the limitations of each of the available options right now. Explore what your needs are, and choose a library that fits your needs.
For the time being, we have opted to go back to ZXing because it has been the most reliable for us despite the fact that it is more difficult to work with on the development side.