npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@karus-systems/react-native-honeywell-intent

v0.1.0

Published

React Native + Expo library for Honeywell barcode scanners using the Data Collection Intent API — no Mobility SDK binary required.

Readme

react-native-honeywell-intent

Honeywell barcode scanning for React Native and Expo, over Honeywell's Data Collection Intent API — claim the scanner, configure symbologies, and receive decoded barcodes entirely through Android broadcasts.

No DataCollection.jar. No DataCollection.aar. No vendored binary.

That is the point of this library. Every other React Native Honeywell package commits Honeywell's Mobility SDK binary — distributed only through their auth-walled support portal — into its own repo, which raises a redistribution question and forces consumers to carry a binary they cannot audit or update. The Intent API needs no dependency at all, so this installs and autolinks like any other package.

Hardware-verified on a Honeywell CK65 (Android 8.1, Data Collection Service 1.95.00.0039): claim, release, decoder configuration, check digit transmission, trigger disable and barcode delivery all exercised on the device. Every property key is checked against the string table of the device's own DataCollectionService.apk rather than inferred — see ClaimRequest.kt for the command to re-verify against other firmware.

Install

npm install @karus-systems/react-native-honeywell-intent

Android only. Autolinks on React Native 0.60+.

Usage

import { useHoneywellScanner } from '@karus-systems/react-native-honeywell-intent';

function ScanScreen() {
  const { scannerState, isScannerReady, diagnostics } = useHoneywellScanner({
    onBarcode: (event) => console.log(event.data, event.labelType),
  });

  return <Text>{scannerState}</Text>;
}

The hook claims the scanner on mount, re-claims it when the app returns to the foreground, and releases it on unmount.

Scanner lifecycle

The reader is in one of three states. The counterintuitive one is Released: handing the scanner back does not switch it off, it gives it to the device default — so the beam still fires and decoded text can still land in whatever field has focus.

stateDiagram-v2
    [*] --> Released

    Released : Released
    Released : Device default (Scan Wedge) owns the reader
    Released : Beam FIRES · your app receives nothing

    Scanning : Scanning
    Scanning : Claim held · trigger live
    Scanning : Beam fires · barcodes delivered to your app

    Stopped : Stopped
    Stopped : Claim held · trigger disabled
    Stopped : Beam does NOT fire · nothing scans, anywhere

    Released --> Scanning : startReading()
    Scanning --> Stopped : stopReading()
    Stopped --> Scanning : startReading()
    Scanning --> Released : releaseReader()
    Stopped --> Released : releaseReader()
    Scanning --> Released : app backgrounds
    Stopped --> Released : app backgrounds
    Released --> Scanning : app resumes (was scanning)
    Released --> Stopped : app resumes (was stopped)

Backgrounding always releases, and resuming restores the state you were in — including a disabled trigger.

That release matters because the Data Collection Service does not revoke a claim when the holding app backgrounds. Holding it is harmless on its own — with a claim held from the background, Honeywell's own ScanDemo scanned normally in the foreground and no barcode leaked to the backgrounded app, so the service does arbitrate by foreground. What it will not do is undo a property. A trigger disabled by an app that then backgrounds stays disabled for the whole device until that app returns, which is why the library releases on pause rather than trusting the service to clean up after it.

Readiness is evidence, not assumption

A claim is never acknowledged. The Intent API has no reply, no status action and no queryable service, and the Data Collection Service silently transfers the reader when another app claims it. So "claimed" is what the library asked for, and a delivered barcode is the only proof it worked.

stateDiagram-v2
    [*] --> Unconfirmed : claim sent
    Unconfirmed : Unconfirmed
    Unconfirmed : We asked for the reader · nothing has proved it
    Confirmed : Confirmed
    Confirmed : A barcode arrived · the claim was real
    Unconfirmed --> Confirmed : barcode delivered
    Confirmed --> Unconfirmed : new claim supersedes the proof

isScanConfirmed from the hook (and diagnostics.scanConfirmed) exposes this, so a UI can say "claimed, unconfirmed" rather than asserting a readiness nobody has verified. Both are computed locally — getDiagnostics() performs no round-trip and cannot block.

Stopping the scanner

Three different things are easy to confuse, and only one of them actually stops the reader:

| Call | Effect | | --- | --- | | stopReading() | Disables the trigger, keeps the claim. The scanner genuinely stops. | | releaseReader() | Hands the reader back. The beam fires again under the device default. | | backgrounding | Releases automatically, re-claims on resume. Handled for you. |

releaseReader() is not a way to stop scanning. A released reader reverts to the device default — typically Scan Wedge — so the trigger still fires and decoded text can land in whatever field has focus. Use stopReading() for a screen where a stray scan would be destructive, and releaseReader() only when you are done with the scanner entirely.

