Cognex Mobile Barcode SDK for iOS

概述

Cognex Mobile Barcode SDK (cmbSDK) 是用于开发移动条码扫描应用程序的SDK。

SDK是付费的,但功能很强大。

Cognex Mobile Barcode SDK for iOS : https://cmbdn.cognex.com/download#Platforms

iOS技术文档地址:https://cmbdn.cognex.com/knowledge/-cognex-mobile-barcode-sdk-for-ios

SDK

  • CMBReaderDevice

这个类提供了,连接,扫码,扫码结果回调,断开连接等系列操作。

  • CMBReadResult

这个类是扫描结果的抽象类,将扫描结果打包成CMBReadResult,提供了扫描的内容readResult.readString 和 readResult.image,是否是有效的goodRead。

goodRead (BOOL):判断读取是否成功
readString (NSString): 解码后的条码字符串
图像(UIImage):解码器处理过的图像/帧
imageGraphics (NSData):条码的边界路径作为SVG数据
XML (NSData):解码器返回的原始 XML
符号(CMBSymbology):条码的符号类型。该枚举在CMBReaderDevice.h 中定义。

  • CMBReadResults

这个类有两个数组,readResults 和 subReadResults ,将一帧(或者更短时间)内的所有扫描结果CMBReadResult都“入队”到两个数组中。

读取扫描结果的时候,我们只需取第一个元素作为最终的扫描结果即可。

  • CDMDataManSystem

这个类提供了连接远程服务的API,通过用户名和密码连接远程,可以发送命令和接收命令。

  • CDMResponse

远程连接的回调类。

  • MWOverlay

以下两种模式的UI是不一样的,如果需要自定义UI的话,可以选择第一种模式,在previewView添加自定义试图。

// 这种模式适用于自己设置一个previewView,在规定的previewView范围内扫描

[MWOverlay setOverlayMode:OM_CMB];

// 这种模式在SDK的较低版本中是全屏进行扫描,在高一点的版本中(如2.6.1)如果设置previewView,则在previewView范围内扫描,不设置的话默认全屏扫描。低版本中设置previewView是无效的。

[MWOverlay setOverlayMode:OM_LEGACY];

还有一些设置边框颜色什么的属性,可以试试看。

  • CDMEADiscoverer

SDK使用

下载官方提供的SDK,文档以及Demo,例 cmbSDK_iOS_v2.6.1 -> samples -> SampleApp

Demo中已经引用好了SDK,官方给我的SDK支持 arm64和armv7的真机和x86_64的模拟器。

WScanViewController

#import "WScanViewController.h"
#import <cmbSDK/cmbSDK.h> // 引用SDK头文件

#define CognexRegistrationKey @"xxx" 
#define CognexRegistrAuth @"xxx"     

@interface WScanViewController ()<CMBReaderDeviceDelegate>

@property (nonatomic, strong) UIImageView *previewView; // 扫描预览试图

@property (nonatomic, strong) CMBReaderDevice *readerDevice; 

@property (nonatomic, weak) id<NSObject> applicationWillEnterForegroundObserver;
@property (nonatomic, weak) id<NSObject> applicationDidEnterBackgroundObserver;
@property (nonatomic, weak) id<NSObject> applicationWillResignActiveObserver;
@property (nonatomic, weak) id<NSObject> applicationDidBecomeActiveObserver;

@property (nonatomic, assign) BOOL canAccessCamera;

@end

@implementation WScanViewController

- (void)dealloc {
    
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // SDK 版本号
    NSLog(@"Version: %@",[CDMDataManSystem getVersion]);
    
    // 扫描预览试图
    self.previewView = [[UIImageView alloc] init];
    self.previewView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.previewView];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    
    self.previewView.frame = CGRectMake(CGRectGetWidth(self.view.frame)*0.5-160, CGRectGetHeight(self.view.frame)*0.5-240, 320, 480);
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    // 检测相机授权
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    self.canAccessCamera = (authStatus != AVAuthorizationStatusDenied && authStatus != AVAuthorizationStatusRestricted);
    if (!self.canAccessCamera) {
        NSLog(@"没有权限访问相机");
        [self showAlert];
        return;
    }
    // 初始化扫描类
    self.readerDevice = [self createReaderDevice];
    
    [self addNotifications];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self removeNotifications];
    
    if (self.readerDevice != nil &&
        self.readerDevice.connectionState == CMBConnectionStateConnected) {
        [self.readerDevice stopScanning];
    }
}

