SocketCam

The C# CaptureSDK has support for SocketCam C820 and C860 on both Android and iOS. C820 is now available on Windows (Xamarin-UAP)

SocketCam is using the internal camera(s) of your device. It will display the video feed and allow you to scan barcodes.

The application receives the decoded data with the same APIs that are used for physical readers and they can also be used to manage some of the SocketCam properties the same way you would for a physical reader. To unable SocketCam, extra steps are required and listed below.

Setup

Windows (Xamarin/Uap)

On the platform-specific level and after opening an instance of the CaptureHelper, create an instance of CaptureExtension by providing your App context, the Capture Handle and your credentials. Then start it with Start() method:

It can be achieved by using an instance of CaptureHelper and then platform specific code:

// Shared or platform-specific code
CaptureHelper capture = new CaptureHelper();
await capture.OpenAsync();

// Platform-specific
var appContext = Window.Current;
CaptureExtension captureExtension = new CaptureExtension(appContext, capture.GetHandle(), appId, developerId, appKey);
captureExtension.Start();

You can then choose between displaying the Default View or the Custom View.

Default View: The Default View will display the camera video feed View in fullscreen. No other action is needed. The View will close upon scanning a barcode or pressing the close button.

Custom View: Then Custom View will provide a UI element (UserControl) that you can resize and position anywhere. However, to ensure proper display, the minimum size of the element should be 250 x 250 ePX. For handling the closing of the view when the close button (‘X’ in the UI) is pressed, please refer to the Triggering SocketCam section.

To enable the Custom View, subscribe to the CaptureExtension’s SocketCamView event and retrieve the UserControl object as follow:

private async void YourMethod()
{
    CaptureExtension captureExtension = new CaptureExtension()
    captureExtension.SocketCamView += Extension_SocketCamViewEvent;

    captureExtension.Start();
}

private void Extension_SocketCamViewEvent(object sender, SocketCamViewEventArgs e)
{
    var userControl = (UserControl)e.SocketCamView;
}

You can also subscribe to an Error event for potential errors while operating the CaptureExtension. See below:

captureExtension.Error += CaptureExtension_Error;

private void CaptureExtension_Error(object sender, CaptureExtensionErrorEventArgs e)
{
    // Your code here
}

To allow Camera scanning with SocketCam you should add the following Capabilities, webcam and pointOfService, in Package.appxManifest.:

<Capabilities>
    ...
        <DeviceCapability Name="webcam"/>
        <DeviceCapability Name="pointOfService"/>
    <DeviceCapability Name="microphone"/>
    ...
</Capabilities>

Note

Subscribing to the SocketCamView event will disable the Default View.

Note

Under Xamarin you can use dependency injection. The platform-specific code will be at the same level as the YourAppName.Windows.csproj project file.

Android

On the platform-specific level and after opening an instance of the CaptureHelper, create an instance of CaptureExtension by providing your App context and the Capture Handle. Then Start it with Start() method:

It can be achieved by using an instance of CaptureHelper and then platform specific code:

// Shared or platform-specific code
CaptureHelper capture = new CaptureHelper();
await capture.OpenAsync();

// Platform-specific
var appContext = Android.App.Application.Context;
CaptureExtension captureExtension = new CaptureExtension(appContext, capture.GetHandle());
captureExtension.Start();

You can also subscribe to an Error event for potential errors while operating the CaptureExtension. See below:

captureExtension.Error += CaptureExtension_Error;

private void CaptureExtension_Error(object sender, CaptureExtensionErrorEventArgs e)
{
    // Your code here
}

Note

Under Xamarin you can use dependency injection. The platform-specific code will be at the same level as the YourAppName.Android.csproj project file.

Under Maui, you can use conditional compilation at shared code level:

#if __ANDROID__
// Platform specific code here
#endif

iOS

Under Xamarin, all the code to open the Capture Helper, register for events and manipulate properties should be under the Xamarin.iOS app.

For SocketCam C860 which is an enhanced version of SocketCam C820, you also need to add the following key to your Info.plist: LSApplicationQueriesSchemes (Queried URL Schemes) with a new item: sktcompanion (in lower case).:

<key>LSApplicationQueriesSchemes</key>
<array>
<string>sktcompanion</string>
</array>

Note

The Xamarin SampleApp uses Dependency Services to link the platform specific code.

Enabling SocketCam

In order to enable SocketCam, you should set the SocketCam status property to Enable:

CaptureHelper capture = new CaptureHelper();
await capture.OpenAsync();

// (Windows, Android) Start CaptureExtension here

