原生二維碼掃描
#define QRCodeWidth 260.0 //正方形二維碼的邊長
#define SCREENWidth [UIScreen mainScreen].bounds.size.width
#define SCREENHeight [UIScreen mainScreen].bounds.size.height
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property (strong,nonatomic)AVCaptureDevice * device;
@property (strong,nonatomic)AVCaptureDeviceInput * input;
@property (strong,nonatomic)AVCaptureMetadataOutput * output;
@property (strong,nonatomic)AVCaptureSession * session;
@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;
@end
- (void)viewDidLoad {
[super viewDidLoad];
[self setupMaskView];//設(shè)置掃描區(qū)域之外的陰影視圖
[self setupScanWindowView];//設(shè)置掃描二維碼區(qū)域的視圖
[self beginScanning];//開始掃二維碼
}
2-1 設(shè)置掃描區(qū)域之外的陰影視圖
- (void)setupMaskView
{
//設(shè)置統(tǒng)一的視圖顏色和視圖的透明度
UIColor *color = [UIColor blackColor];
float alpha = 0.7;
//設(shè)置掃描區(qū)域外部上部的視圖
UIView *topView = [[UIView alloc]init];
topView.frame = CGRectMake(0, 64, SCREENWidth, (SCREENHeight-64-QRCodeWidth)/2.0-64);
topView.backgroundColor = color;
topView.alpha = alpha;
//設(shè)置掃描區(qū)域外部左邊的視圖
UIView *leftView = [[UIView alloc]init];
leftView.frame = CGRectMake(0, 64+topView.frame.size.height, (SCREENWidth-QRCodeWidth)/2.0,QRCodeWidth);
leftView.backgroundColor = color;
leftView.alpha = alpha;
//設(shè)置掃描區(qū)域外部右邊的視圖
UIView *rightView = [[UIView alloc]init];
rightView.frame = CGRectMake((SCREENWidth-QRCodeWidth)/2.0+QRCodeWidth,64+topView.frame.size.height, (SCREENWidth-QRCodeWidth)/2.0,QRCodeWidth);
rightView.backgroundColor = color;
rightView.alpha = alpha;
//設(shè)置掃描區(qū)域外部底部的視圖
UIView *botView = [[UIView alloc]init];
botView.frame = CGRectMake(0, 64+QRCodeWidth+topView.frame.size.height,SCREENWidth,SCREENHeight-64-QRCodeWidth-topView.frame.size.height);
botView.backgroundColor = color;
botView.alpha = alpha;
//將設(shè)置好的掃描二維碼區(qū)域之外的視圖添加到視圖圖層上
[self.view addSubview:topView];
[self.view addSubview:leftView];
[self.view addSubview:rightView];
[self.view addSubview:botView];
}
2-2 設(shè)置掃描二維碼區(qū)域的視圖
- (void)setupScanWindowView
{
//設(shè)置掃描區(qū)域的位置(考慮導航欄和電池條的高度為64)
UIView *scanWindow = [[UIView alloc]initWithFrame:CGRectMake((SCREENWidth-QRCodeWidth)/2.0,(SCREENHeight-QRCodeWidth-64)/2.0,QRCodeWidth,QRCodeWidth)];
scanWindow.clipsToBounds = YES;
[self.view addSubview:scanWindow];
//設(shè)置掃描區(qū)域的動畫效果
CGFloat scanNetImageViewH = 241;
CGFloat scanNetImageViewW = scanWindow.frame.size.width;
UIImageView *scanNetImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"scan_net"]];
scanNetImageView.frame = CGRectMake(0, -scanNetImageViewH, scanNetImageViewW, scanNetImageViewH);
CABasicAnimation *scanNetAnimation = [CABasicAnimation animation];
scanNetAnimation.keyPath =@"transform.translation.y";
scanNetAnimation.byValue = @(QRCodeWidth);
scanNetAnimation.duration = 1.0;
scanNetAnimation.repeatCount = MAXFLOAT;
[scanNetImageView.layer addAnimation:scanNetAnimation forKey:nil];
[scanWindow addSubview:scanNetImageView];
//設(shè)置掃描區(qū)域的四個角的邊框
CGFloat buttonWH = 18;
UIButton *topLeft = [[UIButton alloc]initWithFrame:CGRectMake(0,0, buttonWH, buttonWH)];
[topLeft setImage:[UIImage imageNamed:@"scan_1"]forState:UIControlStateNormal];
[scanWindow addSubview:topLeft];
UIButton *topRight = [[UIButton alloc]initWithFrame:CGRectMake(QRCodeWidth - buttonWH,0, buttonWH, buttonWH)];
[topRight setImage:[UIImage imageNamed:@"scan_2"]forState:UIControlStateNormal];
[scanWindow addSubview:topRight];
UIButton *bottomLeft = [[UIButton alloc]initWithFrame:CGRectMake(0,QRCodeWidth - buttonWH, buttonWH, buttonWH)];
[bottomLeft setImage:[UIImage imageNamed:@"scan_3"]forState:UIControlStateNormal];
[scanWindow addSubview:bottomLeft];
UIButton *bottomRight = [[UIButton alloc]initWithFrame:CGRectMake(QRCodeWidth-buttonWH,QRCodeWidth-buttonWH, buttonWH, buttonWH)];
[bottomRight setImage:[UIImage imageNamed:@"scan_4"]forState:UIControlStateNormal];
[scanWindow addSubview:bottomRight];
}
2-3 開始掃二維碼
-(void)beginScanning
{
//獲取攝像設(shè)備
AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//創(chuàng)建輸入流
AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
if (!input) return;
//創(chuàng)建輸出流
AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
//特別注意的地方:有效的掃描區(qū)域困介,定位是以設(shè)置的右頂點為原點。屏幕寬所在的那條線為y軸蘸际,屏幕高所在的線為x軸
CGFloat x = ((SCREENHeight-QRCodeWidth-64)/2.0)/SCREENHeight;
CGFloat y = ((SCREENWidth-QRCodeWidth)/2.0)/SCREENWidth;
CGFloat width = QRCodeWidth/SCREENHeight;
CGFloat height = QRCodeWidth/SCREENWidth;
output.rectOfInterest = CGRectMake(x, y, width, height);
//設(shè)置代理在主線程里刷新
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//初始化鏈接對象
_session = [[AVCaptureSession alloc]init];
//高質(zhì)量采集率
[_session setSessionPreset:AVCaptureSessionPresetHigh];
[_session addInput:input];
[_session addOutput:output];
//設(shè)置掃碼支持的編碼格式(如下設(shè)置條形碼和二維碼兼容)
output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code];
AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
layer.frame=self.view.layer.bounds;
[self.view.layer insertSublayer:layer atIndex:0];
//開始捕獲
[_session startRunning];
}
3.遵守協(xié)議
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
NSString *stringValue;
if (metadataObjects.count >0) {
//停止掃描
[self.session stopRunning];
AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
stringValue = metadataObject.stringValue;
[_session stopRunning];
}else
{
NSLog(@"沒數(shù)據(jù)");
}
}
5.若是報錯 -This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
是因為沒開啟相機權(quán)限
解決方法:
將info.plist文件以Source Code打開 (右鍵 選擇Open As)
復制粘貼下面 key value即可
<key>NSCameraUsageDescription</key>
<string>cameraDesciption</string>
celan 運行