-(void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    
    if (self.readerDevice != nil &&
        self.readerDevice.connectionState == CMBConnectionStateConnected) {
        [self.readerDevice disconnect];
    }
}


- (void)addNotifications {
    
    void(^becomeActiveHandler)(NSNotification *) = ^(NSNotification *note){
        if (self.readerDevice.connectionState == CMBConnectionStateDisconnecting || self.readerDevice.connectionState == CMBConnectionStateDisconnected) {
            [self.readerDevice connectWithCompletion:^(NSError *error) {
                if (!error)
                    [self.readerDevice startScanning];
            }];
        }
    };
    void(^becomeInactiveHandler)(NSNotification *) = ^(NSNotification *note){
        if (self.readerDevice.connectionState == CMBConnectionStateConnecting || self.readerDevice.connectionState == CMBConnectionStateConnected) {
            UIImage *screenShot = [WcanViewController getImageViewWithView:self.previewView];
            [self.readerDevice stopScanning];
            [self.readerDevice disconnect];
            self.previewView.image = screenShot;
        }
    };
    
    self.applicationDidBecomeActiveObserver = [NSNotificationCenter.defaultCenter addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:NSOperationQueue.mainQueue usingBlock:becomeActiveHandler];
    self.applicationDidEnterBackgroundObserver = [NSNotificationCenter.defaultCenter addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:NSOperationQueue.mainQueue usingBlock:becomeInactiveHandler];
}

- (void)removeNotifications {
    [NSNotificationCenter.defaultCenter removeObserver:self.applicationDidBecomeActiveObserver];
    [NSNotificationCenter.defaultCenter removeObserver:self.applicationDidEnterBackgroundObserver];
}

- (CMBReaderDevice *)createReaderDevice {
    
    if (self.readerDevice != nil) {
        [self.readerDevice disconnect];
    }
    // 这种模式指定在设置的previewView之内扫描以及预览。当设置为OM_LEGACY时,previewView的设置无效,会全屏预览扫描。
    [MWOverlay setOverlayMode:OM_CMB];
    
    // previewOptions 可以用 OR 语法传参。
    /**
    
    kCDMPreviewOptionDefaults:接受由CameraMode设置的所有默认值。
    kCDMPreviewOptionNoZoomBtn:隐藏直播预览上的缩放按钮。
    kCDMPreviewOptionNoIllumBtn:隐藏直播预览上的照明按钮。
    kCDMPreviewOptionHwTrigger:启用模拟硬件触发器(音量控制)以开始扫描。按下后,扫描开始。
    kCDMPreviewOptionPaused:当调用 startScanning()方法而不开始解码(即寻找条形码)时显示实时预览。按屏幕上的扫描按钮开始解码。
    kCDMPreviewOptionAlwaysShow:选择主动或被动瞄准模式时强制显示实时预览(例如CameraMode == kCDMCameraModePassiveAimer)
    kCDMPreviewOptionPessimisticCaching:仅在CameraMode ==     kCDMCameraModeActiveAimer时使用,这将在应用程序从后台恢复时从ActiveAimer读取设置,以防瞄准器设置从另一个应用程序更改。
    kCDMPreviewOptionHighResolution:使用更高分辨率的设备摄像头来帮助扫描小条码,但解码时间较慢。该选项在支持它的设备上将分辨率设置为 1920x1080,在不支持的设备上设置为默认分辨率。默认分辨率为 1280x720。  

    kCDMPreviewOptionHighFrameRate:将相机设置为 60 FPS 而不是默认的 30 FPS,以提供更流畅的相机预览。
kCDMPreviewOptionKeepPreviewInPausedState:在读取或超时后保持预览处于暂停状态。

    */
    // 如果是扫描小条码的话,建议使用kCDMPreviewOptionHighResolution,会默认设置最大分辨率扫描。
    CMBReaderDevice *tmpDevice = [CMBReaderDevice readerOfDeviceCameraWithCameraMode:kCDMCameraModeNoAimer
                                                                      previewOptions:kCDMPreviewOptionDefaults
                                                                         previewView:self.previewView
                                                                     registrationKey:CognexRegistrationKey
                                                                          customData:CognexRegistrAuth];
    tmpDevice.delegate = self;
    if (tmpDevice.availability == CMBReaderAvailibilityAvailable && tmpDevice.connectionState == CMBConnectionStateDisconnected) {
        [tmpDevice connectWithCompletion:^(NSError *error) {
            if (error) {
                NSLog(@"%@", error.localizedDescription);
            }
            else {
                [tmpDevice startScanning];
            }
        }];
    }
    else {
        NSLog(@"不能打开摄像头扫描,请确保摄像头已允许访问");
    }
    
    return tmpDevice;
}

