77//
88
99#import " ZXScanCodeViewController.h"
10+ #import < AVFoundation/AVFoundation.h>
1011#import " ScanBGView.h"
11- #import < ZXingObjC/ZXingObjC.h>
1212
13- @interface ZXScanCodeViewController ()<ZXCaptureDelegate>
14- @property (nonatomic , strong ) ZXCapture *capture;
13+ @interface ZXScanCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>
1514@property (strong , nonatomic ) ScanBGView *myScanBGView;
1615@property (strong , nonatomic ) UIImageView *scanRectView, *lineView;
1716@property (strong , nonatomic ) UILabel *tipLabel;
18- @property (assign , nonatomic ) BOOL scanSucessed;
17+
18+ @property (strong , nonatomic ) AVCaptureVideoPreviewLayer *videoPreviewLayer;
1919@end
2020
2121@implementation ZXScanCodeViewController
@@ -45,8 +45,8 @@ - (void)viewDidAppear:(BOOL)animated {
4545
4646- (void )viewWillDisappear : (BOOL )animated {
4747 [super viewWillDisappear: animated];
48- [self .capture stop ];
49- [self .capture.layer removeFromSuperlayer ];
48+ [self .videoPreviewLayer.session stopRunning ];
49+ [self .videoPreviewLayer removeFromSuperlayer ];
5050 [self scanLineStopAction ];
5151}
5252
@@ -55,14 +55,38 @@ - (void)configUI{
5555 CGFloat padding = (kScreen_Width - width)/2 ;
5656 CGRect scanRect = CGRectMake (padding, kScreen_Height /10 , width, width);
5757
58- if (!_capture) {
59- _capture = [[ZXCapture alloc ] init ];
60- _capture.camera = _capture.back ;
61- _capture.focusMode = AVCaptureFocusModeContinuousAutoFocus;
62- _capture.rotation = 90 .f ;
63- _capture.layer .frame = self.view .bounds ;
64- _capture.scanRect = scanRect;
65- _capture.delegate = self;
58+ if (!_videoPreviewLayer) {
59+ NSError *error;
60+ AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
61+ AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice: captureDevice error: &error];
62+ if (!input) {
63+ kTipAlert (@" %@ " , error.localizedDescription );
64+ [self .navigationController popViewControllerAnimated: YES ];
65+ }else {
66+ // 设置会话的输入设备
67+ AVCaptureSession *captureSession = [AVCaptureSession new ];
68+ [captureSession addInput: input];
69+ // 对应输出
70+ AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc ] init ];
71+ [captureMetadataOutput setMetadataObjectsDelegate: self queue: dispatch_queue_create (" ease_capture_queue" ,NULL )];
72+ [captureSession addOutput: captureMetadataOutput];
73+
74+ // 设置条码类型:包含 AVMetadataObjectTypeQRCode 就好
75+ if (![captureMetadataOutput.availableMetadataObjectTypes containsObject: AVMetadataObjectTypeQRCode]) {
76+ kTipAlert (@" 摄像头不支持扫描二维码!" );
77+ [self .navigationController popViewControllerAnimated: YES ];
78+ }else {
79+ [captureMetadataOutput setMetadataObjectTypes: captureMetadataOutput.availableMetadataObjectTypes];
80+ }
81+ captureMetadataOutput.rectOfInterest = CGRectMake (CGRectGetMinY (scanRect)/CGRectGetHeight (self.view .frame ),
82+ 1 - CGRectGetMaxX (scanRect)/CGRectGetWidth (self.view .frame ),
83+ CGRectGetHeight (scanRect)/CGRectGetHeight (self.view .frame ),
84+ CGRectGetWidth (scanRect)/CGRectGetWidth (self.view .frame ));// 设置扫描区域。。默认是手机头向左的横屏坐标系(逆时针旋转90度)
85+ // 将捕获的数据流展现出来
86+ _videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession: captureSession];
87+ [_videoPreviewLayer setVideoGravity: AVLayerVideoGravityResizeAspectFill];
88+ [_videoPreviewLayer setFrame: self .view.bounds];
89+ }
6690 }
6791
6892 if (!_myScanBGView) {
@@ -92,7 +116,7 @@ - (void)configUI{
92116 _lineView.image = lineImage;
93117 }
94118
95- [self .view.layer addSublayer: _capture.layer ];
119+ [self .view.layer addSublayer: _videoPreviewLayer ];
96120 [self .view addSubview: _myScanBGView];
97121 [self .view addSubview: _scanRectView];
98122 [self .view addSubview: _tipLabel];
@@ -101,8 +125,8 @@ - (void)configUI{
101125 make.top .equalTo (_scanRectView.mas_bottom ).offset (20 );
102126 make.height .mas_equalTo (30 );
103127 }];
104- [_capture start ];
105128 [_scanRectView addSubview: _lineView];
129+ [_videoPreviewLayer.session startRunning ];
106130 [self scanLineStartAction ];
107131}
108132
@@ -123,80 +147,48 @@ - (void)scanLineStopAction{
123147}
124148
125149- (void )dealloc {
126- [self .capture.layer removeFromSuperlayer ];
127- self.capture = nil ;
150+ [self .videoPreviewLayer removeFromSuperlayer ];
151+ self.videoPreviewLayer = nil ;
128152 [self scanLineStopAction ];
129153 [[NSNotificationCenter defaultCenter ] removeObserver: self ];
130154}
131155
132- #pragma p_Method
133- - (NSString *)barcodeFormatToString : (ZXBarcodeFormat)format {
134- switch (format) {
135- case kBarcodeFormatAztec :
136- return @" Aztec" ;
137-
138- case kBarcodeFormatCodabar :
139- return @" CODABAR" ;
140-
141- case kBarcodeFormatCode39 :
142- return @" Code 39" ;
143-
144- case kBarcodeFormatCode93 :
145- return @" Code 93" ;
146-
147- case kBarcodeFormatCode128 :
148- return @" Code 128" ;
149-
150- case kBarcodeFormatDataMatrix :
151- return @" Data Matrix" ;
152-
153- case kBarcodeFormatEan8 :
154- return @" EAN-8" ;
155-
156- case kBarcodeFormatEan13 :
157- return @" EAN-13" ;
158-
159- case kBarcodeFormatITF :
160- return @" ITF" ;
161-
162- case kBarcodeFormatPDF417 :
163- return @" PDF417" ;
164-
165- case kBarcodeFormatQRCode :
166- return @" QR Code" ;
167-
168- case kBarcodeFormatRSS14 :
169- return @" RSS 14" ;
170-
171- case kBarcodeFormatRSSExpanded :
172- return @" RSS Expanded" ;
173-
174- case kBarcodeFormatUPCA :
175- return @" UPCA" ;
176-
177- case kBarcodeFormatUPCE :
178- return @" UPCE" ;
179-
180- case kBarcodeFormatUPCEANExtension :
181- return @" UPC/EAN extension" ;
182-
183- default :
184- return @" Unknown" ;
156+ #pragma mark AVCaptureMetadataOutputObjectsDelegate
157+
158+ - (void )captureOutput : (AVCaptureOutput *)captureOutput didOutputMetadataObjects : (NSArray *)metadataObjects fromConnection : (AVCaptureConnection *)connection {
159+ // 判断是否有数据,是否是二维码数据
160+ if (metadataObjects.count > 0 ) {
161+ __block AVMetadataMachineReadableCodeObject *result = nil ;
162+ [metadataObjects enumerateObjectsUsingBlock: ^(AVMetadataMachineReadableCodeObject *obj, NSUInteger idx, BOOL *stop) {
163+ if ([obj.type isEqualToString: AVMetadataObjectTypeQRCode]) {
164+ result = obj;
165+ *stop = YES ;
166+ }
167+ }];
168+ if (!result) {
169+ result = [metadataObjects firstObject ];
170+ }
171+ dispatch_async (dispatch_get_main_queue (), ^{
172+ [self analyseResult: result];
173+ });
185174 }
186175}
187176
188- #pragma mark ZXCaptureDelegate
189- - (void )captureResult : (ZXCapture *)capture result : (ZXResult *)result {
190- NSLog (@" result : %@ " , result.text );
191-
192- if (!result || _scanSucessed) return ;
193- _scanSucessed = YES ;
194- [capture stop ];
177+ - (void )analyseResult : (AVMetadataMachineReadableCodeObject *)result {
178+ DebugLog (@" result : %@ " , result.stringValue );
179+ if (result.stringValue .length <= 0 ) {
180+ return ;
181+ }
195182
196- // Vibrate
183+ // 停止扫描
184+ [self .videoPreviewLayer.session stopRunning ];
185+ [self scanLineStopAction ];
186+
187+ // 震动反馈
197188 AudioServicesPlaySystemSound (kSystemSoundID_Vibrate );
198189
199- OTPAuthURL *authURL = [OTPAuthURL authURLWithURL: [NSURL URLWithString: result.text] secret: nil ];
190+ // 解析结果
191+ OTPAuthURL *authURL = [OTPAuthURL authURLWithURL: [NSURL URLWithString: result.stringValue] secret: nil ];
200192 if ([authURL isKindOfClass: [TOTPAuthURL class ]]) {
201193 if (self.sucessScanBlock ) {
202194 self.sucessScanBlock (authURL);
@@ -207,28 +199,25 @@ - (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result{
207199 if (authURL) {
208200 tipStr = @" 目前仅支持 TOTP 类型的身份验证令牌" ;
209201 }else {
210- NSString *formatString = [self barcodeFormatToString: result.barcodeFormat];
211- NSString *resultString = result.text ;
212- tipStr = [NSString stringWithFormat: @" 条码「%@ : %@ 」不是有效的身份验证令牌条码" , formatString, resultString];
202+ tipStr = [NSString stringWithFormat: @" 条码「%@ : %@ 」不是有效的身份验证令牌条码" , result.type, result.stringValue];
213203 }
214-
215204 UIAlertView *alertV = [UIAlertView bk_alertViewWithTitle: @" 无效条码" message: tipStr];
216205 [alertV bk_addButtonWithTitle: @" 重试" handler: ^{
217- self.scanSucessed = NO ;
218- [capture start ];
206+ [ self .videoPreviewLayer.session startRunning ] ;
207+ [self scanLineStartAction ];
219208 }];
220209 [alertV show ];
221210 }
222211}
223212
224213#pragma mark Notification
225214- (void )applicationDidBecomeActive : (UIApplication *)application {
226- [self .capture start ];
215+ [self .videoPreviewLayer.session startRunning ];
227216 [self scanLineStartAction ];
228217}
229218
230219- (void )applicationWillResignActive : (UIApplication *)application {
231- [self .capture stop ];
220+ [self .videoPreviewLayer.session stopRunning ];
232221 [self scanLineStopAction ];
233222}
234223@end
0 commit comments