二維碼廣泛應用於支付、登錄、分享等場景。iOS 原生框架 CoreImage(生成)與 AVFoundation(掃描)提供了高效、零依賴的實現方案。本文詳解兩大核心流程及關鍵代碼。
<CoreImage/CoreImage.h>CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];[filter setDefaults];NSData (UTF-8),通過 KVO 設置 inputMessageCIImageUIImageCIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[filter setDefaults];
NSString *str = @"這是一個二維碼生成結果";
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
[filter setValue:data forKey:@"inputMessage"];
CIImage *outputImage = [filter outputImage];
self.imageView.image = [UIImage imageWithCIImage:outputImage];
默認輸出較小,需按比例放大並關閉插值:
- (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat)size {
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size / CGRectGetWidth(extent), size / CGRectGetHeight(extent));
size_t width = CGRectGetWidth(extent) * scale;
size_t height = CGRectGetHeight(extent) * scale;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, kCGImageAlphaNone);
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
CGContextScaleCTM(bitmapRef, scale, scale);
CGContextDrawImage(bitmapRef, extent, bitmapImage);
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
CGContextRelease(bitmapRef);
CGImageRelease(bitmapImage);
return [UIImage imageWithCGImage:scaledImage];
}
調用:UIImage *hdQR = [self createNonInterpolatedUIImageFormCIImage:outputImage withSize:300];
NSString *url = @"https://www.baidu.com"; // 必須帶 https:// 或 https://
// 生成的二維碼掃描後系統會提示打開瀏覽器
AVCaptureSessionAVCaptureDevice (後置鏡頭) → AVCaptureDeviceInputAVCaptureMetadataOutput,設置代理、隊列、元數據類型 AVMetadataObjectTypeQRCodeAVCaptureVideoPreviewLayer 關聯 session,加到 view[session startRunning]captureOutput:didOutputMetadataObjects:fromConnection: 獲取掃描結果@interface ViewController () <AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *layer;
@property (nonatomic, strong) AVCaptureSession *session;
@end
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
AVCaptureSession *session = [[AVCaptureSession alloc] init];
self.session = session;
// 輸入
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
[session addInput:input];
// 輸出
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[session addOutput:output];
[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
// 預覽圖層
AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:session];
layer.frame = self.view.bounds;
[self.view.layer addSublayer:layer];
self.layer = layer;
[session startRunning];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputMetadataObjects:(NSArray *)metadataObjects
fromConnection:(AVCaptureConnection *)connection {
if (metadataObjects.count > 0) {
AVMetadataMachineReadableCodeObject *obj = metadataObjects.lastObject;
NSLog(@"掃描結果: %@", obj.stringValue);
[self.session stopRunning];
[self.layer removeFromSuperlayer];
} else {
NSLog(@"未掃描到數據");
}
}
AVCaptureVideoPreviewLayer 上疊加半透明遮罩 + 掃描線動畫,提升用戶體驗。output.rectOfInterest(歸一化坐標),減少計算量、提高速度。[device lockForConfiguration:nil]; device.torchMode = AVCaptureTorchModeOn; [device unlockForConfiguration];NSCameraUsageDescription,首次掃描前檢查授權狀態。CGContextDrawImage 在中心繪製 Logo,注意 Logo 佔比不超 20% 且留白邊距。iOS 原生框架已足夠強大:CoreImage 生成 + AVFoundation 掃描,無需引入三方庫即可滿足 90%+ 業務場景。掌握高清渲染、掃描區域限制、權限適配等細節,即可構建生產級二維碼功能。