直接上项目代码
首先检查相机权限 AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (status == AVAuthorizationStatusRestricted || status == AVAuthorizationStatusDenied) { // 没有授权访问相机权限 提示 return; } #import "QrCodeVC.h" #import <AVFoundation/AVFoundation.h> #import <Masonry/Masonry.h> #import <pop/POP.h> #import "AppDelegate.h" #import "GoodsDetailVC.h" #import "WebViewVC.h" #define QRWH (ZKScreenW*283/375.0) #define TOP (ZKScreenH-QRWH)/2.0 #define LEFT (ZKScreenW-QRWH)/2.0 #define kScanRect CGRectMake(LEFT, TOP, QRWH, QRWH) #define kLineRect CGRectMake(LEFT+15, TOP, QRWH-30, 3) const static CGFloat animationTime = 2.0f;//扫描时长 @interface QrCodeVC () <AVCaptureMetadataOutputObjectsDelegate> { CAShapeLayer *cropLayer; } @property (nonatomic, strong) AVCaptureDevice *device; @property (nonatomic, strong) AVCaptureDeviceInput *input; @property (nonatomic, strong) AVCaptureMetadataOutput *output; @property (nonatomic, strong) AVCaptureSession *session; @property (nonatomic, strong) AVCaptureVideoPreviewLayer *preview; /** 二维码View **/ @property (nonatomic, strong) UIImageView *qrImageView; @property (nonatomic, strong) UIImageView *animationImageV; @property (nonatomic, assign) BOOL animationUp; @property (nonatomic, strong) UILabel *messageLb; @end @implementation QrCodeVC - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (_session != nil) { [_session startRunning]; } self.animationImageV.hidden = NO; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // if (_session != nil) { // [_session stopRunning]; // } self.animationImageV.hidden = YES; } - (void)viewDidLoad { [super viewDidLoad]; // 初始化扫描UI [self initView]; // 初始化扫描二维码 [self setupCamera]; } - (void)initView { UIView *bgView = [[UIView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:bgView]; bgView.backgroundColor = [UIColor clearColor]; cropLayer = [[CAShapeLayer alloc] init]; CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, nil, kScanRect); CGPathAddRect(path, nil, self.view.bounds); [cropLayer setFillRule:kCAFillRuleEvenOdd]; [cropLayer setPath:path]; [cropLayer setFillColor:[[UIColor blackColor] colorWithAlphaComponent:0.3].CGColor]; [cropLayer setNeedsDisplay]; [bgView.layer addSublayer:cropLayer]; UIImageView *imageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"qrCode_bg"]]; imageV.frame = kScanRect; [self.view addSubview:imageV]; _qrImageView = imageV; UIImageView *animationImageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"qrCodeLine"]]; animationImageV.frame = kLineRect; animationImageV.contentMode = UIViewContentModeScaleAspectFill; [self.view addSubview:animationImageV]; _animationImageV = animationImageV; UILabel *messageLb = [[UILabel alloc] initWithFrame:CGRectMake(15, TOP-40, ZKScreenW-30, 20)]; messageLb.text = getStringByKey(@"string_key_1592"); messageLb.textAlignment = NSTextAlignmentCenter; messageLb.numberOfLines = 0; messageLb.font = [UIFont boldSystemFontOfSize:14]; messageLb.textColor = [UIColor whiteColor]; [self.view addSubview:messageLb]; UILabel *titleLb = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, ZKScreenW, 20)]; titleLb.text = getStringByKey(@"string_key_1593"); titleLb.textAlignment = NSTextAlignmentCenter; titleLb.font = [UIFont boldSystemFontOfSize:17]; titleLb.textColor = [UIColor whiteColor]; [self.view addSubview:titleLb]; UIButton *backBtn = [[UIButton alloc] init]; [backBtn setImage:[UIImage imageNamed:@"video_wirteBackArrow"] forState:UIControlStateNormal]; [backBtn addTarget:self action:@selector(clickBackBtn) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:backBtn]; [backBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.view.mas_top).with.offset(20); make.leading.equalTo(self.view.mas_leading); make.width.mas_equalTo(44); make.height.mas_equalTo(44); }]; } - (void)clickBackBtn { [self.navigationController popViewControllerAnimated:YES]; } - (CABasicAnimation *)qrAnimation { CGPoint starPoint = CGPointMake(_qrImageView.centerX , _qrImageView.mj_y+3); CGPoint endPoint = CGPointMake(_qrImageView.centerX, _qrImageView.mj_y+QRWH-3); CABasicAnimation*translation = [CABasicAnimation animationWithKeyPath:@"position"]; translation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; translation.fromValue = [NSValue valueWithCGPoint:starPoint]; translation.toValue = [NSValue valueWithCGPoint:endPoint]; translation.duration = animationTime; translation.repeatCount = CGFLOAT_MAX; translation.autoreverses = YES; translation.removedOnCompletion = NO; return translation; } - (void)setupCamera { AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if (device==nil) { // 设备没有摄像头 // UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"设备没有摄像头" preferredStyle:UIAlertControllerStyleAlert]; // [alert addAction:[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // // }]]; // [self presentViewController:alert animated:YES completion:nil]; return; } _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; _output = [[AVCaptureMetadataOutput alloc]init]; [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; //设置扫描区域 CGFloat top = TOP/ZKScreenH; CGFloat left = LEFT/ZKScreenW; CGFloat width = QRWH/ZKScreenW; CGFloat height = QRWH/ZKScreenH; ///top 与 left 互换 width 与 height 互换 [_output setRectOfInterest:CGRectMake(top,left, height, width)]; // Session _session = [[AVCaptureSession alloc]init]; [_session setSessionPreset:AVCaptureSessionPresetHigh]; if ([_session canAddInput:self.input]) { [_session addInput:self.input]; } if ([_session canAddOutput:self.output]) { [_session addOutput:self.output]; } // 条码类型 AVMetadataObjectTypeQRCode [_output setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeQRCode, nil]]; // Preview _preview =[AVCaptureVideoPreviewLayer layerWithSession:_session]; _preview.videoGravity = AVLayerVideoGravityResizeAspectFill; _preview.frame =self.view.layer.bounds; [self.view.layer insertSublayer:_preview atIndex:0]; [_session startRunning]; [_animationImageV.layer addAnimation:[self qrAnimation] forKey:nil]; } #pragma mark AVCaptureMetadataOutputObjectsDelegate - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { NSString *stringValue; if ([metadataObjects count] >0) { //停止扫描 [_session stopRunning]; AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0]; stringValue = metadataObject.stringValue; if (stringValue.length > 0) { if ([stringValue containsString:@"sheinlink://applink/"]) { // 调用deeplink跳转页面 AppDelegate *appDelegate=(AppDelegate*)[UIApplication sharedApplication].delegate; [appDelegate openWithUrl:[NSURL URLWithString:stringValue]]; } else if ([stringValue containsString:@"toApp"] && [stringValue containsString:@"goods_id="]) { // 商品详情 NSRange sizeRange= [stringValue rangeOfString:@"goods_id="]; NSString *goodsId = [stringValue substringFromIndex:sizeRange.location+@"goods_id=".length]; if (goodsId) { GoodsInfo *goodsInfo=[[GoodsInfo alloc] init]; goodsInfo.goods_id=[goodsId intValue]; UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Goods" bundle:[NSBundle mainBundle]]; GoodsDetailVC *vc=[sb instantiateViewControllerWithIdentifier:@"GoodsDetailVC"]; vc.goodsInfo=goodsInfo; [self.navigationController pushViewController:vc animated:YES]; } } else { // 跳转到普通网页 UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Setting" bundle:[NSBundle mainBundle]]; WebViewVC *vc=[sb instantiateViewControllerWithIdentifier:@"WebViewVC"]; vc.titleText = @""; vc.url = stringValue; [self.navigationController pushViewController:vc animated:YES]; } } else { // 没有获取到url } } else { NSLog(@"无扫描信息"); return; } }