Getting Started with React Native CaptureSDK

Requirements

The Socket Mobile CaptureSDK uses Bluetooth Classic for the barcode scanner products and Bluetooth Low Energy (BLE) for the Contactless Reader/Writer products (Socket Mobile D600, S550) and the new S721 barcode scanner.

Even though the React Native CaptureSDK allows to develop an app to run on iOS and Android the underlying Capture architecture on these 2 platforms is different.

On Android there is a service embedded in the Socket Mobile Companion app that is required in order to connect the Socket Mobile device to the Android host.

On iOS the communication with the Socket Mobile devices are embedded in the React Native Module therefore adding more configuration to be taken care of in the application itself.

Requirements for iOS platform

For applications that need to work with barcode scanners, make sure the following requirements are met:

  1. Your iOS application needs to be registered in our Apple MFI Approved Application list before submitting your application to the Apple Store. It will not pass the Apple Store review if this is not done.

  2. Your application must have the string com.socketmobile.chs in the Supported External Protocol setting.
    ExternalAccessory

  3. In your Info.plist, you need to add the sktcompanion scheme to the LSApplicationQueriesSchemes array.

<key>NSCameraUsageDescription</key>
        <string>Need to enable camera access for SocketCam products such as C820</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<key>LSApplicationQueriesSchemes</key>
<array>
  <string>sktcompanion</string>
</array>

4. Your application must add some security descriptions for the Bluetooth permissions shown here:
BluetoothPrivacy

Note

For more info on enabling your app for iOS, check out the documentation pertaining to iOS.

Requirements for Android platform

  1. Add the below lines to your AndroidManifest.xml file, found in your app’s android/app/src/main folder, right under your opening <manifest> tag.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  1. Add the below lines to your AndroidManifest.xml file.

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<meta-data android:name="com.socketmobile.capture.APP_KEY" android:value="YOUR_APP_KEY"/>
<meta-data android:name="com.socketmobile.capture.DEVELOPER_ID" android:value="YOUR_DEVELOPER_ID"/>
  1. Next, you will need to enable communication to Socket Mobile Companion. Right before your closing </manifest> tag, put the below queries property.

<queries>
  <package android:name="com.socketmobile.companion"/>
</queries>
  1. Next you will need to update the <application> tag to include android:networkSecurityConfig="@xml/network_security_config". It should look something like the below.

<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:networkSecurityConfig="@xml/network_security_config">
  1. Next, add a file called network_security_config.xml to your xml directory, which can be found in your app’s android/app/src/main/res folder. This file should look like this.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <base-config cleartextTrafficPermitted="false" />
  <domain-config cleartextTrafficPermitted="true">
      <domain includeSubdomains="false">localhost</domain>
      <domain includeSubdomains="false">127.0.0.1</domain>
  </domain-config>
</network-security-config>
  1. The final step is to add Socket Mobile’s Maven repository to your project so that Gradle can resolve all transitive dependencies (including com.honeywell:swiftdecoder, which is required by capture-socketcam). Add the following to the repositories block used for dependency resolution in your project (e.g. settings.gradle under dependencyResolutionManagement, or build.gradle under allprojects):

maven {
  url "https://bin.socketmobile.com/repo/releases"
}

Note

For more info on enabling your app for Android, check out the documentation pertaining to Android.

Requirements for both iOS and Android platforms

  1. Your application will need a SocketMobile AppKey. Follow the link to create an AppKey. AppKeys can be generated online and at no additional cost beyond the nominal one time registration fee. The AppKey is validated by the SDK library on the device, no internet connection is required. Note: You don’t need to create your own AppKey to compile and run the sample apps.

  2. The scanner needs to be paired with your devices in Application Mode. This can be done using Socket Mobile Companion app which can be downloaded from the App Store .

  3. Try our React Native sample app Single Entry React Native.

SDK Installation

The React Native CaptureSDK is released as a NPM (Node Package Manager) package.

Using yarn

yarn add react-native-capture

Using npm

npm install --save react-native-capture

