QRCodeScanViewController.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. //
  2. // QRCodeScanViewController.m
  3. // 隐私保护
  4. //
  5. // Created by APPLE on 2023/9/19.
  6. //
  7. #import "QRCodeScanViewController.h"
  8. #import <AVFoundation/AVFoundation.h>
  9. #import <ImageIO/ImageIO.h>
  10. #import "GuideViewController.h"
  11. #import "RSATool.h"
  12. @interface QRCodeScanViewController ()<AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>
  13. @property(nonatomic,strong)AVCaptureVideoPreviewLayer *layer;
  14. //捕捉会话
  15. @property(nonatomic,strong)AVCaptureSession *session;
  16. //辅助区域框
  17. @property(nonatomic,strong)UIView * cyanView;
  18. ////打开灯光btn,默认为hidden
  19. //
  20. //@property(nonatomic,strong)UIButton * lightBtn;
  21. //
  22. ////获取相册图片进行扫描
  23. //
  24. //@property(nonatomic,strong)UIButton * photoBtn;
  25. @end
  26. @implementation QRCodeScanViewController
  27. - (void)viewDidLoad {
  28. [super viewDidLoad];
  29. // Do any additional setup after loading the view.
  30. [self.navigationBar setHidden:YES];
  31. [self.toolBar setHidden:YES];
  32. AVAuthorizationStatus authStatus =[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  33. //判断摄像头状态是否可用
  34. if(authStatus==AVAuthorizationStatusAuthorized){
  35. [self startScan];
  36. }else{
  37. NSLog(@"未开启相机权限,请前往设置中开启");
  38. [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
  39. if (granted){
  40. mainBlock(^{
  41. [self startScan];
  42. });
  43. }
  44. }];
  45. }
  46. }
  47. //开始扫描二维码
  48. -(void)startScan{
  49. //1.创建捕捉会话,AVCaptureSession是第一个要被创建的对象,所有的操作都要基于这一个session
  50. self.session = [[AVCaptureSession alloc]init];
  51. AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  52. AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
  53. [self.session addInput:input];
  54. //3.添加输出数据(示例对象-->类对象-->元类对象-->根元类对象)
  55. /*输入的类是AVCaptureInput,那么输出的类相应的就应该是AVCaptureOutput。
  56.  输出不需要和设备挂钩,因为一般情况下,我们的输出要么是音频或视频文件,要么是一些其他的数据,像二维码扫描一般是字符串类型。
  57.  所以创建AVCaptureOutput实例就不需要AVCaptureDevice对象。
  58.  AVCaptureOutput也同样是一个抽象类,同样要使用其子类,在这里我们扫描二维码,
  59.  使用的是AVCaptureMetadataOutput,设置代码如下所示*/
  60. AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
  61. [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
  62. //设置能扫描的区域,这里注意,CGRectMake的x,y和width,height的值是互换位置
  63. output.rectOfInterest=CGRectMake(250/self.view.frame.size.height, 100/self.view.frame.size.width, (self.view.frame.size.width-200)/self.view.frame.size.width, (self.view.frame.size.width-200)/self.view.frame.size.width);
  64. [self.session addOutput:output];
  65. //设置输入元数据的类型(类型是二维码,条形码数据,注意,这个一定要写在添加到session后面,不然要崩溃,如果只需要扫描二维码只需要AVMetadataObjectTypeQRCode,如果还需要扫描条形码,那么全部添加上)
  66. [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode,
  67. AVMetadataObjectTypeEAN8Code,
  68. AVMetadataObjectTypeEAN13Code,
  69. AVMetadataObjectTypeCode39Code,
  70. AVMetadataObjectTypeCode39Mod43Code,
  71. AVMetadataObjectTypeCode93Code,
  72. AVMetadataObjectTypeCode128Code,
  73. AVMetadataObjectTypePDF417Code,
  74. AVMetadataObjectTypeAztecCode,
  75. AVMetadataObjectTypeUPCECode,
  76. AVMetadataObjectTypeInterleaved2of5Code,
  77. AVMetadataObjectTypeITF14Code,
  78. AVMetadataObjectTypeDataMatrixCode,
  79. ]];
  80. //4.添加扫描图层
  81. self.layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
  82. self.layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
  83. self.layer.frame = self.view.bounds;
  84. [self.view.layer addSublayer:self.layer];
  85. //5.创建view,通过layer层进行设置边框宽度和颜色,用来辅助展示扫描的区域
  86. UIView * cyanView=[[UIView alloc] initWithFrame:CGRectMake(100, 250, self.view.frame.size.width-200, self.view.frame.size.width-200)];
  87. cyanView.layer.borderWidth=2;
  88. cyanView.layer.borderColor =[UIColor cyanColor].CGColor;
  89. [self.view addSubview:cyanView];
  90. //6.创建检测光感源
  91. AVCaptureVideoDataOutput *guangOutPut = [[AVCaptureVideoDataOutput alloc] init];
  92. [guangOutPut setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
  93. //设置为高质量采集率
  94. [self.session setSessionPreset:AVCaptureSessionPresetHigh];
  95. //把光感源添加到会话
  96. [self.session addOutput:guangOutPut];
  97. // self.lightBtn=[[UIButton alloc]initWithFrame:CGRectMake(150, cyanView.frame.origin.y+cyanView.frame.size.height+100, self.view.frame.size.width-300, self.view.frame.size.width-300)];
  98. //
  99. // self.lightBtn.backgroundColor=[UIColor grayColor];
  100. //
  101. // [self.lightBtn addTarget:self action:@selector(lightBtnClick:) forControlEvents:UIControlEventTouchUpInside];
  102. //
  103. // [self.view addSubview:self.lightBtn];
  104. // self.photoBtn=[[UIButton alloc]initWithFrame:CGRectMake(100, self.lightBtn.frame.origin.y+self.lightBtn.frame.size.height+50, self.view.frame.size.width-200, 50)];
  105. // [self.photoBtn setTitle:@"相册" forState:UIControlStateNormal];
  106. // [self.photoBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  107. // self.photoBtn.backgroundColor=[UIColor orangeColor];
  108. // [self.photoBtn addTarget:self action:@selector(photoBtnClick:) forControlEvents:UIControlEventTouchUpInside];
  109. // [self.view addSubview:self.photoBtn];
  110. //9.开始扫描
  111. [self.session startRunning];
  112. }
  113. //实现扫描的回调代理方法
  114. - (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputMetadataObjects:(NSArray*)metadataObjects fromConnection:(AVCaptureConnection*)connection{
  115. //如果数组metadataObjects中有数据,metadataObjects是个数组类型
  116. if(metadataObjects.count>0) {
  117. AVMetadataMachineReadableCodeObject*object = [metadataObjects lastObject];
  118. NSLog(@"%@",object.stringValue);
  119. /*扫描到有用信息时取消扫描*/
  120. NSString *resStr = object.stringValue;//RK3908P1V62112465
  121. if(resStr.length == @"Ch0IKJCY9lOgokjfPBFE1cowdC1+tj7ywB2pZgSzjhc=".length)
  122. {
  123. resStr = [RSATool AES128Decrypt:resStr key:@"fvO8gAfNSr1tbdQe"];
  124. }
  125. if (([resStr containsString:@"RK"] && (resStr.length == @"RK3908P1V62112465".length))
  126. || resStr.length == @"0333933700223250017273".length
  127. ){
  128. NSDictionary *newDict = [[NSDictionary alloc] initWithObjectsAndKeys:resStr,Const_Have_Add_Device_SN, nil];
  129. [HWDataManager setObjectWithKey:Const_Have_Add_Device value:newDict];
  130. [self nextStep:resStr];
  131. //停止扫描
  132. [self.session stopRunning];
  133. //移除扫描层layer
  134. [self.layer removeFromSuperlayer];
  135. }
  136. }else{
  137. NSLog(@"没有扫描到数据");
  138. }
  139. }
  140. - (void)nextStep:(NSString *)sn{
  141. /*下一步*/
  142. GuideViewController *nextVC = [[GuideViewController alloc] init];
  143. nextVC.sn = sn;
  144. [self.navigationController pushViewController:nextVC animated:YES];
  145. }
  146. //光感传感器代理
  147. -(void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection{
  148. //获取光线的值
  149. CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,sampleBuffer, kCMAttachmentMode_ShouldPropagate);
  150. NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
  151. CFRelease(metadataDict);
  152. NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
  153. float brightnessValue = [[exifMetadata objectForKey:(NSString*)kCGImagePropertyExifBrightnessValue]floatValue];
  154. NSLog(@"%f",brightnessValue);
  155. // 根据brightnessValue的值来打开和关闭闪光灯,一般值小于0就需要打开,大于0就关闭
  156. // if((brightnessValue <0)) {//显示闪光灯
  157. // self.lightBtn.hidden=NO;
  158. // }else if((brightnessValue >0)) {//隐藏闪光灯
  159. // self.lightBtn.hidden=YES;
  160. // }
  161. }
  162. ////闪光灯按钮点击方法
  163. //
  164. //-(void)lightBtnClick:(UIButton*)sender{
  165. // //判断当前设备是否有闪光灯
  166. //
  167. // AVCaptureDevice * device=[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  168. //
  169. // BOOL result=[device hasTorch];
  170. //
  171. // if(result==YES){
  172. // if(self.lightBtn.isSelected==NO){
  173. // self.lightBtn.selected=YES;
  174. // self.lightBtn.backgroundColor=[UIColor greenColor];
  175. // [device lockForConfiguration:nil];
  176. // [device setTorchMode: AVCaptureTorchModeOn];//开
  177. // [device unlockForConfiguration];
  178. // }else if(self.lightBtn.isSelected==YES){
  179. // self.lightBtn.selected=NO;
  180. // self.lightBtn.backgroundColor=[UIColor grayColor];
  181. // [device lockForConfiguration:nil];
  182. // [device setTorchMode: AVCaptureTorchModeOff];//关
  183. // [device unlockForConfiguration];
  184. // }
  185. // }else{
  186. // NSLog(@"当前设备闪光灯不可用");
  187. // }
  188. //}
  189. //
  190. ////获取相册图片btn点击方法
  191. //
  192. //-(void)photoBtnClick:(UIButton*)sender{
  193. // UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
  194. // imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
  195. // // imagePicker.allowsEditing = YES;
  196. // imagePicker.delegate=self;
  197. // [self.navigationController presentViewController:imagePicker animated:YES completion:nil];
  198. //}
  199. //UIImagePickerControllerDelegate选择图片的回调
  200. -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
  201. //把UIimage类型转换成CIimage类型
  202. UIImage *pickedImage = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];
  203. CIImage*detectImage = [CIImage imageWithData:UIImagePNGRepresentation(pickedImage)];
  204. //解析扫描二维码结果字符串
  205. CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
  206. CIQRCodeFeature*feature = (CIQRCodeFeature*)[detector featuresInImage:detectImage options:nil].firstObject;
  207. [picker dismissViewControllerAnimated:YES completion:^{
  208. if(feature.messageString) {
  209. NSLog(@"=================二维码结果为%@",feature.messageString);
  210. }else{
  211. NSLog(@"未扫描到相应二维码");
  212. }
  213. //停止会话对象扫描
  214. [self.session stopRunning];
  215. //移除扫描层layer
  216. [self.layer removeFromSuperlayer];
  217. }];
  218. }
  219. @end