Skip to main content
Not sure which Scandit product fits your use case?

Install the Scandit plugin and use the /data-capture-sdk skill so that your AI coding agent can recommend the right product for your use case. More info →

Run the following command in your project directory. It detects the supported coding agents you have installed and adds the Scandit plugin to each. Re-run it to update.

npx plugins add scandit/skills

Prefer to set it up yourself? Manual installation steps for each agent →

Get Started

The AIO ("all-in-one") components are React scanning views that own their own capture mode, overlay, camera claim and lifecycle. You render one component instead of assembling a context, a mode, a view and an overlay by hand.

They are available from version 8.7.

Use an AIO view for a standard scanning screen. Use the classic Barcode Capture path when you need to build the capture pipeline yourself, for example to drive the camera or compose overlays your own way. Both are supported.

In this guide you will learn step-by-step how to build a scanner with them. The general steps are:

  1. Wrap your app in ScanditProvider.
  2. Add a scanning view and handle the barcodes it reads.
  3. Navigate between two scanning screens.
  4. Set the camera position and torch, and handle camera permissions.

Prerequisites

  • The latest stable version of React Native CLI and other related tools and dependencies.
  • A valid Scandit Data Capture SDK license key. You can sign up for a free test account.
  • If you have not already done so, see this guide for information on how to add the Scandit Data Capture SDK to your project. This guide imports from two packages, so install both: scandit-react-native-datacapture-core and scandit-react-native-datacapture-barcode.
  • Navigation is your own choice of library, and is not part of the Scandit SDK. The examples here use React Navigation, which needs @react-navigation/native and @react-navigation/stack.

Add the Provider

ScanditProvider creates the DataCaptureContext and the single Camera that the AIO scanning views share, and tracks camera permission. Every AIO view needs one above it.

It ships in the core package. Mount one at the root of your app and pass your license key, which is the key from your Scandit dashboard or the test account linked above:

import { NavigationContainer } from '@react-navigation/native';
import { ScanditProvider } from 'scandit-react-native-datacapture-core';

const LICENSE_KEY = 'YOUR_LICENSE_KEY_HERE';

export default function App() {
return (
<ScanditProvider licenseKey={LICENSE_KEY}>
<NavigationContainer>{/* your screens */}</NavigationContainer>
</ScanditProvider>
);
}

That is all the setup a first scanner needs.

Add a Scanning View

SparkScanAioView is the quickest view to start with: it brings its own scanning UI, including the trigger button and the mini preview.

Pass the symbologies you want to read, and a didScan callback to receive them:

import { SparkScanAioView, Symbology } from 'scandit-react-native-datacapture-barcode';

const SYMBOLOGIES = [Symbology.EAN13UPCA, Symbology.Code128];

function ScanScreen({ navigation }) {
return (
<SparkScanAioView
style={{ flex: 1 }}
// Lets the view stop scanning when this screen loses focus, and start
// again when it comes back. See Navigate Between Scanning Screens below.
navigation={navigation}
symbologies={SYMBOLOGIES}
didScan={(barcodes) => {
for (const barcode of barcodes) {
console.log(barcode.data);
}
}}
/>
);
}

EAN13UPCA and Code128 are two common retail symbologies. Enable whichever ones you need: the full list is in the Symbology reference.

Render the screen inside the provider from the previous section, and you have a working scanner:

export default function App() {
return (
<ScanditProvider licenseKey={LICENSE_KEY}>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Scan" component={ScanScreen} />
</Stack.Navigator>
</NavigationContainer>
</ScanditProvider>
);
}

didScan is called for each newly recognized barcode. If you need to do asynchronous work before the next scan is processed, such as looking the barcode up, return a promise and the view waits for it:

didScan={async (barcodes) => {
await lookupProduct(barcodes[0].data);
}}
tip

Declare SYMBOLOGIES outside the component, as above. A new array on every render is a new value, which makes the view re-apply its settings more often than it needs to.