- (void)showAlert {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Permission denied" message:@"使用相机" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
    [alertController addAction:[UIAlertAction actionWithTitle:@"Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
            }];
        }
    }]];
    
    [self presentViewController:alertController animated:YES completion:nil];
}

+ (UIImage *)getImageViewWithView:(UIView *)view
{
    CGRect screenRect = [UIScreen mainScreen].bounds;
    UIGraphicsBeginImageContext(screenRect.size);
    UIGraphicsGetCurrentContext();
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}


#pragma mark - CMBReaderDeviceDelegate
- (void)connectionStateDidChangeOfReader:(CMBReaderDevice *)reader
{
    if (self.readerDevice.connectionState == CMBConnectionStateConnected) {
        
        // https://cmbdn.cognex.com/v2.6.x/knowledge/-cognex-mobile-barcode-sdk-for-ios/using-cmbsdk/enabling-symbologies
        // 通过 -(void) setSymbology:(CMBSymbology)symbology 
enabled:(bool)enabled
completion:(void (^)(NSError *error))completionBlock; 方法,启用符号系统
        // 此方法中用于符号系统参数的所有符号系统都可以在CMBReaderDevice.h 中找到。见枚举 CMBSymbology。
        // 以此来设置需要支持的扫码形式
        
        // Not find Codabar & Telepen
        [self.readerDevice setSymbology:CMBSymbologyDataMatrix enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyDataMatrix], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyQR enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyQR], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyMaxicode enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyMaxicode], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyAzteccode enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyAzteccode], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyDotcode enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyDotcode], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyUpcEan enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyUpcEan], %@", error.description);
            }
        }];
        
        [self.readerDevice setSymbology:CMBSymbologyC25 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyC25], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyC39 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyC39], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyC11 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyC11], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyC93 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyC93], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyC128 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyC128], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyC39ConvertToC32 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyC39ConvertToC32], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyMsi enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyMsi], %@", error.description);
            }
        }];
        [self.readerDevice setSymbology:CMBSymbologyI2o5 enabled:YES completion:^(NSError *error){
            if (error)
            {
                NSLog(@"FALIED TO ENABLE [CMBSymbologyI2o5], %@", error.description);
            }
        }];
        
        // 这里只扫条形码,结果不需要以图片或者图像的形式返回,所以设置为NO,在返回结果CMBReadResults里面,iamge就会为空。
        self.readerDevice.imageResultEnabled = NO;
        self.readerDevice.SVGResultEnabled = NO;
        
        // https://cmbdn.cognex.com/v2.6.x/knowledge/-cognex-mobile-barcode-sdk-for-ios/using-cmbsdk/advanced-configuration
        // 使用 DataMan 控制命令的高级配置 
        // 相机变焦设置 sendCommand("SET CAMERA.ZOOM 2");
        [self.readerDevice.dataManSystem sendCommand:@"SET DECODER.MAX-SCAN-TIMEOUT 120"];
        [self.readerDevice.dataManSystem sendCommand:@"SET FOCUS.FOCUSTIME 3"];
    }
}

