Release notes

Barcode Info 1.2: what a shipping label actually says

September 10, 2026 · UpFlyDev engineering

barcodeinforeleaseengineering

Point Barcode Info at the barcode on a parcel and, until this release, it told you the truth and not much else: Code 128, here are the characters. That is technically correct and practically useless, because the code on a parcel is not one number. It is a list of fields, and the list is why the label exists.

What's new

  • GS1 labels are read field by field. Scan a GS1-128 or GS1 DataMatrix code and the app lists what it carries: product number, batch or lot, production and packaging dates, best before, sell by, expiry, serial number, pallet number, location numbers, counts, weights, sizes and amounts. Dates come out as dates, and a measure comes out with its unit and the precision the label encodes.
  • A settings screen. It says how many scan photos are on the phone and how much room they take. Look through them, delete one, or clear them all and keep the scans.
  • Scan from the home screen on Android too. Press and hold the app icon, pick Scan. iPhone has had this since 1.1.
  • The history list reads better. What the code is on one line, when you scanned it on the next, and a QR code carries a small icon for what is inside it: a link, a Wi-Fi network, a note.
  • iOS 15 or later for this version, up from iOS 13.

Nothing about the privacy model changed. The parsing is arithmetic and a lookup table, so it runs where everything else in this app runs: on the phone, with no network. The Android release build still ships with no internet permission at all.

Under the hood

A code with no delimiters in it

A GS1 payload is a run of pairs: a two to four digit Application Identifier, then its value, then the next identifier. There is no separator between them. 010400638133393115280331 is a product number followed by a best before date, and the only way to know where one ends is to know that identifier 01 is always followed by exactly fourteen digits.

Values that vary in length are terminated by FNC1, a control character that arrives in the payload as the ASCII group separator. It is invisible, and every font draws it as an empty box, so the app now spells it out as [GS] when it shows you the raw code. The copy button still gives you the bytes exactly as scanned.

An identifier we do not know stops the reading

The General Specifications are long, and this release reads the identifiers that turn up on retail packs and shipping labels rather than all of them. That raises an obvious question: what happens at an identifier the app has never heard of?

It cannot skip it. The length of an unknown identifier is unknowable, so there is no way to find where its value ends and the next field starts. Guessing would produce a batch number that is half a batch number, presented with the same confidence as a correct one.

So the parser stops, keeps everything it read up to that point, and the sheet says the rest of the code uses an identifier it does not read yet. A label with one exotic field stays useful, and nothing on screen is invented.

Plain text that looks like a label

Here is the trap. A Code 128 code on a warehouse shelf might just say 10ABC. Read as GS1, that is identifier 10, batch ABC, and the app would announce a batch number that nobody encoded.

A payload is therefore only accepted as GS1 when it starts with a known identifier and one of three things also holds: it contains a separator, so the encoder was working in GS1 mode; or it opens with a fixed length field whose value is exactly that long, which plain text rarely is; or it decodes into more than one field. 10ABC passes none of those and stays what it is, which is text.

The label's own product number

If a label carries identifier 01, that is a GTIN, and the app already knows what to do with a GTIN. So the check digit gets verified and the country of registration gets looked up, exactly as they would for the EAN-13 on a tin of beans. A pallet label with no product number in it says so instead, rather than being called invalid.

Identifier 02, which is the product number of the items inside a logistic unit, deliberately does not do this. It describes the contents, not the label.

Two digits of year, fifty years of window

GS1 dates are six digits: 280331 is the 31st of March 2028. Two digit years need a rule for the century, and the standard's rule is a window that runs from 49 years back to 50 years forward, which means the same six digits mean different things depending on when you scan them. Day 00 is also legal and means the last day of that month, so the app shows the last day and says that is what it did.

None of this is hard, and all of it is easy to get wrong in a way nobody notices for years. The parser takes the current date as an argument rather than reading the clock, so the tests pin every edge of that window instead of passing until 2050.

Checked on both engines. The parser is covered by unit tests, but what the two scanning engines put in the payload where FNC1 was is not something a unit test can answer. ML Kit on Android and Vision on iOS do not have to agree. They do: a GS1-128 and a GS1 DataMatrix carrying real separators both came out whole on an iPhone and on a moto g stylus, with the batch number ending where it should rather than swallowing the field after it.

Get Barcode Info, free, offline, no accounts and nothing collected. On both stores.

Download on the App Store Get it on Google Play

Learn more about Barcode Info →