# Connect to our products with CaptureSDK

Guide for connecting Socket Mobile Bluetooth Low Energy (BLE) devices directly through CaptureSDK without the Companion app. Covers BLE device discovery, connecting to discovered devices, handling device arrival and removal events, and managing multi-function devices (combo barcode scanner + NFC reader like the S370). Includes code samples for discovery, connect and disconnect BLE device.

## Connect Bluetooth LE devices

First initialize CaptureSDK. Please refer to [Capture Helper initialization](/docs/using-capturesdk/capture-helper).

Then the steps to connect to Bluetooth Low Energy (BLE) devices like NFC reader/writer and barcode scanner are the following:

Implement the **discovery events** — delivered by **CaptureHelper** on iOS, C#, JavaScript and Dart, or as **EventBus events** on Android to be notified when the discovery has ended and has discovered Bluetooth LE devices.

Then you can adapt the connection flow to your own UI as the discovery provides devices in the vicinity.

A full connection flow is available in [our samples apps on Github](https://github.com/SocketMobile?view_as=public).

## Add Bluetooth Low Energy or Bluetooth Classic devices Discovery

You can choose either Bluetooth Classic or Bluetooth LE Discovery.

## Bluetooth LE Discovery

### Discovery and adding a device

Launch the discovery for Bluetooth LE devices in your own UI or directly once CaptureSDK is started:

## Java

```java
byte deviceType = (byte) BluetoothDiscoveryMode.BLUETOOTH_LOW_ENERGY;

mCaptureClient.addDevice(deviceType, new PropertyCallback() {
    @Override
    public void onComplete(@Nullable CaptureError error, @Nullable Property property) {
        if (error == null) {
            // Discovery started successfully, show your own UI to list discovered devices
            showMyDiscoveryUI();
        } else {
            // Handle error
        }
    }
});
```

## Kotlin

```kotlin
val deviceType: Byte = BluetoothDiscoveryMode.BLUETOOTH_LOW_ENERGY.toByte()

mCaptureClient.addDevice(deviceType) { error, property ->
    if (error == null) {
        // Discovery started successfully, show your own UI to list discovered devices
        showMyDiscoveryUI()
    } else {
        // Handle error
    }
}
```

## Swift

```swift
let captureHelper = CaptureHelper.sharedInstance
// Here we start the discovery with 'addBluetoothDevice' and the parameter '.bluetoothLowEnergy'
captureHelper.addBluetoothDevice(.bluetoothLowEnergy , withCompletionHandler: { result in
    print("addBluetoothDevice - Bluetooth Low Energy: \(result.rawValue)")
})

// Here you can show your own UI to show the discovered devices
showMyDiscoveryUI()
```

## C#

```csharp
// capture is of type "CaptureHelper" and is initialized
await capture.AddBluetoothDeviceAsync(
    ICaptureProperty.Values.BluetoothDiscoveryMode.kBluetoothLowEnergy);

// Show your own UI to list the discovered devices
ShowMyDiscoveryUI();
```

## Dart

```dart
// BLE discovery (for S721, D600, S550, S370, S320...)
await helper.addBluetoothDevice(
  mode: BluetoothDiscoveryMode.bluetoothLowEnergy,
);

// Show your own UI to list the discovered devices
showMyDiscoveryUI();
```

## JavaScript

```javascript
// BLE discovery (for S721, D600, S550, S370, S320...)
await helper.addBluetoothDevice(BluetoothDiscoveryMode.BluetoothLowEnergy);

// Show your own UI to list the discovered devices
showMyDiscoveryUI();
```

Then for each discovered device the **device discovery event** is triggered. We advise you to keep an array of discovered devices to show them in your own UI:

## Java

```java
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onCaptureDeviceDiscoveryChange(DeviceDiscoveryEvent event) {
    DiscoveredDevice device = event.getDiscoveredDevice();
    if (device != null) {
        String uniqueIdentifier = device.getUniqueIdentifier();
        String name = device.getName();

        // Keep the discovered device in a list to show it in your own UI
        if (!discoveredDevices.contains(device)) {
            discoveredDevices.add(device);
            runOnUiThread(() -> myDiscoveredDevicesAdapter.notifyDataSetChanged());
        }
    }
}
```

## Kotlin

```kotlin
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onCaptureDeviceDiscoveryChange(event: DeviceDiscoveryEvent) {
    val device = event.discoveredDevice ?: return
    val uniqueIdentifier = device.uniqueIdentifier
    val name = device.name

    // Keep the discovered device in a list to show it in your own UI
    if (!discoveredDevices.contains(device)) {
        discoveredDevices.add(device)
        runOnUiThread { myDiscoveredDevicesAdapter.notifyDataSetChanged() }
    }
}
```

## Swift

```swift
func didDiscoverDevice(_ device: SKTCaptureDiscoveredDeviceInfo) {
    print("didDiscoverDevice: \(device.name) - \(device.identifierUuid)")

    // Keep the discovered device in an array to show them in your own UI
    if !discoveredDevices.contains(where: { deviceToCompare in
        return device.identifierUuid == deviceToCompare.identifierUuid
    }) {
        discoveredDevices.append(device)
        DispatchQueue.main.async {
            self.myDiscoveredDevicesTableView?.reloadData()
        }
    }
}
```

## C#

```csharp
capture.DeviceDiscovered += Capture_DeviceDiscovered;

List<CaptureDiscoveredDeviceInfo> discoveredDeviceList = new List<CaptureDiscoveredDeviceInfo>();

private void Capture_DeviceDiscovered(object sender,
    CaptureHelper.DeviceDiscoveredArgs e)
{
    CaptureDiscoveredDeviceInfo info = e.DeviceDiscoveredInfo;
    Debug.WriteLine($"didDiscoverDevice: {info.Name} - {info.IdentifierUuid}");

    // Keep the discovered device in a list to show it in your own UI
    if (!discoveredDeviceList.Any(d => d.IdentifierUuid == info.IdentifierUuid))
    {
        discoveredDeviceList.Add(info);
    }
}
```

## Dart

```dart
onDiscoveredDevice: (DiscoveredDeviceInfo info) {
  print('didDiscoverDevice: ${info.name} - ${info.identifierUuid}');

  // Keep the discovered device in a list to show it in your own UI
  if (!discoveredDevices.any((d) => d.identifierUuid == info.identifierUuid)) {
    setState(() {
      discoveredDevices.add(info);
    });
  }
},
```

## JavaScript

```javascript
onDiscoveredDevice: (device) => {
    console.log(`Found: ${device.name} (${device.identifierUuid})`);

    // Keep the discovered device in an array to show it in your own UI
    setDiscoveredDevices((current) => {
        if (current.find((d) => d.identifierUuid === device.identifierUuid)) {
            return current;
        }
        return [...current, device];
    });
}
```

The device discovery ends once the time out has elapsed and notifies your app by calling the **end discovery event**:

## Java

```java
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onCaptureDeviceDiscoveryChange(DeviceDiscoveryCompleteEvent event) {
    if (event.isComplete()) {
        // Discovery has ended
    }
}
```

## Kotlin

```kotlin
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onCaptureDeviceDiscoveryChange(event: DeviceDiscoveryCompleteEvent) {
    if (event.isComplete) {
        // Discovery has ended
    }
}
```

## Swift

```swift
func didEndDiscoveryWithResult(_ result: SKTResult) {
    print("end discovery with result: \(result.rawValue)")
}
```

## C#

```csharp
capture.DiscoveryEnded += Capture_DiscoveryEnded;

private void Capture_DiscoveryEnded(object sender,
    CaptureHelper.DiscoveryEndedArgs e)
{
    Debug.WriteLine("DiscoveryEnded");
}
```

## Dart

```dart
onDiscoveryEnd: (int result) {
  print('end discovery with result: $result');
},
```

## JavaScript

```javascript
onDiscoveryEnd: () => {
    console.log('Discovery scan finished');
}
```

To connect to a discovered device, use **CaptureHelper's connect** method or **CaptureClient.connectDevice()** on Android:

## Java

```java
mCaptureClient.connectDevice(deviceUniqueIdentifier, new PropertyCallback() {
    @Override
    public void onComplete(@Nullable CaptureError error, @Nullable Property property) {
        if (error == null) {
            // Connection initiated successfully.
            // Wait for the device arrival event to confirm the device is ready.
        } else {
            // Handle connection error
        }
    }
});
```

## Kotlin

```kotlin
mCaptureClient.connectDevice(deviceUniqueIdentifier) { error, property ->
    if (error == null) {
        // Connection initiated successfully.
        // Wait for the device arrival event to confirm the device is ready.
    } else {
        // Handle connection error
    }
}
```

## Swift

```swift
let captureHelper = CaptureHelper.sharedInstance
captureHelper.connectToDiscoveredDevice(selectedDiscoveredDevice) { result in
    print("connectToDiscoveredDevice: \(device.name ?? "") - Result: \(result.rawValue)")

    // Keep the connected device in an array to show them in your own UI
    self.connectedDevices.append(device)
    self.myConnectedDevicesTableView.reloadData()
}
```

## C#

```csharp
// selectedDiscoveredDeviceInfo is of type "CaptureDiscoveredDeviceInfo" and retrieved from Capture's DeviceDiscovered event. See Capture_DeviceDiscovered
await capture.ConnectToDiscoveredDeviceAsync(selectedDiscoveredDeviceInfo);

// Update your own UI once the device arrival event is received
```

## Dart

```dart
await helper.connectDiscoveredDevice(device: selectedDiscoveredDevice);

// Update your own UI once the device arrival event is received
```

## JavaScript

```javascript
const connectDevice = async (device) => {
    try {
        await helper.connectDiscoveredDevice(device);
        // Update your own UI once the device arrival event is received
    } catch (err) {
        console.error('Failed to connect:', err?.error?.message);
    }
};
```

Then the device will connect automatically and you will be notified in the **device arrival event** (**DeviceStateEvent** on Android).

The next time you open your application, CaptureSDK will automatically connect to this connected device as it becomes a favorite device.

### Removing a device

To remove favorite devices, use **CaptureHelper's remove** method or **CaptureClient.removeDevice()** on Android. Pass the device’s identifier to remove it:

## Java

```java
mCaptureClient.removeDevice(uniqueDeviceIdentifier, new PropertyCallback() {
    @Override
    public void onComplete(@Nullable CaptureError error, @Nullable Property property) {
        if (error == null) {
            // Device removed from favorites
            connectedDevices.remove(device);
            runOnUiThread(() -> myConnectedDevicesAdapter.notifyDataSetChanged());
        } else {
            // Handle error
        }
    }
});
```

## Kotlin

```kotlin
mCaptureClient.removeDevice(uniqueDeviceIdentifier) { error, property ->
    if (error == null) {
        // Device removed from favorites
        connectedDevices.remove(device)
        runOnUiThread { myConnectedDevicesAdapter.notifyDataSetChanged() }
    } else {
        // Handle error
    }
}
```

## Swift

```swift
let captureHelper = CaptureHelper.sharedInstance
if let deviceGuid = device.deviceInfo.guid {
    captureHelper.removeBluetoothDevice(deviceGuid) { result in
        print("removeBluetoothDevice: \(device.deviceInfo.name ?? "") - Result: \(result.rawValue)")

        // Update the connected devices array to update your own UI
        if result == .E_NOERROR {
            if let index = self.connectedDevices.firstIndex(of: device) {
                self.connectedDevices.remove(at: index)
                self.myConnectedDevicesTableView.reloadData()
            }
        }
    }
}
```

## C#

```csharp
// device is of type "CaptureHelperDevice" and retrieved from Capture's DeviceArrival event. See Capture_DeviceArrival
await capture.RemoveBluetoothDeviceAsync(device);

// Update the connected devices list to refresh your own UI
connectedDevices.Remove(device);
```

## Dart

```dart
await helper.removeBleDevice(device: connectedDevice);

// Update the connected devices list to refresh your own UI
setState(() {
  connectedDevices.remove(connectedDevice);
});
```

## JavaScript

```javascript
const disconnectDevice = async (device) => {
    try {
        await helper.removeBleDevice(device);

        // Update the connected devices array to refresh your own UI
        setConnectedDevices((current) =>
            current.filter((d) => d.guid !== device.guid)
        );
    } catch (err) {
        console.error('Error disconnecting:', err?.error?.code);
    }
};
```

## Bluetooth Classic Discovery

Launch the discovery for Bluetooth Classic devices. On iOS this will show the native system picker to select the device(s) to connect to:

> **Note**
>
> The Bluetooth Classic discovery can be launched right after the opening of the CaptureSDK.
>
> Devices will connect automatically and you will be notified with the <b>device arrival event</b> and they will also connect automatically the next times.

## Java

```java
byte deviceType = (byte) BluetoothDiscoveryMode.BLUETOOTH_CLASSIC;

mCaptureClient.addDevice(deviceType, new PropertyCallback() {
    @Override
    public void onComplete(@Nullable CaptureError error, @Nullable Property property) {
        // Bluetooth Classic discovery launched
    }
});
```

## Kotlin

```kotlin
val deviceType: Byte = BluetoothDiscoveryMode.BLUETOOTH_CLASSIC.toByte()

mCaptureClient.addDevice(deviceType) { error, property ->
    // Bluetooth Classic discovery launched
}
```

## Swift

```swift
let captureHelper = CaptureHelper.sharedInstance
// Here we start the discovery with 'addBluetoothDevice' and the parameter '.bluetoothClassic'
captureHelper.addBluetoothDevice(.bluetoothClassic , withCompletionHandler: { result in
    print("addBluetoothDevice - Bluetooth Classic: \(result.rawValue)")
})
```

## C#

```csharp
await capture.AddBluetoothDeviceAsync(
    ICaptureProperty.Values.BluetoothDiscoveryMode.kBluetoothClassic);
```

## Dart

```dart
// Classic Bluetooth discovery (for S720, D720, S820...)
await helper.addBluetoothDevice(
  mode: BluetoothDiscoveryMode.bluetoothClassic,
);
```

## JavaScript

```javascript
// Classic Bluetooth discovery (for S720, D720, S820...)
await helper.addBluetoothDevice(BluetoothDiscoveryMode.BluetoothClassic);
```

## Additional context

For a combo device like the S370 which has 2 devices, there will be two **device arrival events** and two **device removal events**. The following code shows how you can distinguish and handle them:

## Java

```java
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onCaptureDeviceStateChange(DeviceStateEvent event) {
    DeviceClient device = event.getDevice();
    DeviceState state = event.getState();

    if (state.intValue() == DeviceState.READY) {
        int deviceType = device.getDeviceType();

        if (deviceType == DeviceType.kModelNfcS370) {
            // Handle the NFC reader of the S370
        } else if (deviceType == DeviceType.kModelScannerS370) {
            // Handle the Barcode scanner of the S370
        }
    }
}
```

## Kotlin

```kotlin
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onCaptureDeviceStateChange(event: DeviceStateEvent) {
    val device: DeviceClient = event.device
    val state = event.state

    if (state.intValue() == DeviceState.READY) {
        when (device.deviceType) {
            DeviceType.kModelNfcS370 -> {
                // Handle the NFC reader of the S370
            }
            DeviceType.kModelScannerS370 -> {
                // Handle the Barcode scanner of the S370
            }
        }
    }
}
```

## Swift

```swift
func didNotifyArrivalForDevice(_ device: CaptureHelperDevice, withResult result: SKTResult) {
  print("didNotifyArrivalForDevice: \(String(describing: device.deviceInfo.name))")
  if device.deviceInfo.deviceType == .NFCS370 {
    // handle the NFC reader of the S370
  } else if device.deviceInfo.deviceType == .scannerS370 {
    // handle the Barcode scanner of the S370
  }
}
```

## C#

```csharp
capture.DeviceArrival += Capture_DeviceArrival;

List<CaptureHelperDevice> connectedDevices = new List<CaptureHelperDevice>();

private void Capture_DeviceArrival(object sender, CaptureHelper.DeviceArgs e)
{
    CaptureHelperDevice device = e.CaptureDevice;
    int deviceType = device.GetDeviceInfo().Type;
    
    connectedDevices.Add(e.CaptureDevice);

    if (deviceType == DeviceTypes.kNFCS370)
    {
        // Handle the NFC reader of the S370
    }
    else if (deviceType == DeviceTypes.kScannerS370)
    {
        // Handle the Barcode scanner of the S370
    }
}
```

## Dart

```dart
onDeviceArrival: (CaptureHelperDevice device) {
  print('didNotifyArrivalForDevice: ${device.deviceInfo.name}');

  if (device.type == CaptureDeviceType.nFCS370) {
    // Handle the NFC reader of the S370
  } else if (device.type == CaptureDeviceType.scannerS370) {
    // Handle the Barcode scanner of the S370
  }
},
```

## JavaScript

```javascript
onDeviceArrival: (device) => {
    console.log(`Device arrival: ${device.name}`);

    if (device.type === CaptureDeviceType.NFCS370) {
        // Handle the NFC reader of the S370
    } else if (device.type === CaptureDeviceType.ScannerS370) {
        // Handle the Barcode scanner of the S370
    }
}
```

You can also check if a device is barcode reader or a NFC reader when you get the **device arrival event**:

## Java

```java
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onCaptureDeviceStateChange(DeviceStateEvent event) {
    DeviceClient device = event.getDevice();
    DeviceState state = event.getState();

    if (state.intValue() == DeviceState.READY) {
        if (DeviceType.isBarcodeScanner(device.getDeviceType())) {
            // Handle a barcode scanner (S370, S320, S740...)
        } else if (DeviceType.isNfcScanner(device.getDeviceType())) {
            // Handle an NFC reader (S370, S550...)
        }
    }
}
```

## Kotlin

```kotlin
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onCaptureDeviceStateChange(event: DeviceStateEvent) {
    val device: DeviceClient = event.device
    val state = event.state

    if (state.intValue() == DeviceState.READY) {
        if (DeviceType.isBarcodeScanner(device.deviceType)) {
            // Handle a barcode scanner (S370, S320, S740...)
        } else if (DeviceType.isNfcScanner(device.deviceType)) {
            // Handle an NFC reader (S370, S550...)
        }
    }
}
```

## Swift

```swift
func didNotifyArrivalForDevice(_ device: CaptureHelperDevice, withResult result: SKTResult) {
  print("didNotifyArrivalForDevice: \(String(describing: device.deviceInfo.name))")
  if device.isNFCReader {
    // handle the NFC reader of the S370 or another NFC reader like a S550
  } else if device.isBarcodeReader {
    // handle the Barcode scanner of the S370 or another barcode scanner like a S320 or S740
  }
}
```

## C#

```csharp
private void Capture_DeviceArrival(object sender, CaptureHelper.DeviceArgs e)
{
    CaptureHelperDevice device = e.CaptureDevice;

    connectedDevices.Add(e.CaptureDevice);

    if (device.IsNFCReader())
    {
        // Handle an NFC reader (S370, S550...)
    }
    else if (device.IsBarcodeReader())
    {
        // Handle a barcode scanner (S370, S320, S740...)
    }
}
```

## Dart

```dart
// Coming soon
```

## JavaScript

```javascript
// Coming soon
```