GRScanManager.m 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. //
  2. // GRCodeManager.m
  3. // GreenRoad
  4. //
  5. // Created by Vecige on 16/11/17.
  6. // Copyright © 2016年 jetsum. All rights reserved.
  7. //
  8. #import "GRScanManager.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. #import <AudioToolbox/AudioToolbox.h>
  11. @interface GRScanManager()<AVCaptureMetadataOutputObjectsDelegate>
  12. @property (copy, nonatomic) void (^completionBlock) (NSString *);
  13. @property (nonatomic, strong) AVCaptureSession *session;
  14. @property (nonatomic, strong) dispatch_queue_t sessionQueue;
  15. @end
  16. @implementation GRScanManager
  17. - (instancetype)init {
  18. self = [super init];
  19. if (self) {
  20. _supportQRCode = YES;
  21. _supportBarCode = YES;
  22. [self createQueue];
  23. }
  24. return self;
  25. }
  26. /**
  27. * 创建一个队列,防止阻塞主线程
  28. */
  29. - (void)createQueue{
  30. dispatch_queue_t sessionQueue = dispatch_queue_create("com.Colexiu.KulexiuForStudent.sesson", DISPATCH_QUEUE_SERIAL);
  31. self.sessionQueue = sessionQueue;
  32. }
  33. #pragma mark - 扫描二维码
  34. #pragma mark 开始扫描
  35. - (void)startScanningQRCodeWithInView:(UIView *)inView scanView:(UIView *)scanView resultCallback:(void(^)(NSString *result))callback {
  36. if ([self.session isRunning]) {
  37. [self.session stopRunning];
  38. self.session = nil;
  39. }
  40. // 0.保存block
  41. self.completionBlock = callback;
  42. // 1.创建输入
  43. // 1.1.定义错误
  44. NSError *error = nil;
  45. // 1.2.获取摄像头
  46. AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  47. if ([device respondsToSelector:@selector(setVideoZoomFactor:)]) {
  48. if ([ device lockForConfiguration:nil]) {
  49. // float zoomFactor = device.activeFormat.videoZoomFactorUpscaleThreshold;
  50. float zoomFactor = 2.0;
  51. [device setVideoZoomFactor:zoomFactor];
  52. [device unlockForConfiguration];
  53. }
  54. }
  55. // 1.3.创建输入
  56. AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
  57. if (error != nil) {
  58. return;
  59. }
  60. // 2.创建输出
  61. AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
  62. [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
  63. // 3.创建捕捉会话
  64. AVCaptureSession *session = [[AVCaptureSession alloc] init];
  65. [session addInput:input];
  66. [session addOutput:output];
  67. self.session = session;
  68. // 4.设置输入的内容类型
  69. // [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
  70. // [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]];
  71. NSMutableArray *types = [NSMutableArray array];
  72. if (self.supportQRCode) {
  73. [types addObject:AVMetadataObjectTypeQRCode];
  74. }
  75. if (self.supportBarCode) {
  76. [types addObjectsFromArray:@[AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]];
  77. }
  78. [output setMetadataObjectTypes:[types copy]];
  79. // 5.添加预览图层(让用户看到扫描的界面)
  80. // 5.1.创建图层
  81. AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
  82. previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
  83. // 5.2.设置的layer的frame
  84. previewLayer.frame = inView.bounds;
  85. inView.clipsToBounds = YES;
  86. inView.layer.masksToBounds = YES;
  87. scanView.clipsToBounds = YES;
  88. scanView.layer.masksToBounds = YES;
  89. // 5.3.将图层添加到其它图层中
  90. [inView.layer insertSublayer:previewLayer below:scanView.layer];
  91. [previewLayer setAffineTransform:CGAffineTransformMakeScale(2.0, 2.0)];
  92. // 6.设置扫描区域
  93. CGSize screenSize = [UIScreen mainScreen].bounds.size;
  94. CGFloat x = scanView.frame.origin.y / screenSize.height;
  95. CGFloat y = scanView.frame.origin.x / screenSize.width;
  96. CGFloat w = scanView.frame.size.height / screenSize.height;
  97. CGFloat h = scanView.frame.size.width / screenSize.width;
  98. output.rectOfInterest = CGRectMake(x, y, w, h);
  99. // 7.开始扫描
  100. [self sessionStartRunning];
  101. }
  102. - (void)sessionStartRunning {
  103. @weakObj(self);
  104. dispatch_async(self.sessionQueue, ^{
  105. @strongObj(self);
  106. if (!self.session.running) {
  107. [self.session startRunning];
  108. }
  109. });
  110. }
  111. -(void)sessionStopRunning{
  112. @weakObj(self);
  113. dispatch_async(self.sessionQueue, ^{
  114. @strongObj(self);
  115. if (self.session.running) {
  116. [self.session stopRunning];
  117. }
  118. });
  119. }
  120. #pragma mark - 实现AVCaptureMetadataOutput代理方法
  121. - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
  122. // 1.遍历结果
  123. for (AVMetadataMachineReadableCodeObject *result in metadataObjects) {
  124. NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) result stringValue];
  125. [self addwarningtone];
  126. BLOCK_EXEC(_completionBlock,scannedResult);
  127. // [self stopScanning];
  128. break;
  129. }
  130. }
  131. #pragma mark 给扫描结果添加提示音
  132. -(void)addwarningtone{
  133. SystemSoundID soundID = 1000;
  134. AudioServicesPlaySystemSound(soundID);
  135. AudioServicesPlayAlertSound(soundID);
  136. }
  137. + (BOOL)isAvailable
  138. {
  139. @autoreleasepool {
  140. AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  141. if (!captureDevice) {
  142. return NO;
  143. }
  144. NSError *error;
  145. AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
  146. if (!deviceInput || error) {
  147. return NO;
  148. }
  149. return YES;
  150. }
  151. }
  152. + (BOOL)supportsMetadataObjectTypes:(NSArray *)metadataObjectTypes
  153. {
  154. if (![self isAvailable]) {
  155. return NO;
  156. }
  157. @autoreleasepool {
  158. // Setup components
  159. AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  160. AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
  161. AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
  162. AVCaptureSession *session = [[AVCaptureSession alloc] init];
  163. [session addInput:deviceInput];
  164. [session addOutput:output];
  165. if (metadataObjectTypes == nil || metadataObjectTypes.count == 0) {
  166. // Check the QRCode metadata object type by default
  167. metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
  168. }
  169. for (NSString *metadataObjectType in metadataObjectTypes) {
  170. if (![output.availableMetadataObjectTypes containsObject:metadataObjectType]) {
  171. return NO;
  172. }
  173. }
  174. return YES;
  175. }
  176. }
  177. - (void)stopScanning {
  178. [self sessionStopRunning];
  179. }
  180. @end