Using CaptureSDK with CaptureRn (low-level)

The low-level CaptureRn class is still available for developers who need full control. Import it as follows:

import { CaptureRn, CaptureEventIds, SktErrors } from 'react-native-capture';

Here are the usual steps to follow:

  1. Open Capture with the App credentials and provide event handler function

  2. Handle device arrival and open the device in the event handler function

  3. Handle device removal and close the device in the event handler function

  4. Handle decoded data in the event handler function

Opening Capture with App credentials

The React Native CaptureSDK is an extension of the CaptureJS SDK. The main difference is the first instance that uses CaptureRn instead of Capture:

const appInfo: AppInfoRn = {
  appIdIos: 'ios:com.socketmobile.reactjs.native.example.example',
  appIdAndroid: 'android:com.example',
  developerId: 'ecc6c526-970b-ec11-b6e6-0022480a2304',
  appKeyIos: 'MC0CFHL9no0HS6LohlvgGj3s6R4fUTTGAhUAjkIUkoWjCi8NXAjDB9uk9WMdlJc=',
  appKeyAndroid:
    'MC0CFBJxr9ERxurLZQk8voZsFC7BH+8zAhUAxbT41GqB8EwOu7JtVYhffCnTdmI=',
};

const App = () => {
  const [capture] = useState(new CaptureRn());
  const [status, setStatus] = useState<string>('Opening Capture...');
  const [isOpen, setIsOpen] = useState<boolean>(false);

  const openCapture = () => {
    capture
      .open(appInfo, onCaptureEvent as Notification)
      .then(() => {
        setStatus('capture open success');
        setIsOpen(true);
      })
      .catch((err: any) => {
        const {error} = err;
        const {code, message} = error;
        setStatus(`failed to open Capture: ${code} \n ${message}`);
        if (code === SktErrors.ESKT_UNABLEOPENDEVICE) {
          setStatus('Is Socket Mobile Companion app installed?');
        }
      });
  };

Handle device arrival and open the device

When the application receives a Device Arrival notification, it can create a new CaptureRn object that represents the new device.

The application opens the device by passing GUID and the main CaptureRn reference as arguments of the device open function.

Opening the device allows to receive the decoded data from this device.

Note

the device GUID changes everytime the device connects. It identifies a connection session with a device.

Note

If a Socket Mobile device is already connected to the host prior to the app opening CaptureSDK, the device arrival notification will still be sent to make the application aware that the device is connected.

const onCaptureEvent = (e, handle) => {
  if (!e) {
    return;
  }

  switch (e.id) {
    case CaptureEventIds.DeviceArrival:
      const newDevice = new CaptureRn();
      openDeviceHelper(newDevice, e, false);
      break;

    // OTHER EVENT CASES
}

Handle device removal and close the device

The device removal occurs when the Socket Mobile is no longer connected to the host. It is recommended to close it.

case CaptureEventIds.DeviceRemoval:
  let index = devs.findIndex((d: CaptureDeviceInfo) => {
      return d.guid === e.value.guid;
    });
    if (index >= 0) {
      let removeDevice = devs[index];
      removeDevice!.devCapture
        .close()
        .then((result: number) => {
          devs.splice(index, 1);
          setDevices(devs);
        })
        .catch((res: JRpcError) => {
          let {error} = res;
          let {message, code} = error;
          setStatus(`error closing a device: ${code}: ${message}`);
        });
    }
  break;

Handle decoded data in the event handler function

Each time a Socket Mobile device is successful at reading a barcode or an NFC tag, the decoded data notification is sent:

case CaptureEventIds.DecodedData:
  let devWithInfo = stateRef.current.devices.find(
    (d: CaptureDeviceInfo) => {
      return d.handle === handle;
    },
  );

  if (devWithInfo) {
    setStatus('Decoded Data from ' + devWithInfo.name);
  }
  lastDecodedData = {
    data: arrayToString(e.value.data),
    length: e.value.data.length,
    name: e.value.name,
  };
  setDecodedData(lastDecodedData);
  break;