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 中定义。
这个类有两个数组,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,会默认设置最大分辨率扫描。
setSymbologyhttps://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条)