Basics

Getting the Decoded Data

Using Capture Helper to retrieve the decoded data from a scanner is as simple as deriving from CaptureHelperDeviceDecodedDataDelegate protocol and implementing the didReceiveDecodedData delegate.

Note

If the UI should be updated with the decoded data received, the updating code should be in the main dispatch queue using the DipatchQueue.main.async or simply by settings the Capture Helper property dispatchQueue to DispatchQueue.main like this: CaptureHelper.sharedInstance.dispatchQueue = DispatchQueue.main

Here is an example of such implementation for handling the decoded data with Capture Helper:

  • Swift
  • ObjectiveC
import UIKit
import SKTCapture

class MasterViewController:
    UIViewController,
    CaptureHelperDeviceDecodedDataDelegate {

    // Capture Helper shareInstance allows to share
    // the same instance of Capture Helper with the
    // entire application. That static property can
    // be used in any views but it is recommended
    // to open only once Capture Helper (in the main
    // view controller) and pushDelegate, popDelegate
    // each time a new view requiring scanning capability
    // is loaded or unloaded respectively.
    var captureHelper = CaptureHelper.sharedInstance

    @IBOutlet weak var decodedData: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // CaptureSDK requires the app to be registered on
        // Socket Mobile developer portal
        let appInfo = SKTAppInfo()
        appInfo.appKey = "<YOUR APP KEY HERE>"
        appInfo.appID = "<YOUR APP BUNDLE ID HERE>"
        appInfo.developerID = "<YOUR DEVELOPER ID HERE>"

        // there is a stack of delegates the last push is the
        // delegate active, when a new view requiring notifications from the
        // scanner, then push its delegate and pop its delegate when the
        // view is done
        captureHelper.pushDelegate(self)

        // to make all the delegates able to update the UI without the app
        // having to dispatch the UI update code, set the dispatchQueue
        // property to the DispatchQueue.main
        // Do the the same with the property dispatchQueue if the UI needs to
        // be updated in any of the completion handlers
        captureHelper.dispatchQueue = DispatchQueue.main

        // open Capture Helper only once in the application by passing the
        // application information (developer ID, application bundle ID and the
        // AppKey coming from the application registration on Socket Mobile
        // developer portal
        captureHelper.openWithAppInfo(appInfo, withCompletionHandler: { (_ result: SKTResult) in
            print("Result of Capture initialization: \(result.rawValue)")
        })
    }
#import "ViewController.h"
#import <CaptureSDK/CaptureSDK.h>

@interface ViewController () <CaptureHelperDelegate>
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@property (weak, nonatomic) IBOutlet UITextView *decodedDataTextView;
@property (weak, nonatomic) IBOutlet UIButton *clearButton;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _decodedDataTextView.text = @"";
    _decodedDataTextView.layer.borderWidth = 2;
    _decodedDataTextView.layer.cornerRadius = 10;

    _clearButton.layer.cornerRadius = 10;
    _clearButton.layer.borderWidth = 2;
    _clearButton.backgroundColor = UIColor.whiteColor;
    _clearButton.layer.borderColor = UIColor.blueColor.CGColor;

    [CaptureHelper.sharedInstance pushDelegate:self];
    [CaptureHelper.sharedInstance openWithCompletionHandler:^(SKTResult result) {
        NSLog(@"Opening Capture Helper returned: %ld", (long)result);
    }];
}

@end

And the decoded data handler might look like this:

  • Swift
  • ObjectiveC
// MARK: - CaptureHelperDeviceDecodedDataDelegate

// This delegate is called each time a decoded data is read from the scanner
// It has a result field that should be checked before using the decoded
// data.
// It would be set to SKTCaptureErrors.E_CANCEL if the user taps on the
// cancel button in the SocketCam View Finder
func didReceiveDecodedData(_ decodedData: SKTCaptureDecodedData?, fromDevice device: CaptureHelperDevice, withResult result: SKTResult) {

    if result == SKTCaptureErrors.E_NOERROR {
        let str = decodedData?.stringFromDecodedData()!
        print("Decoded Data \(String(describing: str))")
        decodedData.text = str
    }
}
/**
* called when decoded data are received from a device
*
* @param decodedData contains the decoded data
* @param device identifies the device from which the decoded data comes from
* @param result contains an error if something wrong happen while getting the decoded data
* or if the SocketCam trigger operation has been cancelled
*/
-(void)didReceiveDecodedData:(SKTCaptureDecodedData *)decodedData fromDevice:(CaptureHelperDevice *)device withResult:(SKTResult)result {
    NSLog(@"receive decoded data: %@", [decodedData stringFromDecodedData]);
    dispatch_async(dispatch_get_main_queue(), ^{
        self.decodedDataTextView.text = [self.decodedDataTextView.text stringByAppendingString: [decodedData stringFromDecodedData]];
        self.decodedDataTextView.text = [self.decodedDataTextView.text stringByAppendingString: @"\n"];
    });

}

