公司最近要添加一個二維碼掃描網頁登錄的功能,所以最近研究了一下iOS關于二維碼掃描的功能
因為移動端不涉及二維碼的生成,所以只做關于二維碼的掃描(這里感謝一下SGQRCode的作者)
5301663-fab2e80855a3ef4b.jpg
攝像頭掃描二維碼
用攝像頭掃描二維碼就需要我們剛才說的AVCaptureSession,具體怎么實現,我們來看demo。
框架
首先導入我們要用到的框架,因為掃描和識別都是在系統AVFoundation下的做的,所以第一步就要把框架主頭文件導入 #import <AVFoundation/AVFoundation.h>
頭文件
/** 回話對象屬性*/
@property (nonatomic, strong) AVCaptureSession *session;
/** 攝像頭預覽圖層*/
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
實現部分
// 創建回話對象
self.session = [[AVCaptureSession alloc] init];
// 設置回話對象圖像采集率
[self.session setSessionPreset:AVCaptureSessionPresetHigh];
// 獲取攝像頭設備
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 創建回話輸入對象
NSError *inputError = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&inputError];
// 添加會話輸入
[self.session addInput:input];
// 創建輸出對象
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 設置輸出對象代理
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 添加會話輸出
[self.session addOutput:output];
// 設置輸出數據類型,需要將元數據輸出添加到回話后,才能制定元數據,否則會報錯
// 二維碼和條形碼可以一起設置
output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
// 創建攝像頭預覽圖層
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.previewLayer.frame = self.view.frame;
// 將圖層插入當前圖層
[self.view.layer insertSublayer:self.previewLayer atIndex:0];
// 啟動會話
[self.session startRunning];
主體方法實現了以后,我們來看一下AVCaptureMetadataOutputObjectsDelegate方法- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection;,當二維碼掃描成功之后,系統將自動調用這個代理方法。
AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// 1、如果掃描完成,停止會話
[self.session stopRunning];
// 2、刪除預覽圖層
[self.previewLayer removeFromSuperlayer];
// 3、設置界面顯示掃描結果
if (metadataObjects && metadataObjects.count > 0) {
// 播放音效
NSString *audioFile = [[NSBundle mainBundle] pathForResource:@"sound" ofType:@"wav"];
NSURL *fileUrl = [NSURL fileURLWithPath:audioFile];
SystemSoundID soundID = 0;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID);
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);
AudioServicesPlaySystemSound(soundID); // 播放音效
AVMetadataMachineReadableCodeObject *obj = metadataObjects.firstObject;
// 取出二維碼掃描到的內容
NSLog(@"二維碼內容:::%@",obj.stringValue);
}
}
// 播放音效成功回調
void soundCompleteCallback (){
}
如果想監聽設備攝像頭實時的視頻流就將會話輸出對象添加AVCaptureVideoDataOutputSampleBufferDelegate代理監聽實現- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;代理方法
AVCaptureVideoDataOutputSampleBufferDelegate
[output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
實現方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
// 這個方法會時時調用,但內存很穩定
CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,sampleBuffer, kCMAttachmentMode_ShouldPropagate);
NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
CFRelease(metadataDict);
NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];
NSLog(@"%f",brightnessValue);
}