capture.SetSocketCamStatusAsync(CaptureHelper.SocketCamStatus.Enable);

At this point you will receive the device arrival.

Triggering SocketCam

Since SocketCam is not an independent device, a scan trigger button should be added:

private void Button_TriggerScan(object sender, EventArgs e)
{
    selectedDevice.SetTriggerStartAsync();
}

Windows (Xamarin/Uap)

Default View: Triggering the scan will open SocketCam’s view in full screen and close upon scanning or when the close button (‘X’ in the UI) is pressed.

Custom View: Triggering the scan will provide a UserControl object vie the CaptureExtension’s SocketCam event. On pressing the close button, the DecodedData event from the CaptureHelper instance will be triggered with an SktErrors.ESKT_CANCEL error.

Here is an example on how to catch the error:

private void YourDecodedDataEventFunction(object sender, CaptureHelper.DecodedDataArgs e)
{
    if (e.Result == SktErrors.ESKT_CANCEL)
    {
        // SocketCam closed with UI element 'X'
    }

    if (SktErrors.SKTSUCCESS(e.Result))
    {
        // Data scanned and recieved
    }
}

Android

Triggering the scan will open SocketCam’s view in full screen.

iOS

Triggering the scan will return SocketCam’s UIViewController. You can then use the UIViewController or its UIView to display SocketCam as you wish. You also have to control the dismissal of the view controller. Note that the minimal size of the view to ensure a correct representation of all SocketCam’s UI elements is of 250px x 250px. Below are two examples on how to display SocketCam in full screen and as a subview.

Full screen display with view controller dismissal. In this example, the UI element (UIViewController) is retrieved from the SetTriggerStartAsync() method and then displayed. Then, upon scanning data or closing SocketCam (see note below), the view controller is dismissed:

// Save ViewController for dismiss purpose
private UIViewController socketCamViewController;

public YourFunction()
{
    device?.SetTriggerStartAsync().ContinueWith(result =>
    {
        var resultDictionary = (NSDictionary)result.Result.ResultObject;
        var resultType = (NSString)resultDictionary[NSObject.FromObject("SKTObjectType")];

        if (resultType == "SKTSocketCamViewControllerType")
        {
            socketCamViewController = (UIViewController)resultDictionary[NSObject.FromObject("SKTSocketCamViewController")];

            if (socketCamViewController != null)
            {
                MainThread.BeginInvokeOnMainThread(() =>
                {
                    var currentViewController = Platform.GetCurrentUIViewController();
                    currentViewController.PresentViewController(socketCamViewController, true, null);
                });
            }
        }
    });
}

private void YourDecodedDataEventFunction(object sender, CaptureHelper.DecodedDataArgs e)
{
    MainThread.BeginInvokeOnMainThread(() =>
    {
        if (socketCamViewController != null)
        {
            socketCamViewController.DismissViewController(true, null);
        }
    });
}

Subview display with subview dismissal. In this example, the UIView of the UIViewController is used as a subview and resized to the minimal dimensions and placed in the top left corner. Then, upon scanning data or closing SocketCam (see note below), the view controller is dismissed:

// Save ViewController for dismiss purpose
private UIViewController socketCamViewController;

// SocketCam view: position and dimensions (min = 250 x 250)
private int socketCamXPos = 0;
private int socketCamYPos = 0;
private int socketCamWidth = 250;
private int socketCamHeight = 250;

public YourFunction()
{
    device?.SetTriggerStartAsync().ContinueWith(result =>
    {
        // To use SocketCam on iOS get the returned object and use it as a View Controller
        var resultDictionary = (NSDictionary)result.Result.ResultObject;
        var resultType = (NSString)resultDictionary[NSObject.FromObject("SKTObjectType")];

        if (resultType == "SKTSocketCamViewControllerType")
        {
            socketCamViewController = (UIViewController)resultDictionary[NSObject.FromObject("SKTSocketCamViewController")];

            if (socketCamViewController != null)
            {
                MainThread.BeginInvokeOnMainThread(() =>
                {
                    var currentViewController = Platform.GetCurrentUIViewController();
                    socketCamViewController.View.Frame = new CoreGraphics.CGRect(socketCamXPos, socketCamYPos, socketCamWidth, socketCamHeight);
                    currentViewController.View.AddSubview(socketCamViewController.View);
                });
            }
        }
    });
}

private void YourDecodedDataEventFunction(object sender, CaptureHelper.DecodedDataArgs e)
{
    MainThread.BeginInvokeOnMainThread(() =>
    {
        if (socketCamViewController != null)
        {
            socketCamViewController.View.RemoveFromSuperview();
        }
    });
}