- (void)didReceiveReadResultFromReader:(CMBReaderDevice *)reader results:(CMBReadResults *)readResults
{
    NSMutableArray *results = [NSMutableArray array];
    if (readResults.readResults.count > 0) {
        [results addObjectsFromArray:readResults.readResults];
    }
    if (readResults.subReadResults.count > 0) {
        [results addObjectsFromArray:readResults.subReadResults];
    }
    
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"goodRead == TRUE"];
    [results filterUsingPredicate:predicate];
    
    if (results.count > 0) {
        
        CMBReadResult *result = results.firstObject;
        if (result.goodRead) {
            NSLog(@"++++++++++++%@+++++++++++++",result.readString);
        }

        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

@end
  • previewOptions

可以用 OR 语法传参。

kCDMPreviewOptionDefaults:接受由CameraMode设置的所有默认值。
kCDMPreviewOptionNoZoomBtn:隐藏直播预览上的缩放按钮。
kCDMPreviewOptionNoIllumBtn:隐藏直播预览上的照明按钮。
kCDMPreviewOptionHwTrigger:启用模拟硬件触发器(音量控制)以开始扫描。按下后,扫描开始。
kCDMPreviewOptionPaused:当调用 startScanning()方法而不开始解码(即寻找条形码)时显示实时预览。按屏幕上的扫描按钮开始解码。
kCDMPreviewOptionAlwaysShow:选择主动或被动瞄准模式时强制显示实时预览(例如CameraMode == kCDMCameraModePassiveAimer)
kCDMPreviewOptionPessimisticCaching:仅在CameraMode ==     kCDMCameraModeActiveAimer时使用,这将在应用程序从后台恢复时从ActiveAimer读取设置,以防瞄准器设置从另一个应用程序更改。
kCDMPreviewOptionHighResolution:使用更高分辨率的设备摄像头来帮助扫描小条码,但解码时间较慢。该选项在支持它的设备上将分辨率设置为 1920x1080,在不支持的设备上设置为默认分辨率。默认分辨率为 1280x720。  

kCDMPreviewOptionHighFrameRate:将相机设置为 60 FPS 而不是默认的 30 FPS,以提供更流畅的相机预览。

kCDMPreviewOptionKeepPreviewInPausedState:在读取或超时后保持预览处于暂停状态。

  • previewOptions

如果是扫描小条码的话,建议使用kCDMPreviewOptionHighResolution,会默认设置最大分辨率扫描。

  • setSymbology

https://cmbdn.cognex.com/v2.6.x/knowledge/-cognex-mobile-barcode-sdk-for-ios/using-cmbsdk/enabling-symbologies

通过 -(void) setSymbology:(CMBSymbology)symbology
enabled:(bool)enabled
completion:(void (^)(NSError *error))completionBlock; 方法,启用符号系统

此方法中用于符号系统参数的所有符号系统都可以在CMBReaderDevice.h 中找到。见枚举 CMBSymbology。

以此来设置需要支持的扫码形式

问题

SDK不支持arm架构的模拟器设备,在M1 Xcode13上选择模拟器编译会报错:building for iOS Simulator-arm64 but attempting to link with file built for iOS Simulator-x86_64

解决办法:Build Settings -> Excluded Architectures -> arm 64

参考 ‘Xcode 12, building for iOS Simulator, but linking in an object file built for iOS, for architecture ‘arm64’’ :https://stackoverflow.com/questions/63607158/xcode-12-building-for-ios-simulator-but-linking-in-an-object-file-built-for-io

最后

如果只是简单的识别个二维码或者条形码就够了的话,使用系统提供的框封装一个QRCodeScaner完全满足需求。但是如果需要更加专业的扫描的话,Cognex还是挺专业的。

关于 Apple 的 MFi 产品计划以及上线要求之类的,建议仔细阅读一遍光放文档,文档中都有说明。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Morris_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值