Perform the following steps to install the iOS cmbSDK:
Download the latest XCode for iOS Development.
Download the Cognex Mobile Barcode SDK for iOS.
Perform the following steps to set up your application to use the iOS cmbSDK:
Open XCode and start a new project.
* SystemConfiguration.framework * AVFoundation.framework
* CoreGraphics.framework
* CoreMedia.framework
* CoreVideo.framework
* MediaPlayer.framework * Security.framework
* AudioToolbox.framework * libDataManSDK.a
3. Go to your project's Info.plist file and add the Privacy - Camera Usage Description or NSCameraUsageDescription. This is required by iOS and is used to display a message explaining the usage of the user's device camera by your application.
If you plan to use the cmbSDK to do mobile scanning with a smartphone or tablet (with no MX mobile terminal), then the SDK requires the installation of a license key.
Without a license key, the SDK will still operate, although scanned results will be obfuscated (the SDK will randomly replace characters in the scan result with an asterisk character).
Contact your Cognex Sales Representative for information on how to obtain a license key including trial licenses which can be used for 30 days to evaluate the SDK.
After obtaining your license key, add it as a String in your application's Info.plist file, under the key MX_MOBILE_LICENSE.
The cmbSDK has been designed to provide a high-level, abstract interface for supported scanning devices. This includes not only the MX series of mobile terminals, but also for applications that intend to use the mobile device camera as the imaging device. The intricacies of communicating with and managing these devices is encapsulated within the SDK itself: leaving the application to just connect to the device of choice, then using it.
The primary interface between your application and a supported barcode scanning device is the CMBReaderDevice class. This class represents the abstraction layer to the device itself, handling all communication as well as any necessary hardware management (e.g., for smartphone scanning).
Perform the following steps to use the cmbSDK:
Initialize a Reader Device for the type of device you want to use (MX reader or camera reader).
Connect the Reader Device.
Configure the reader (if necessary).
Start scanning.
Initialization, connection, and configuration generally need to be performed only once in your application, except for the following cases:
The cmbSDK provides two different reader class initializers: one for scanning using an MX mobile terminal (like the MX- 1000 or MX-1502) and another for scanning using the built-in camera of the mobile device (iPhones, iPads, etc).
Initializing the Reader Device for use with an MX mobile terminal like the MX-1000 or MX-1502 is easy: simply create the reader device using the MX device method (it requires no parameters), and set the appropriate delegate (normally self):
CMBReaderDevice *readerDevice = [CMBReaderDevice readerOfMXDevice];
[readerDevice setDelegate:self];
The availability of the MX mobile terminal can change when the device turns ON or OFF, or if the lightning cable gets connected or disconnected. You can handle those changes using the following CMBReaderDeviceDelegate method.
- (void)availabilityDidChangeOfReader:(CMBReaderDevice *)reader;
Barcode scanning with the built-in camera of the mobile device can be more complex than with an MX mobile terminal. The cmbSDK supports several configurations to provide the maximum flexibility. This includes support of optional, external aimers/illumination, as well as the ability to customize the appearance of the live-stream preview.
To scan barcodes using the built-in camera of the mobile device, initialize the CMBReaderDevice object using the readerOfDeviceCameraWithCameraMode static method. The camera reader has several options when initialized. The following parameters are required:
* CDMCameraMode
* CDMPreviewOption
* UIView
The CameraMode parameter is of the type CDMCameraMode (defined in CDMDataManSystem.h), and it accepts one of the following values:
All of the above modes provide the following default settings for the reader:
Based on the selected mode, the following additional options and behaviors are set:
The previewOptions parameter (of type CDMPreviewOption, defined in CDMDataManSystem.h) is used to change the reader’s default values or override defaults derived from the selected CameraMode. Multiple options can be specified by OR-ing them when passing the parameter. The available options are the following:
The last parameter of type UIView is optional and is used as a container for the camera preview. If the parameter is left nil, a full screen preview will be used.
Examples:
Create a reader with no aimer and a full screen live-stream preview:
CMBReaderDevice *readerDevice = [CMBReaderDevice readerOfDeviceCameraWithCameraMode:kCDMCameraModeNoAimer previewOptions:kCDMPreviewOptionDefaults previewView:nil];
readerDevice.delegate = self;
Create a reader with no aimer, no zoom button, and using a simulated trigger:
CMBReaderDevice *readerDevice = [CMBReaderDevice readerOfDeviceCameraWithCameraMode:kCDMCameraModeNoAimer previewOptions:(kCDMPreviewOptionNoZoomBtn | kCDMPreviewOptionHwTrigger) previewView:nil];
readerDevice.delegate = self;
After initializing the Reader Device and setting a delegate to handle responses from the reader, you are ready to connect using connectWithCompletion:
// Make sure the device is turned ON and ready
if (readerDevice.availability == CMBReaderAvailibilityAvailable) {
// create the connection between the readerDevice object and device [readerDevice connectWithCompletion:^(NSError *error) {
if (readerDevice.connectionState == CMBConnectionStateConnected) { // Connected successfully
} else {
if (error) {
// handle connection error }
} }];
}
If everything was done correctly, connectionStateDidChangeOfReader in the delegate will be called, where you can check the connection status in your Reader Device's connectionState parameter. It should be CMBConnectionStateConnected, which means that you have successfully made the connection to the Reader Device, and can begin using the Cognex Mobile Barcode SDK.
After connecting to the scanning device, you may want (or need) to change some of its settings. The cmbSDK provides a set of high-level, device independent APIs for setting and retrieving the current configuration of the device.
Like in the case of initializing the Reader Device, there are some differences between using an MX reader and the camera reader for scanning. These differences are detailed in the following sections.
The MX family of mobile terminals provides sophisticated device configuration and management, including saved configurations on the device itself. In general, these devices come from Cognex preconfigured for an exceptional out-of- the-box experience with most symbologies and features ready to use.
When custom reconfiguration is desired, this is typically done using either the DataMan Setup Tool, or the DataMan Quick Setup as these tools can be used to distribute saved configurations easily to multiple devices, thereby greatly simplifying configuration management.
However, it is still possible (and sometimes desirable) for the mobile application itself to configure the MX device:
Much like an MX mobile terminal, the cmbSDK employs a default set of options for barcode reading with the built-in camera of the mobile device, providing a good out-of-box experience. However, there are two important differences to keep in mind:
Individual symbologies can be enabled using the following method of the Reader Device object:
-(void) setSymbology:(CMBSymbology)symbology
enabled:(bool)enabled
completion:(void (^)(NSError *error))completionBlock;
All symbologies used for the symbology parameter in this method can be found in CMBReaderDevice.h.
Examples
/* Enable QR scanning */
[readerDevice setSymbology:CMBSymbologyQR
enabled:YES completion:^(NSError *error) { if (!error) {
// Success }else{
/* Unsuccessful
probably the symbology is unsupported by
the current device, or there is a problem with the connection between
the readerDevice and MX device
*/
} }];
The same method can also be used to turn symbologies off:
/* Disable Code 25 scanning */ [readerDevice setSymbology:CMBSymbologyC25
enabled:NO completion:^(NSError *error) { if (!error) {
// Success }else{
// Unsuccessful }
}];
If your reader device is equipped with illumination lights (e.g. LEDs), you can control whether they are ON or OFF when scanning starts using the following method of your Reader Device object:
-(void) setLightsON:(bool)on
completion:(void (^)(NSError *error))completionBlock;
Keep in mind that not all devices and device modes supported by the cmbSDK allow for illumination control. For example, if using the built-in camera in passive aimer mode, illumination is not available since the LED is being used for aiming.
The cmbSDK includes a method for resetting the device to its default settings. In the case of an MX mobile terminal, this is the configuration saved by default (not the factory defaults), while in the case of the built-in camera, these are the defaults identified in Appendix B, where no symbologies will be enabled. This method is the following:
- (void) resetConfigWithCompletion:(void (^)(NSError *error))completionBlock;
Every Cognex scanning device implements DataMan Control Commands (DMCC), a method for configuring and controlling the device. Virtually every feature of the device can be controlled using this text based language. The API provides a method for sending DMCC commands to the device. Commands exist both for setting and querying configuration properties.
Appendix A includes the complete DMCC reference for use with the camera reader. DMCC commands for other
supported devices (e.g. the MX-1000) are included with the documentation of that particular device.
Appendix B provides the default values for the camera reader’s configuration settings as related to the corresponding
DMCC setting.
The following examples show different DMCC commands being sent to the device for more advanced configuration. Change the scan direction to omnidirectional:
[self.dataManSystem sendCommand:@"DECODER.1D-SYMBOLORIENTATION 0" withCallback:^(CDMResponse *response){
if (response.status == DMCC_STATUS_NO_ERROR) {...}
else
{...} }];
Change the scanning timeout of the live-stream preview to 10 seconds:
[self.dataManSystem sendCommand:@"DECODER.MAX-SCAN-TIMEOUT 10" withCallback:^(CDMResponse *response){
if (response.status == DMCC_STATUS_NO_ERROR) {...}
else
{...} }];
Get the type of the connected device:
[self.dataManSystem sendCommand:@"GET DEVICE.TYPE" withCallback:^(CDMResponse *response){
if (response.status == DMCC_STATUS_NO_ERROR) {NSString *deviceType = response.payload; }
else
{...} }];
With a properly configured reader, you are now ready to scan barcodes. This is simply accomplished by calling the startScanning() method from your Reader Device object. What happens next is based on the type of Reader Device and how it has been configured, but in general:
Scanning stops under one of the following conditions:
When a barcode is decoded successfully (the first case), you will receive a CMBReadResults array in your Reader Device's delegate using the following CMBReaderDeviceDelegate method:
- (void)didReceiveReadResultFromReader:(CMBReaderDevice *)reader results:(CMBReadResults *)readResults;
The following is an example to simply display a ReadResult after scanning a barcode:
- (void)didReceiveReadResultFromReader:(CMBReaderDevice *)reader results:(CMBReadResults *)readResults
{
for (CMBReadResult *readResult in readResults.readResults) {
if (readResult.image) {
_ivPreview.image = readResult.image; }
if (readResult.readString) {
_lblCode.text = readResult.readString; }
}
}
In the example above, _ivPreview is an UIImageView used to display an image of the barcode that was scanned, and _ lblCode is a UILabel used to show the result from the barcode. You can also use the BOOL from readResult.goodRead to check whether the scan was successful or not.
When a barcode is successfully read, a CMBReadResult object is created and returned by the didReceiveReadResultFromReader:results: method. In case of having multiple barcodes successfully read on a single image/frame, multiple CMBReadResult objects are returned. This is why the CMBReadResults class has an array of CMBReadResult objects containing all results.
The CMBReadResult class has properties describing the result of a barcode read:
When a scanning ends with no successful read, a CMBReadResult is returned with the goodRead property set to false. This usually happens when scanning is canceled or timed out.
To enable the image and imageGraphics properties being filled in the CMBReadResult object, you have to set the corresponding imageResultEnabled and/or SVGResultEnabled properties of the CMBReaderDevice object.
To see an example on how the image and SVG graphics are used and displayed in parallel, refer to the sample applications provided in the SDK package.
To access the raw bytes from the scanned barcode, you can use the XML property. The bytes are stored as a Base64 String under the "full_string" tag. Here's an example how you can use a XML parser to extract the raw bytes from the XML property.
NSXMLParser *xmlParser = [NSXMLParser.alloc initWithData:result.XML];
xmlParser.delegate = self;
if ([xmlParser parse]) {
// the raw bytes will be stored in this variable
NSData *bytes = [NSData.alloc initWithBase64EncodedString:base64String options:0];
}
Parsing the XML and extracting the Base64 String is done using the NSXMLParser
#pragma NSXMLParserDelegate
NSString *currentElement;
NSString *base64String;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
currentElement = elementName;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([currentElement isEqualToString:@"full_string"]) {
base64String = string;
}
}
By default, the image and SVG results are disabled, which means that when scanning, the CMBReadResults will not contain any data in the corresponding properties.
To enable image results, set the imageResultEnabled property from the CMBReaderDevice class by using the following method:
[readerDevice setImageResultEnabled:YES];
To enable SVG results, set the imageResultEnabled property from the CMBReaderDevice class by using the following method:
[readerDevice setSVGResultEnabled:YES];
There may be cases when a device disconnects due to low battery condition or manual cable disconnection. These cases can be detected by the connectionStateDidChangeOfReader callback of the CMBReaderDeviceDelegate.
After you return to your application from inactive state, the reader device remains initialized, but not connected. This means there is no need for reinitializing the SDK, but you will need to re-connect.
Some iOS versions will send a "Availability" notification when resuming the application that the External Accessory is available. You can use this in the CMBReaderDeviceDelegate's method: (void)availabilityDidChangeOfReader:(CMBReaderDevice *)reader. In it, when the reader becomes available, you can connect to it.
For example:
- (void)availabilityDidChangeOfReader:(CMBReaderDevice *)reader
{
if (readerDevice.availability == CMBReaderAvailibilityAvailable) {
[readerDevice connectWithCompletion:^(NSError *error) {
if (error) {
// handle connection error
}
}];
}
}
Some iOS versions do not report availability change on resume, so you will have to handle this manually. For this, you will have to add an observer for "UIApplicationDidBecomeActiveNotification" and do some checks before connecting, so you don't connect while the reader is already in "connecting" or "connected" state. For example:
- (void)viewDidLoad {
// add observer for app resume
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appBecameActive)
name:UIApplicationDidBecomeActiveNotification object:nil];
}
// handle app resume
-(void) appBecameActive {
if (readerDevice != nil
&& readerDevice.availability == CMBReaderAvailibilityAvailable
&& readerDevice.connectionState != CMBConnectionStateConnecting && readerDevice.connectionState != CMBConnectionStateConnected)
{
[readerDevice connectWithCompletion:^(NSError *error) {
if (error) {
// handle connection error
}
}];
}
}