Cognex Mobile Barcode SDK for iOS
概述
Cognex Mobile Barcode SDK (cmbSDK) 是用于開(kāi)發(fā)移動(dòng)條碼掃描應(yīng)用程序的SDK。
SDK是付費(fèi)的,但功能很強(qiáng)大。
Cognex Mobile Barcode SDK for iOS : https://cmbdn.cognex.com/download#Platforms
iOS技術(shù)文檔地址:https://cmbdn.cognex.com/knowledge/-cognex-mobile-barcode-sdk-for-ios
SDK
- CMBReaderDevice
這個(gè)類提供了,連接,掃碼,掃碼結(jié)果回調(diào),斷開(kāi)連接等系列操作。
- CMBReadResult
這個(gè)類是掃描結(jié)果的抽象類,將掃描結(jié)果打包成CMBReadResult,提供了掃描的內(nèi)容readResult.readString 和 readResult.image,是否是有效的goodRead。
goodRead (BOOL):判斷讀取是否成功
readString (NSString): 解碼后的條碼字符串
圖像(UIImage):解碼器處理過(guò)的圖像/幀
imageGraphics (NSData):條碼的邊界路徑作為SVG數(shù)據(jù)
XML (NSData):解碼器返回的原始 XML
符號(hào)(CMBSymbology):條碼的符號(hào)類型。該枚舉在CMBReaderDevice.h 中定義。
- CMBReadResults
這個(gè)類有兩個(gè)數(shù)組,readResults 和 subReadResults ,將一幀(或者更短時(shí)間)內(nèi)的所有掃描結(jié)果CMBReadResult都“入隊(duì)”到兩個(gè)數(shù)組中。
讀取掃描結(jié)果的時(shí)候,我們只需取第一個(gè)元素作為最終的掃描結(jié)果即可。
- CDMDataManSystem
這個(gè)類提供了連接遠(yuǎn)程服務(wù)的API,通過(guò)用戶名和密碼連接遠(yuǎn)程,可以發(fā)送命令和接收命令。
- CDMResponse
遠(yuǎn)程連接的回調(diào)類。
- MWOverlay
以下兩種模式的UI是不一樣的,如果需要自定義UI的話,可以選擇第一種模式,在previewView添加自定義試圖。
// 這種模式適用于自己設(shè)置一個(gè)previewView,在規(guī)定的previewView范圍內(nèi)掃描
[MWOverlay setOverlayMode:OM_CMB];// 這種模式在SDK的較低版本中是全屏進(jìn)行掃描,在高一點(diǎn)的版本中(如2.6.1)如果設(shè)置previewView,則在previewView范圍內(nèi)掃描,不設(shè)置的話默認(rèn)全屏掃描。低版本中設(shè)置previewView是無(wú)效的。
[MWOverlay setOverlayMode:OM_LEGACY];還有一些設(shè)置邊框顏色什么的屬性,可以試試看。
- CDMEADiscoverer
SDK使用
下載官方提供的SDK,文檔以及Demo,例 cmbSDK_iOS_v2.6.1 -> samples -> SampleApp
Demo中已經(jīng)引用好了SDK,官方給我的SDK支持 arm64和armv7的真機(jī)和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; // 掃描預(yù)覽試圖@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 版本號(hào)NSLog(@"Version: %@",[CDMDataManSystem getVersion]);// 掃描預(yù)覽試圖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];// 檢測(cè)相機(jī)授權(quán)AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];self.canAccessCamera = (authStatus != AVAuthorizationStatusDenied && authStatus != AVAuthorizationStatusRestricted);if (!self.canAccessCamera) {NSLog(@"沒(méi)有權(quán)限訪問(wèn)相機(jī)");[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];}// 這種模式指定在設(shè)置的previewView之內(nèi)掃描以及預(yù)覽。當(dāng)設(shè)置為OM_LEGACY時(shí),previewView的設(shè)置無(wú)效,會(huì)全屏預(yù)覽掃描。[MWOverlay setOverlayMode:OM_CMB];// previewOptions 可以用 OR 語(yǔ)法傳參。/**kCDMPreviewOptionDefaults:接受由CameraMode設(shè)置的所有默認(rèn)值。kCDMPreviewOptionNoZoomBtn:隱藏直播預(yù)覽上的縮放按鈕。kCDMPreviewOptionNoIllumBtn:隱藏直播預(yù)覽上的照明按鈕。kCDMPreviewOptionHwTrigger:啟用模擬硬件觸發(fā)器(音量控制)以開(kāi)始掃描。按下后,掃描開(kāi)始。kCDMPreviewOptionPaused:當(dāng)調(diào)用 startScanning()方法而不開(kāi)始解碼(即尋找條形碼)時(shí)顯示實(shí)時(shí)預(yù)覽。按屏幕上的掃描按鈕開(kāi)始解碼。kCDMPreviewOptionAlwaysShow:選擇主動(dòng)或被動(dòng)瞄準(zhǔn)模式時(shí)強(qiáng)制顯示實(shí)時(shí)預(yù)覽(例如CameraMode == kCDMCameraModePassiveAimer)kCDMPreviewOptionPessimisticCaching:僅在CameraMode == kCDMCameraModeActiveAimer時(shí)使用,這將在應(yīng)用程序從后臺(tái)恢復(fù)時(shí)從ActiveAimer讀取設(shè)置,以防瞄準(zhǔn)器設(shè)置從另一個(gè)應(yīng)用程序更改。kCDMPreviewOptionHighResolution:使用更高分辨率的設(shè)備攝像頭來(lái)幫助掃描小條碼,但解碼時(shí)間較慢。該選項(xiàng)在支持它的設(shè)備上將分辨率設(shè)置為 1920x1080,在不支持的設(shè)備上設(shè)置為默認(rèn)分辨率。默認(rèn)分辨率為 1280x720。 kCDMPreviewOptionHighFrameRate:將相機(jī)設(shè)置為 60 FPS 而不是默認(rèn)的 30 FPS,以提供更流暢的相機(jī)預(yù)覽。 kCDMPreviewOptionKeepPreviewInPausedState:在讀取或超時(shí)后保持預(yù)覽處于暫停狀態(tài)。*/// 如果是掃描小條碼的話,建議使用kCDMPreviewOptionHighResolution,會(huì)默認(rèn)設(shè)置最大分辨率掃描。CMBReaderDevice *tmpDevice = [CMBReaderDevice readerOfDeviceCameraWithCameraMode:kCDMCameraModeNoAimerpreviewOptions:kCDMPreviewOptionDefaultspreviewView:self.previewViewregistrationKey:CognexRegistrationKeycustomData: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(@"不能打開(kāi)攝像頭掃描,請(qǐng)確保攝像頭已允許訪問(wèn)");}return tmpDevice; }- (void)showAlert {UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Permission denied" message:@"使用相機(jī)" 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// 通過(guò) -(void) setSymbology:(CMBSymbology)symbology enabled:(bool)enabled completion:(void (^)(NSError *error))completionBlock; 方法,啟用符號(hào)系統(tǒng)// 此方法中用于符號(hào)系統(tǒng)參數(shù)的所有符號(hào)系統(tǒng)都可以在CMBReaderDevice.h 中找到。見(jiàn)枚舉 CMBSymbology。// 以此來(lái)設(shè)置需要支持的掃碼形式// 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);}}];// 這里只掃條形碼,結(jié)果不需要以圖片或者圖像的形式返回,所以設(shè)置為NO,在返回結(jié)果CMBReadResults里面,iamge就會(huì)為空。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 控制命令的高級(jí)配置 // 相機(jī)變焦設(shè)置 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 語(yǔ)法傳參。
kCDMPreviewOptionDefaults:接受由CameraMode設(shè)置的所有默認(rèn)值。 kCDMPreviewOptionNoZoomBtn:隱藏直播預(yù)覽上的縮放按鈕。 kCDMPreviewOptionNoIllumBtn:隱藏直播預(yù)覽上的照明按鈕。 kCDMPreviewOptionHwTrigger:啟用模擬硬件觸發(fā)器(音量控制)以開(kāi)始掃描。按下后,掃描開(kāi)始。 kCDMPreviewOptionPaused:當(dāng)調(diào)用 startScanning()方法而不開(kāi)始解碼(即尋找條形碼)時(shí)顯示實(shí)時(shí)預(yù)覽。按屏幕上的掃描按鈕開(kāi)始解碼。 kCDMPreviewOptionAlwaysShow:選擇主動(dòng)或被動(dòng)瞄準(zhǔn)模式時(shí)強(qiáng)制顯示實(shí)時(shí)預(yù)覽(例如CameraMode == kCDMCameraModePassiveAimer) kCDMPreviewOptionPessimisticCaching:僅在CameraMode == kCDMCameraModeActiveAimer時(shí)使用,這將在應(yīng)用程序從后臺(tái)恢復(fù)時(shí)從ActiveAimer讀取設(shè)置,以防瞄準(zhǔn)器設(shè)置從另一個(gè)應(yīng)用程序更改。 kCDMPreviewOptionHighResolution:使用更高分辨率的設(shè)備攝像頭來(lái)幫助掃描小條碼,但解碼時(shí)間較慢。該選項(xiàng)在支持它的設(shè)備上將分辨率設(shè)置為 1920x1080,在不支持的設(shè)備上設(shè)置為默認(rèn)分辨率。默認(rèn)分辨率為 1280x720。 kCDMPreviewOptionHighFrameRate:將相機(jī)設(shè)置為 60 FPS 而不是默認(rèn)的 30 FPS,以提供更流暢的相機(jī)預(yù)覽。kCDMPreviewOptionKeepPreviewInPausedState:在讀取或超時(shí)后保持預(yù)覽處于暫停狀態(tài)。
- previewOptions
如果是掃描小條碼的話,建議使用kCDMPreviewOptionHighResolution,會(huì)默認(rèn)設(shè)置最大分辨率掃描。
- setSymbology
https://cmbdn.cognex.com/v2.6.x/knowledge/-cognex-mobile-barcode-sdk-for-ios/using-cmbsdk/enabling-symbologies
通過(guò) -(void) setSymbology:(CMBSymbology)symbology
enabled:(bool)enabled
completion:(void (^)(NSError *error))completionBlock; 方法,啟用符號(hào)系統(tǒng)
此方法中用于符號(hào)系統(tǒng)參數(shù)的所有符號(hào)系統(tǒng)都可以在CMBReaderDevice.h 中找到。見(jiàn)枚舉 CMBSymbology。
以此來(lái)設(shè)置需要支持的掃碼形式
問(wèn)題
SDK不支持arm架構(gòu)的模擬器設(shè)備,在M1 Xcode13上選擇模擬器編譯會(huì)報(bào)錯(cuò):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 ‘a(chǎn)rm64’’ :https://stackoverflow.com/questions/63607158/xcode-12-building-for-ios-simulator-but-linking-in-an-object-file-built-for-io
最后
如果只是簡(jiǎn)單的識(shí)別個(gè)二維碼或者條形碼就夠了的話,使用系統(tǒng)提供的框封裝一個(gè)QRCodeScaner完全滿足需求。但是如果需要更加專業(yè)的掃描的話,Cognex還是挺專業(yè)的。
關(guān)于 Apple 的 MFi 產(chǎn)品計(jì)劃以及上線要求之類的,建議仔細(xì)閱讀一遍光放文檔,文檔中都有說(shuō)明。
總結(jié)
以上是生活随笔為你收集整理的Cognex Mobile Barcode SDK for iOS的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: IBM V7000错误代码及解决
- 下一篇: ByShell 一个穿越主动防御的木马