Calling the View Directly

Every AIO view exposes a handle through a ref. The handle carries the imperative methods for that view, and every AIO view has enable() and disable() on it for turning scanning on and off yourself:

import { useRef } from 'react';

function ScanScreen({ navigation }) {
const view = useRef(null);

return (
<>
<SparkScanAioView
ref={view}
style={{ flex: 1 }}
navigation={navigation}
symbologies={SYMBOLOGIES}
didScan={(barcodes) => console.log(barcodes[0]?.data)}
/>
<Button title="Stop scanning" onPress={() => view.current?.disable()} />
</>
);
}

Two scanning screens cannot both drive the camera. The newest view to claim it takes ownership, and passing each view the screen's navigation object suspends scanning while that screen is blurred.

See Navigating Between Screens for the ownership model and the lifecycle props that control when each view scans.

Camera Position and Torch

For the views that share the provider's camera, set the torch and camera position on the provider. The outermost provider is the root: it creates the context and the camera, and disposes of both when it unmounts. licenseKey is required there and ignored, with a warning, anywhere else.

A provider mounted below another is nested. It creates nothing, and applies its own torchState and cameraPosition to the same camera the root owns. Nesting one around a single screen is the supported way to control the camera for that screen only:

import { CameraPosition, TorchState } from 'scandit-react-native-datacapture-core';

function TorchScreen({ navigation }) {
return (
<ScanditProvider
torchState={TorchState.On}
cameraPosition={CameraPosition.WorldFacing}>
<ScanScreen navigation={navigation} />
</ScanditProvider>
);
}
note

torchState and cameraPosition are set-only. A nested provider does not restore the previous values when it unmounts, so set what you need on the screen that needs it.

warning

These props do not reach SparkScanAioView, because it drives its own camera. Set its starting state through SparkScanViewSettings.defaultTorchState and SparkScanViewSettings.defaultCameraPosition, and let the user change it with the view's built-in controls: torchControlVisible and cameraSwitchButtonVisible.

tip

Please refer to ScanditProvider for the full list of parameters.

Camera Permissions

useCameraPermission reports the current permission state and asks for it:

import { useEffect } from 'react';
import { useCameraPermission } from 'scandit-react-native-datacapture-core';

function CameraGate({ children }) {
const { hasPermission, requestPermission } = useCameraPermission();

useEffect(() => {
if (!hasPermission) {
void requestPermission();
}
}, [hasPermission, requestPermission]);

return hasPermission ? children : null;
}
note

The two platforms behave differently. On Android the hook reports the real status, requestPermission() shows the system prompt, and the status is re-checked when your app returns to the foreground. On iOS the system shows its own dialog the first time the camera is used, so the hook reports not-determined until that happens.

React Native Architecture Support

The AIO components run on both React Native architectures.

The new architecture is the default for new applications, and React Native 0.82 and later run it exclusively. The legacy ("Paper") architecture is also supported: every AIO view has been verified rendering on it, on both iOS and Android, on React Native 0.81.4 and 0.74.7.

note

React Native 0.74 is the lowest version verified against this SDK. Older releases are not supported.

Troubleshooting

Nothing happens when you point at a barcode. The symbology is probably not enabled. Only the symbologies in the array you pass are read, so a QR code is ignored by the example above. Add it to SYMBOLOGIES, or check the Symbology reference for the name you need.

The preview is black, or freezes when you come back to a screen. Two scanning views are competing for the camera. Pass every view the screen's navigation object so that a blurred screen releases the camera, and read Navigating Between Screens.

The camera never starts and no permission dialog appears. On Android, call requestPermission() from useCameraPermission: the system prompt does not appear on its own. On iOS the dialog is shown the first time the camera is used, so if it never appears, no view has claimed the camera yet.

Scan Some Barcodes

Now that you're up and running, go find some barcodes to scan. Don't feel like getting up from your desk? Here's a handy pdf of barcodes you can print out.

Where to Go Next