Configuration

Expo

Add the config plugin. It writes the Android resources at prebuild and adds the <queries> entries diagnostics needs on Android 11+.

{
  "plugins": [
    [
      "@karus-systems/react-native-honeywell-intent",
      {
        "scanAction": "com.yourapp.SCAN",
        "scanner": "dcs.scanner.imager",
        "profile": "DEFAULT",
        "decoders": ["code128", "qrcode", "ean13"]
      }
    ]
  ]
}

Bare React Native

Write the same values yourself in android/app/src/main/res/values/honeywell_intent.xml — see the bare example. All values are optional; omit the file and the library defaults apply.

| Option | Default | Notes | | --- | --- | --- | | scanAction | <applicationId>.SCAN | Action decoded barcodes are broadcast to | | scanner | dcs.scanner.imager | Or dcs.scanner.ring for a Bluetooth ring scanner | | profile | DEFAULT | Named EZConfig profiles only | | decoders | ["code128"] | Symbologies to enable; all others are explicitly disabled |

Symbologies

Every symbology below is written on every claim — the ones you list as enabled, the rest as disabled. That matters when more than one app uses the scanner on a device: a Honeywell claim inherits whatever the previous claimant configured, so anything left unwritten would carry one app's settings into the next. Listing decoders therefore sets the reader's full state rather than adding to it.

| Group | Values | | --- | --- | | Linear | code128 gs1-128 code39 code93 code11 codabar msi telepen trioptic tlc39 | | Retail | ean8 ean13 upca upce upce1 | | 2 of 5 | i2of5 matrix-25 standard-25 iata-25 hk-25 | | GS1 DataBar | databar-14 databar-expanded databar-limited composite | | Stacked | pdf417 micropdf417 codablock-a codablock-f | | 2D | qrcode datamatrix aztec maxicode dotcode hanxin gridmatrix digimarc dpm | | Postal | postal korea-post |

Check digits are transmitted for EAN-8/13 and UPC-A/E. Decoder sub-options — supplemental addenda, Code 39 full ASCII, Code 128 ISBT, video reverse — are pinned off and are not currently configurable.

API

| Export | Purpose | | --- | --- | | useHoneywellScanner(options) | Hook: claim lifecycle, barcode delivery, diagnostics | | claimScanner() | Claim the reader and apply the configured decoders | | releaseScanner() | Release the reader | | setScannerClaimed(claimed) | Claim or release, whichever matches | | setTriggerEnabled(enabled) | Make the trigger inert while keeping the claim | | triggerSoftScan(start) | Start/stop the beam without the hardware trigger | | getDiagnostics() | Device and claim state snapshot | | openScannerSettings() | Deep-link to the Data Collection Service's settings | | addBarcodeListener(fn) | Raw barcode events | | addClaimStateListener(fn) | Claim taken/lost, including on backgrounding |

Relationship to the Zebra sibling

This library deliberately mirrors @karus-systems/react-native-zebra-datawedge so a codebase can support both fleets with one shape. Two differences are real and worth understanding rather than papering over:

Claim is a session, not a profile. A DataWedge profile is written once and persists on the device across reboots. A Honeywell claim is held by one app at a time. That is why the entry point is claimScanner() and not configureProfile() — calling it once at startup and assuming the device stays configured is the single most common way to end up with a scanner that mysteriously stops working.

Note the Data Collection Service does not revoke a claim when the holding app backgrounds — verified on a CK65, where a backgrounded app holding a claim with its trigger disabled left the reader dead for the entire device. This library therefore releases on pause itself and re-claims on resume, so a backgrounded app never keeps the scanner from the rest of the device. addClaimStateListener reports both transitions.

Diagnostics are thinner. DataWedge is a separate installable app that answers questions about itself — is it enabled, does the profile exist, what version. The Data Collection Service is firmware and answers nothing over the intent API. So Diagnostics here carries device facts and claim state only, all synchronous. There is no timeout, no "unknown" state, and correspondingly less to reconcile.

Alternatives and when to use them

Honeywell exposes three scanning surfaces, in increasing order of capability:

  1. Scan Wedge — keyboard wedge. Types decoded text into the focused field. Needs no code at all. If that is genuinely all you need, turn it on in the device settings and do not install this library.
  2. Data Collection Intent API — what this library wraps. Real barcode events, symbology configuration, soft trigger, claim lifecycle. No dependency.
  3. Mobility SDK (com.honeywell.aidc) — full BarcodeReaderProperties access and reader introspection, at the cost of a portal-gated binary. If you need properties this library cannot reach, that is the escape hatch — see react-native-honeywell.

Contributing

See CONTRIBUTING.md.

License

MIT