Note

Scanning data or closing SocketCam (UI element X, top right corner in the view), will trigger the DecodedData event. The event carries a result that can be used to determine if data has been scanned or if SocketCam has been closed:

private void YourDecodedDataEventFunction(object sender, CaptureHelper.DecodedDataArgs e)
{
    if (e.Result == SktErrors.ESKT_CANCEL)
    {
        // SocketCam closed with UI element 'X'
    }

    if (SktErrors.SKTSUCCESS(e.Result))
    {
        // Data scanned and recieved
    }
}

Upgrading to SocketCam C860 (Pro) (available on Android and iOS)

SocketCam C860 (Pro) is an enhanced and paid version of SocketCam C820. Users will have the option to upgrade to SocketCam Pro from the SocketCam view. There are no additional code changes required to support this.

If you choose to upgrade from SocketCam C820 to SocketCam C860, you will be redirected to the Socket Mobile Companion app to complete the upgrade process.

Android

Now, it is possible that you still see the C820. In that case there are two possibilities to see the C860.

  1. Restart the application and the new C860 will appear.

  2. To directly show the C860 after purchasing the license you will need to Close and re-Open your instance of the CaptureHelper. The solution is the same applied for the Deep Sleep/Idle/Doze Mode specific case with one difference (see Delay below).

You can use the lifecycle of the application OnResume() triggering CloseAsync() and OpenAsync() methods from a Capture Helper instance CaptureHelper capture = new CaptureHelper(). A delay should be added before closing the instance. It is necessary for the upgrade to be applied.

Here is an example with the Delay, in App.xaml.cs use OnResume():

MainPage rootPage;

public App()
{
    InitializeComponent();

    rootPage = new MainPage();
    MainPage = rootPage;
}

protected override void OnResume()
{
    AddDelay();
}

private async Task AddDelay()
{
    await Task.Delay(1000);
    rootPage.ReEnableConnection();
}

Note

A minimum Delay of 1 second is recommended. A bit less could work but it might break the update. A broken state would show the C860 but data cannot be retrieved. In the case, re-install the application. (The license will still be valid)

The example above in App.xaml.cs is valid for Xamarin but an extra has to be applied to Maui:

MainPage rootPage;

public App()
{
        InitializeComponent();

    MainPage = new AppShell();
    rootPage = new MainPage(true);
}

protected override void OnResume()
{
    rootPage.ReEnableConnection();
}

Note

In the provided Maui Sample App, MainPage(true) is empty. It is using static variables populated by the MainPage(). In this case, the credentials (appId, developperID, appKey), the instance of Capture Helper and the isFirstLaunch Boolean should be static to be re-used.

Note

OnResume() will be triggered when the application switches from being in the backgroud to being in the foreground. This action is also valid coming back from deep sleep mode.

Then add the following method:

public void ReEnableConnection()
{
    // List will be repopulated on OpenAsync()
    _deviceList.Clear();

    capture.CloseAsync().ContinueWith(result =>
    {
        if (SktErrors.SKTSUCCESS(result.Result))
        {
            isFirstLaunch = false;

            Open();
        }
    });
}

Note

_deviceList is the list of devices saved using the Device Arrival event. In the example provided, it is used to select and trigger a scan via a button. Make sure that _deviceList.Clear() is called before Open() and outside of CloseAsync().

The Open() method refers to the following:

public void Open()
{
    capture.OpenAsync(appId, developerId, appKey)
        .ContinueWith(result =>
        {
            System.Diagnostics.Debug.Print("Open Capture returns {0}", result.Result);
            if (SktErrors.SKTSUCCESS(result.Result))
            {
                if (isFirstLaunch)
                {
                    capture.DeviceArrival += Capture_DeviceArrival;
                    capture.DeviceRemoval += Capture_DeviceRemoval; ;
                    capture.DecodedData += Capture_DecodedData;

                    // (Android-iOS) Check if SocketCam is enabled to set the Switch
                    GetSocketCamStatusInit();
                }
            }
        });
}

Note

If you are re-using the instance of Capture Helper, already registered events should not be re-registered upon using ReEnableConnection(). This is prevented by using the Boolean isFirstLaunch.

Note

If you re-install your application, then the C820 will appear again. To re-enable the C860, trigger a scan, open the camera, tap on the Pro button and select Upgrade to SocketCam Pro. This time it will only check the validity of the license and the C860 will appear again.