Note

Here the UI can be directly updated because in the Capture Helper initialization the UI Context is passed in the dispatchQueue property of Capture Helper: capture.dispatchQueue = DispatchQueue.main

Device Arrival

The Device arrival is fired when a scanner is connected to the host.

This event can be useful for several things such as:

  • confirming to the user the scanner is present and ready

  • switching to a view that is ready to receive the decoded data

  • checking the scanner configuration before setting its configuration

Here is an example of a Device Arrival handler:

  • Swift
  • ObjectiveC
func didNotifyArrivalForDevice(_ device: CaptureHelperDevice, withResult result:SKTResult) {
    print("didNotifyArrivalForDevice")
    scannerStatus.text = device.deviceInfo.name!
}
-(void)didNotifyArrivalForDevice:(CaptureHelperDevice *)device withResult:(SKTResult)result {
    NSLog(@"Receive device arrival for %@", device.friendlyName);
    dispatch_async(dispatch_get_main_queue(), ^{
        _statusLabel.text = device.friendlyName;
    });
}

Note

Here the UI can be directly updated because in the Capture Helper initialization the UI Context is passed in the dispatchQueue property of Capture Helper: capture.dispatchQueue = DispatchQueue.main

This assumes the View class has been derived from CaptureHelperDevicePresenceDelegate:

  • Swift
  • ObjectiveC
import UIKit
import SKTCapture

class MasterViewController:
    UIViewController,
    CaptureHelperDeviceDecodedDataDelegate {

  ...

}
#import "ViewController.h"
#import <CaptureSDK/CaptureSDK.h>

@interface ViewController () <CaptureHelperDelegate>
@property (nonatomic) IBOutlet UILabel *statusLabel;

@end

Device Arrival for Combo devices i.e. S370

For a combo device like the S370 which has 2 devices, there will be two didNotifyArrivalForDevice notifications: one for the NFC reader/writer and one for the Barcode scanner.

The following code shows how you can distinghuish and handle them with the device type:

  • 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
  }
}

Get the Error

It is a good idea to be notified when an unexpected error occurs. One possible scenario where this could happen is when the user scans too many barcodes before the application has time to consume them.

Here is an example of the error event handler to display an error message in a status label in the application UI:

  • Swift
  • ObjectiveC
func didReceiveError(_ error: SKTResult) {
    print("Receive a Capture error: \(error.rawValue)")
    errorLabel.text = "The scanner is reporting an error: \(error.rawValue)"
}
/**
* called when a error needs to be reported to the application
*
* @param error contains the error code
* @param message contains an optional message, can be null
*/
-(void)didReceiveError:(SKTResult)error withMessage:(NSString *)message {
    NSLog(@"Receive error %d from Capture: %@", error, message);
}

This delegate is defined by the CaptureHelperErrorDelegate protocol from which the class should derive.

Note

Here the UI can be directly updated because in the Capture Helper initialization the UI Context is passed in the dispatchQueue property of Capture Helper: capture.dispatchQueue = DispatchQueue.main

Getting a Device Property such as Battery Level

Capture Helper helps to retrieve information about a particular scanner or to configure a scanner through a Capture Helper Device object that is received in the Device Arrival event and in the DecodedData event.

This Capture Helper Device object is also received in argument of the Device Removal event but since the device is disconnected from the host, only limited operations can be done with this Capture Helper Device at this time.

Here is an example of such a command:

  • Swift
  • ObjectiveC
// ask for the Battery Level
device.getBatteryLevelWithCompletionHandler({ (result, batteryLevel) in
    self.displayBatteryLevel(batteryLevel, fromDevice: device, withResult: result)
})

...

// MARK: - Utility functions
func displayBatteryLevel(_ level: UInt?, fromDevice device: CaptureHelperDevice, withResult result: SKTResult) {
    if result != SKTCaptureErrors.E_NOERROR {
        print("error while getting the device battery level: \(result.rawValue)")
    }
    else{
        deviceInfo.text = "the device \((device.deviceInfo.name)! as String) has a battery level: \(String(describing: level))%"
    }
}
// ask for the device Battery Level
[device getBatteryLevelWithCompletionHandler:^(SKTResult result, NSInteger levelInPercentage) {
    [self displayBatteryLevel: levelInPercentage];
}];

...

#pragma mark - Utility methods

-(void)displayBatteryLevel:(NSInteger)batteryLevelInPercentage {
    dispatch_async(dispatch_get_main_queue(), ^{
        _statusLabel.text = [NSString stringWithFormat:@"Battery: %ld%%", (long)batteryLevelInPercentage];
    });
}

With device being defined as a CaptureHelperDevice object.

Please refer to the other topics for more information about configuring the device or retrieving.