This React Native module allows a React Native application to use and control Socket Mobile wireless barcode scanners, NFC Reader/Writer, and Camera to capture and deliver data capture to such application.
The React Native CaptureSDK fully supports the React Native new architecture.
| Devices | < 2.0 | 2.0 |
|---|---|---|
| SocketCam C860 | ✅ | ✅ |
| SocketCam C820 | ✅ | ✅ |
| S720/D720/S820 | ✅ | ✅ |
| D600, S550, and all other barcode scanners | ✅ | ✅ |
| S370 | ✅ | ✅ |
| S320 | ✅ | ✅ |
| S721 (new Bluetooth LE barcode scanner) | ❌ | ✅ |
Version 2.0 introduces CaptureHelper, a high-level lifecycle manager that replaces the manual CaptureRn + onCaptureEvent switch/case pattern. Instead of constructing CaptureProperty objects and interpreting raw events yourself, you create a CaptureHelper instance with typed callbacks and call named methods.
import{CaptureHelper,typeCaptureHelperDevice,typeAppInfoRn,typeDecodedData,SocketCamTypes,BluetoothDiscoveryMode,Trigger,}from'react-native-capture';consthelper=newCaptureHelper({
appInfo,onDeviceArrival: (device)=>console.log(`Connected: ${device.name}`),onDeviceRemoval: (device)=>console.log(`Disconnected: ${device.name}`),onDecodedData: (data,device)=>console.log(`Scanned: ${data.dataasnumber[]}`),onError: ({ code, message })=>console.error(`Error ${code}: ${message}`),});awaithelper.open();Connected devices are now wrapped in CaptureHelperDevice objects that expose typed methods. No more building CaptureProperty by hand:
// Before (v1.x) — manual property constructionconstproperty=newCaptureProperty(CapturePropertyIds.FriendlyNameDevice,CapturePropertyTypes.None,{},);constresult=awaitdevice.devCapture.getProperty(property);// After (v2.0) — typed methodconstname=awaitdevice.getFriendlyName();Available device methods include getFriendlyName, setFriendlyName, getBatteryLevel, getFirmwareVersion, setTrigger, getDataSource, setDataSource, setDataConfirmation, getStandConfig, setStandConfig, and more.
Version 2.0 adds support for Bluetooth LE devices such as the S721. These devices use a manual discovery flow that the SDK handles for you. See Connecting Bluetooth LE Devices.
CaptureHelper was previously a static utility class with methods like CaptureHelper.setSocketCamEnabled(...). It is now an instance-based lifecycle manager that must be created with new CaptureHelper({...}) and opened with helper.open().
Callbacks like onDeviceArrival now receive CaptureHelperDevice instances instead of raw CaptureDeviceInfo. These objects have typed methods (getFriendlyName(), getBatteryLevel(), etc.) and properties (name, guid, type, handle).
The underlying CaptureRn instance is still accessible via device.devCapture if needed.
getBatteryLevel() now returns a plain number (0–100) instead of a bit-shifted value that required manual decoding.
The following interfaces have been removed: GetSocketCamEnabledArguments, SetSocketCamEnabledArguments, SocketCamTriggerButtonData, SocketCamStatusOption, SocketCamStatusSubOption.
Users who want to use Bluetooth LE readers have two options:
Option A — Install the Socket Mobile Companion app which handles discovery and pairing.
Option B — Implement the discovery flow in your own UI using the SDK's discovery methods. See Connecting Bluetooth LE Devices.
yarn add react-native-captureimportReact,{useState,useEffect,useRef}from'react';import{CaptureHelper,typeCaptureHelperDevice,typeAppInfoRn,typeDecodedData,typeDiscoveredDeviceInfo,SocketCamTypes,BluetoothDiscoveryMode,Trigger,}from'react-native-capture';constappInfo: AppInfoRn={appIdIos: 'ios:com.mycompany.myapp',appKeyIos: 'MC0C...',appIdAndroid: 'android:com.mycompany.myapp',appKeyAndroid: 'MC0C...',developerId: 'your-developer-id',};constApp=()=>{const[devices,setDevices]=useState<CaptureHelperDevice[]>([]);const[decodedData,setDecodedData]=useState<DecodedData|null>(null);const[status,setStatus]=useState('Opening Capture...');consthelperRef=useRef<CaptureHelper|null>(null);useEffect(()=>{consthelper=newCaptureHelper({
appInfo,onDeviceArrival: (device)=>{setDevices(d=>[...d,device]);},onDeviceRemoval: (device)=>{setDevices(d=>d.filter(dd=>dd.guid!==device.guid));},onDecodedData: (data,device)=>{setDecodedData(data);},onError: ({ code, message })=>{setStatus(`Error ${code}: ${message}`);},});helperRef.current=helper;helper.open().then(()=>setStatus('Capture open')).catch((err)=>setStatus(`Failed: ${err?.error?.message}`));return()=>{helper.close().catch(()=>{});};},[]);// ...};Once a device arrives, you can call methods directly on the CaptureHelperDevice:
constdevice=devices[0];// Get device infoconstfriendlyName=awaitdevice.getFriendlyName();constfirmware=awaitdevice.getFirmwareVersion();// firmware: { major, middle, minor, build, year, month, day }// Battery (returns 0–100 directly)constbattery=awaitdevice.getBatteryLevel();// Trigger a scanawaitdevice.setTrigger(Trigger.Start);// Enable/disable a symbologyawaitdevice.setDataSource(CaptureDataSourceID.SymbologyQRCode,CaptureDataSourceStatus.Enable);interfaceCaptureHelperCallbacks{onDeviceArrival?: (device: CaptureHelperDevice)=>void;onDeviceRemoval?: (device: CaptureHelperDevice)=>void;onDecodedData?: (data: DecodedData,device: CaptureHelperDevice)=>void;onSocketCamCanceled?: (device: CaptureHelperDevice)=>void;onDiscoveredDevice?: (device: DiscoveredDeviceInfo)=>void;onDiscoveryEnd?: (result: number)=>void;onBatteryLevel?: (level: number,device: CaptureHelperDevice)=>void;onPowerState?: (state: PowerState,device: CaptureHelperDevice)=>void;onButtons?: (state: Notifications,device: CaptureHelperDevice)=>void;onError?: (error: {code: number;message: string})=>void;}// Lifecycleawaithelper.open();awaithelper.close();// Get connected devicesconstdevices=helper.getDevices();// Access the underlying CaptureRn instance (needed for SocketCamViewContainer)constrootCapture=helper.rootCapture;// SDK infoconstversion=awaithelper.getVersion();// SocketCamawaithelper.setSocketCamEnabled(true);awaithelper.getSocketCamEnabled();// BLE discovery (see next section)awaithelper.addBluetoothDevice(BluetoothDiscoveryMode.BluetoothLowEnergy);awaithelper.connectDiscoveredDevice(discoveredDevice);awaithelper.removeBleDevice(connectedDevice);For Bluetooth LE products (S721, D600, S550, S370...) the SDK uses a manual discovery flow. With CaptureHelper, this is straightforward:
Call addBluetoothDevice on your CaptureHelper instance. Each nearby device triggers the onDiscoveredDevice callback.
const[discoveredDevices,setDiscoveredDevices]=useState<DiscoveredDeviceInfo[]>([]);// In your CaptureHelper callbacks:consthelper=newCaptureHelper({
appInfo,onDiscoveredDevice: (device)=>{setDiscoveredDevices(d=>{if(d.find(dd=>dd.identifierUuid===device.identifierUuid))returnd;return[...d,device];});},onDiscoveryEnd: ()=>{setStatus('Discovery finished');},// ...other callbacks});// Start scanningawaithelper.addBluetoothDevice(BluetoothDiscoveryMode.BluetoothLowEnergy);constconnectDevice=async(device: DiscoveredDeviceInfo)=>{awaithelper.connectDiscoveredDevice(device);// A successful connection triggers onDeviceArrival with a CaptureHelperDevice};constdisconnectDevice=async(device: CaptureHelperDevice)=>{awaithelper.removeBleDevice(device);// Triggers onDeviceRemoval};SocketCam (C820 / C860) lets your app use the device camera as a barcode scanner. In version 2.0, the SocketCamViewContainer component handles the native camera view and the SocketCam extension lifecycle.
// Toggle SocketCam on — this triggers a DeviceArrival for the SocketCam virtual deviceawaithelper.setSocketCamEnabled(true);// The SocketCam device appears in your devices listconstsocketCamDevice=devices.find(d=>SocketCamTypes.indexOf(d.type)>-1);Import and use the SocketCamViewContainer component where you want the camera view:
import{SocketCamViewContainer,Trigger,SocketCamTypes}from'react-native-capture';<SocketCamViewContaineropenSocketCamView={openSocketCamView}handleSetSocketCamEnabled={handleSetSocketCamEnabled}clientOrDeviceHandle={helper.rootCapture?.clientOrDeviceHandle}triggerType={Trigger.Start}socketCamCapture={helper.rootCapture}socketCamDevice={socketCamDevice}handleSetStatus={setStatus}handleSetSocketCamExtensionStatus={setExtensionStatus}socketCamCustomModalStyle={{presentationStyle: 'overFullScreen',animationType: 'fade',transparent: true,}}socketCamCustomStyle={customStyles}androidSocketCamCustomView={<MyCustomAndroidView/>}/>Android note: On Android, mount SocketCamViewContainer as soon as helper.rootCapture is available (before the user enables SocketCam). This starts the SocketCam extension process in the background. Without this, enabling SocketCam returns error -32 (ESKT_NOTAVAILABLE).
For more on SocketCam, check out the docs. For custom views, read more here.
// ❌ Before (v1.x)constcapture=newCaptureRn();awaitcapture.open(appInfo,onCaptureEvent);// ...then a big switch/case in onCaptureEvent// ✅ After (v2.0)consthelper=newCaptureHelper({
appInfo,onDeviceArrival: (device)=>{/* ... */},onDecodedData: (data,device)=>{/* ... */},// ...});awaithelper.open();// ❌ Beforeconstprop=newCaptureProperty(CapturePropertyIds.FriendlyNameDevice,CapturePropertyTypes.None,{});constresult=awaitdeviceCapture.getProperty(prop);constname=result.value;// ✅ Afterconstname=awaitdevice.getFriendlyName();// ❌ BeforeawaitCaptureHelper.setSocketCamEnabled({ socketCamCapture, ... });// ✅ Afterawaithelper.setSocketCamEnabled(true);// ❌ Before — manual DeviceManagerArrival handling, CaptureProperty for AddDevice// ✅ Afterawaithelper.addBluetoothDevice(BluetoothDiscoveryMode.BluetoothLowEnergy);// onDiscoveredDevice callback fires for each device foundawaithelper.connectDiscoveredDevice(discoveredDevice);The low-level CaptureRn class and all property types/enums are still exported and can be used directly if you need full control. CaptureHelper is the recommended approach for most applications.
In your build.gradle file, add the Socket Mobile release repo in the repositories section:
maven {
url "https://bin.socketmobile.com/repo/releases"
}In your app/build.gradle, add:
packagingOptions {
pickFirst '/lib/arm64-v8a/libc++_shared.so'
pickFirst '/lib/armeabi-v7a/libc++_shared.so'
}To enable Start Capture Service on Android (so that the developer doesn't need to actively run/open Companion), add a network security configuration.
In your-app/android/app/src/main/res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-configcleartextTrafficPermitted="false" />
<domain-configcleartextTrafficPermitted="true">
<domainincludeSubdomains="false">localhost</domain>
<domainincludeSubdomains="false">127.0.0.1</domain>
</domain-config>
</network-security-config>In AndroidManifest.xml, add to the <application> tag:
android:networkSecurityConfig="@xml/network_security_config"And before the closing </manifest> tag:
<queries>
<packageandroid:name="com.socketmobile.companion"/>
</queries>For more details, see the Android docs.
In your Info.plist, add camera access and the Companion URL scheme:
<key>NSCameraUsageDescription</key>
<string>Need to enable camera access for SocketCam products</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sktcompanion</string>
</array>More documentation available at Socket online documentation.