QRCodeScanForChangeDeviceViewController.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. //
  2. // QRCodeScanForChangeDeviceViewController.m
  3. // 隐私保护
  4. //
  5. // Created by APPLE on 2023/9/19.
  6. //
  7. #import "QRCodeScanForChangeDeviceViewController.h"
  8. #import <AVFoundation/AVFoundation.h>
  9. #import <ImageIO/ImageIO.h>
  10. #import "MySetViewController.h"
  11. #import "RSATool.h"
  12. #import "connectDeviceManager.h"
  13. @interface QRCodeScanForChangeDeviceViewController ()<AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>
  14. @property(nonatomic,strong)AVCaptureVideoPreviewLayer *layer;
  15. //捕捉会话
  16. @property(nonatomic,strong)AVCaptureSession *session;
  17. //辅助区域框
  18. @property(nonatomic,strong)UIImageView * cyanEdgeImageView;
  19. @property(nonatomic,strong)UIImageView * qrCodeScanLine;
  20. @property(nonatomic,strong)NSTimer * scanLineTimer;
  21. ////打开灯光btn,默认为hidden
  22. //
  23. //@property(nonatomic,strong)UIButton * lightBtn;
  24. //
  25. ////获取相册图片进行扫描
  26. //
  27. //@property(nonatomic,strong)UIButton * photoBtn;
  28. @end
  29. @implementation QRCodeScanForChangeDeviceViewController
  30. - (void)viewDidLoad {
  31. [super viewDidLoad];
  32. // Do any additional setup after loading the view.
  33. [self.navigationBar setHidden:YES];
  34. [self.toolBar setHidden:YES];
  35. AVAuthorizationStatus authStatus =[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  36. //判断摄像头状态是否可用
  37. if(authStatus==AVAuthorizationStatusAuthorized){
  38. [self startScan];
  39. }else{
  40. NSLog(@"未开启相机权限,请前往设置中开启");
  41. [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
  42. if (granted){
  43. mainBlock(^{
  44. [self startScan];
  45. });
  46. }
  47. }];
  48. }
  49. }
  50. -(void)viewWillDisappear:(BOOL)animated
  51. {
  52. [super viewWillDisappear:animated];
  53. [_scanLineTimer invalidate];
  54. }
  55. //开始扫描二维码
  56. -(void)startScan{
  57. //1.创建捕捉会话,AVCaptureSession是第一个要被创建的对象,所有的操作都要基于这一个session
  58. self.session = [[AVCaptureSession alloc]init];
  59. AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  60. AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
  61. [self.session addInput:input];
  62. //3.添加输出数据(示例对象-->类对象-->元类对象-->根元类对象)
  63. /*输入的类是AVCaptureInput,那么输出的类相应的就应该是AVCaptureOutput。
  64.  输出不需要和设备挂钩,因为一般情况下,我们的输出要么是音频或视频文件,要么是一些其他的数据,像二维码扫描一般是字符串类型。
  65.  所以创建AVCaptureOutput实例就不需要AVCaptureDevice对象。
  66.  AVCaptureOutput也同样是一个抽象类,同样要使用其子类,在这里我们扫描二维码,
  67.  使用的是AVCaptureMetadataOutput,设置代码如下所示*/
  68. AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
  69. [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
  70. //设置能扫描的区域,这里注意,CGRectMake的x,y和width,height的值是互换位置
  71. 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);
  72. [self.session addOutput:output];
  73. //设置输入元数据的类型(类型是二维码,条形码数据,注意,这个一定要写在添加到session后面,不然要崩溃,如果只需要扫描二维码只需要AVMetadataObjectTypeQRCode,如果还需要扫描条形码,那么全部添加上)
  74. [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode,
  75. AVMetadataObjectTypeEAN8Code,
  76. AVMetadataObjectTypeEAN13Code,
  77. AVMetadataObjectTypeCode39Code,
  78. AVMetadataObjectTypeCode39Mod43Code,
  79. AVMetadataObjectTypeCode93Code,
  80. AVMetadataObjectTypeCode128Code,
  81. AVMetadataObjectTypePDF417Code,
  82. AVMetadataObjectTypeAztecCode,
  83. AVMetadataObjectTypeUPCECode,
  84. AVMetadataObjectTypeInterleaved2of5Code,
  85. AVMetadataObjectTypeITF14Code,
  86. AVMetadataObjectTypeDataMatrixCode,
  87. ]];
  88. //4.添加扫描图层
  89. self.layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
  90. self.layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
  91. self.layer.frame = self.view.bounds;
  92. [self.view.layer addSublayer:self.layer];
  93. //5.创建view,通过layer层进行设置边框宽度和颜色,用来辅助展示扫描的区域
  94. _cyanEdgeImageView=[[UIImageView alloc] initWithFrame:CGRectMake(100, 250, self.view.frame.size.width-200, self.view.frame.size.width-200)];
  95. // _cyanEdgeImageView.layer.borderWidth=2;
  96. //
  97. // _cyanEdgeImageView.layer.borderColor =[UIColor cyanColor].CGColor;
  98. _cyanEdgeImageView.image = [UIImage imageNamed:@"qrCode_scan_bg"];
  99. [self.view addSubview:_cyanEdgeImageView];
  100. _qrCodeScanLine=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width-200, 1)];
  101. _qrCodeScanLine.image = [UIImage imageNamed:@"qrCode_scan_line"];
  102. [_cyanEdgeImageView addSubview:_qrCodeScanLine];
  103. _scanLineTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(scanLineDownAndUpFun) userInfo:nil repeats:YES];
  104. UILabel *tipLib = [[UILabel alloc] initWithFrame:CGRectMake(20, _cyanEdgeImageView.hw_max_y + 15, SCREEN_W - 40, 20)];
  105. tipLib.text = NSLocalizedString(@"guide_qrcoede_tips_please",nil);
  106. tipLib.font = [UIFont systemFontOfSize:14.0];
  107. tipLib.textAlignment = NSTextAlignmentCenter;
  108. tipLib.textColor = [UIColor whiteColor];
  109. [self.view addSubview:tipLib];
  110. //6.创建检测光感源
  111. AVCaptureVideoDataOutput *guangOutPut = [[AVCaptureVideoDataOutput alloc] init];
  112. [guangOutPut setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
  113. //设置为高质量采集率
  114. [self.session setSessionPreset:AVCaptureSessionPresetHigh];
  115. //把光感源添加到会话
  116. [self.session addOutput:guangOutPut];
  117. // 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)];
  118. //
  119. // self.lightBtn.backgroundColor=[UIColor grayColor];
  120. //
  121. // [self.lightBtn addTarget:self action:@selector(lightBtnClick:) forControlEvents:UIControlEventTouchUpInside];
  122. //
  123. // [self.view addSubview:self.lightBtn];
  124. // 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)];
  125. // [self.photoBtn setTitle:@"相册" forState:UIControlStateNormal];
  126. // [self.photoBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  127. // self.photoBtn.backgroundColor=[UIColor orangeColor];
  128. // [self.photoBtn addTarget:self action:@selector(photoBtnClick:) forControlEvents:UIControlEventTouchUpInside];
  129. // [self.view addSubview:self.photoBtn];
  130. //9.开始扫描
  131. [self.session startRunning];
  132. }
  133. #pragma mark timer 处理线上下移动
  134. bool isDownType22 = YES;
  135. -(void)scanLineDownAndUpFun
  136. {
  137. [UIView animateWithDuration:0.01 animations:^{
  138. if(isDownType22 && self->_qrCodeScanLine.hw_y <= self->_cyanEdgeImageView.hw_h){
  139. self->_qrCodeScanLine.hw_y += 2;
  140. if(self->_cyanEdgeImageView.hw_h - self->_qrCodeScanLine.hw_y <= 5){
  141. isDownType22 = NO;
  142. }
  143. }
  144. else if(!isDownType22 && self->_qrCodeScanLine.hw_y >= 0)
  145. {
  146. self->_qrCodeScanLine.hw_y -= 2;
  147. if(self->_qrCodeScanLine.hw_y <= 5){
  148. isDownType22 = YES;
  149. }
  150. }
  151. }];
  152. }
  153. //实现扫描的回调代理方法
  154. - (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputMetadataObjects:(NSArray*)metadataObjects fromConnection:(AVCaptureConnection*)connection{
  155. //如果数组metadataObjects中有数据,metadataObjects是个数组类型
  156. if(metadataObjects.count>0) {
  157. AVMetadataMachineReadableCodeObject*object = [metadataObjects lastObject];
  158. NSLog(@"%@",object.stringValue);
  159. /*扫描到有用信息时取消扫描*/
  160. NSString *resStr = object.stringValue;//RK3908P1V62112465
  161. if(resStr.length > 22)
  162. {
  163. NSString*desStr = [RSATool AES128Decrypt:resStr key:AESCODEKEEYY];
  164. if(desStr){//能解码
  165. resStr = desStr;
  166. }
  167. }
  168. //Ch0IKJCY9lOgokjfPBFE1cowdC1+tj7ywB2pZgSzjhc=
  169. //sgl5OzDoVjY5SmGuL50/EnQ4n6Kw+DzRiE1oUjq7yAM=
  170. if (([resStr containsString:@"RK"] && (resStr.length == @"RK3908P1V62112465".length))
  171. || resStr.length == @"0333933700223250017273".length
  172. ){
  173. NSDictionary *deviceDict = [HWDataManager getObjectWithKey:Const_Have_Add_Device];
  174. if (!deviceDict || [[deviceDict allKeys] containsObject:Const_Have_Add_Device_SN]){
  175. NSString *oldStr = deviceDict[Const_Have_Add_Device_SN];
  176. if([oldStr isEqualToString:resStr]){
  177. [[iToast makeText:NSLocalizedString(@"guide_qrcoede_tips_change_same",nil)] show];
  178. //停止扫描
  179. [self.session stopRunning];
  180. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  181. [self.session startRunning];
  182. });
  183. return;
  184. }
  185. }
  186. //[[iToast makeText:NSLocalizedString(@"guide_qrcoede_tips_ok",nil)] show];
  187. [_scanLineTimer invalidate];
  188. //停止扫描
  189. [self.session stopRunning];
  190. //移除扫描层layer
  191. [self.layer removeFromSuperlayer];
  192. // for (UIViewController *vc in [self.navigationController viewControllers]) {
  193. // if ([vc isKindOfClass:[MySetViewController class]]){
  194. // [self.navigationController popToViewController:vc animated:YES];
  195. // break;
  196. // }
  197. // }
  198. [self showNewIndicatorHaveStrWithCanBack:NO canTouch:NO showText:NSLocalizedString(@"guide_qrcoede_tips_ok",nil)];
  199. [[connectDeviceManager shareInstance] getThridMsgBySN:resStr needReconnect:YES didNetEnd:^(bool didSuc) {
  200. [self removeNewIndicatorHaveStr];
  201. if(didSuc){
  202. NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:deviceDict];
  203. [dict setObject:resStr forKey:Const_Have_Add_Device_SN];
  204. [HWDataManager setObjectWithKey:Const_Have_Add_Device value:dict];
  205. [[NSNotificationCenter defaultCenter] postNotificationName:GuideOkNotification object:nil];
  206. }else{
  207. [[iToast makeText:NSLocalizedString(@"guide_qrcoede_tips_get_SdnID_fail",nil)] show];
  208. [self.navigationController popViewControllerAnimated:YES];
  209. }
  210. }];
  211. }
  212. }else{
  213. //[[iToast makeText:NSLocalizedString(@"guide_qrcoede_tips_error",nil)] show];
  214. NSLog(@"没有扫描到数据");
  215. }
  216. }
  217. //光感传感器代理
  218. -(void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection{
  219. //获取光线的值
  220. CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,sampleBuffer, kCMAttachmentMode_ShouldPropagate);
  221. NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
  222. CFRelease(metadataDict);
  223. NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
  224. float brightnessValue = [[exifMetadata objectForKey:(NSString*)kCGImagePropertyExifBrightnessValue]floatValue];
  225. NSLog(@"%f",brightnessValue);
  226. // 根据brightnessValue的值来打开和关闭闪光灯,一般值小于0就需要打开,大于0就关闭
  227. // if((brightnessValue <0)) {//显示闪光灯
  228. // self.lightBtn.hidden=NO;
  229. // }else if((brightnessValue >0)) {//隐藏闪光灯
  230. // self.lightBtn.hidden=YES;
  231. // }
  232. }
  233. ////闪光灯按钮点击方法
  234. //
  235. //-(void)lightBtnClick:(UIButton*)sender{
  236. // //判断当前设备是否有闪光灯
  237. //
  238. // AVCaptureDevice * device=[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  239. //
  240. // BOOL result=[device hasTorch];
  241. //
  242. // if(result==YES){
  243. // if(self.lightBtn.isSelected==NO){
  244. // self.lightBtn.selected=YES;
  245. // self.lightBtn.backgroundColor=[UIColor greenColor];
  246. // [device lockForConfiguration:nil];
  247. // [device setTorchMode: AVCaptureTorchModeOn];//开
  248. // [device unlockForConfiguration];
  249. // }else if(self.lightBtn.isSelected==YES){
  250. // self.lightBtn.selected=NO;
  251. // self.lightBtn.backgroundColor=[UIColor grayColor];
  252. // [device lockForConfiguration:nil];
  253. // [device setTorchMode: AVCaptureTorchModeOff];//关
  254. // [device unlockForConfiguration];
  255. // }
  256. // }else{
  257. // NSLog(@"当前设备闪光灯不可用");
  258. // }
  259. //}
  260. //
  261. ////获取相册图片btn点击方法
  262. //
  263. //-(void)photoBtnClick:(UIButton*)sender{
  264. // UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
  265. // imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
  266. // // imagePicker.allowsEditing = YES;
  267. // imagePicker.delegate=self;
  268. // [self.navigationController presentViewController:imagePicker animated:YES completion:nil];
  269. //}
  270. //UIImagePickerControllerDelegate选择图片的回调
  271. -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
  272. //把UIimage类型转换成CIimage类型
  273. UIImage *pickedImage = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];
  274. CIImage*detectImage = [CIImage imageWithData:UIImagePNGRepresentation(pickedImage)];
  275. //解析扫描二维码结果字符串
  276. CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
  277. CIQRCodeFeature*feature = (CIQRCodeFeature*)[detector featuresInImage:detectImage options:nil].firstObject;
  278. [picker dismissViewControllerAnimated:YES completion:^{
  279. if(feature.messageString) {
  280. NSLog(@"=================二维码结果为%@",feature.messageString);
  281. }else{
  282. NSLog(@"未扫描到相应二维码");
  283. }
  284. //停止会话对象扫描
  285. [self.session stopRunning];
  286. //移除扫描层layer
  287. [self.layer removeFromSuperlayer];
  288. }];
  289. }
  290. @end