二维码扫描
来源:互联网 发布:js动态添加a标签 编辑:程序博客网 时间:2024/04/30 15:49
本文中我们介绍一下如何在iOS平台实现二维码扫描,我们可以借助一些优秀的第三方库,比如ZBar SDK和ZXing。在iOS7.0之后,我们也可以使用iOS系统原生扫描,通过AVFoundation框架来实现二维码扫描,不过AVFoundation框架不能识别相册中的二维码图片。
1. 通过AVFoundation框架识别二维码
1.1 AVFoundation框架扫描二维码的基本方法
我们先来介绍一下如何使用AVFoundation框架实现二维码扫描。在iOS7之后,苹果自身提供了二维码的扫描功能,从效率上来说,原生的二维码远高于这些第三方框架。之前我们使用AVFoundation框架实现过拍照功能,基本的原理差不多类似;需要AVCaptureSession对象管理输入流和输出流;需要一个AVCaptureVideoPreviewLayer对象来显示信息。基本流程如下:
图中涉及到的几个相关类的说明如下:
- AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
- AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
- AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
- AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
- AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。
下面我们看一下具体的实现步骤:
示例代码:
#import "ViewController.h"#import <AVFoundation/AVFoundation.h>@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>@property (weak, nonatomic) IBOutlet UISwitch *lightSwitch;// 闪光开关@property (nonatomic) AVCaptureSession *captureSession;//捕获的管理会话@property (nonatomic) AVCaptureVideoPreviewLayer *previewLayer;// 预览图层@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad];}// 开始二维码扫描- (IBAction)startScan:(UIButton *)sender { // 1. 初始化捕获会话,并添加输入对象 self.captureSession = [[AVCaptureSession alloc] init]; // 2. 初始化捕获设备对象AVCaptureDevice AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; // 3. 初始化捕获设备的输入对象AVCaptureDeviceInput AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; if (input == nil) { NSLog(@"输入对象初始化失败"); return; } // 将输入对象添加到会话 [self.captureSession addInput:input]; // 4. 初始化输出对象AVCaptureMetadataOutput AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; // 将输出对象添加到会话 [self.captureSession addOutput:output]; // 设置输出对象源数据类型:AVMetadataObjectTypeQRCode条码类型 [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; // 设置输出对象代理,并实现代理方法 [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; // 设置扫码区域为预览区域 默认全屏扫描 CGFloat w = self.view.frame.size.width; CGFloat h = self.view.frame.size.height; // rectOfInterest属性:区域大小是相对于设备的大小的,默认值是(0, 0, 1, 1)。但是区域的坐标系统X和Y是互换的,同时,宽高的比例也互换了。 [output setRectOfInterest:CGRectMake((h/2 -100)/h, (w/2 -100)/w, 200/h, 200/w)]; NSLog(@"%@",NSStringFromCGRect(output.rectOfInterest)); // 5. 初始化预览图层 self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;// 拉伸属性 self.previewLayer.frame = self.view.bounds; [self.view.layer addSublayer:self.previewLayer]; // 6.开始会话 [self.captureSession startRunning]; // 关闭闪光灯 self.lightSwitch.on = NO; [self.view bringSubviewToFront:self.lightSwitch];}#pragma mark -#pragma mark - AVCaptureMetadataOutputObjectsDelegate// 此方法是在识别到QRCode,并且完成转换。如果QRCode的内容越大,转换需要的时间就越长- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { if (metadataObjects != nil && [metadataObjects count] > 0) { // 扫码成功 停止扫描, [self.captureSession stopRunning]; // 获取扫码结果: AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0]; NSString *result; if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) { result = metadataObj.stringValue; NSLog(@"%@",result); } else { NSLog(@"不是二维码"); } }}#pragma mark -#pragma mark - 开启闪光灯- (IBAction)lightOpenOrClose:(UISwitch *)sender { BOOL isOpen = sender.on; // 获取设备 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if ([device hasTorch]) { [device lockForConfiguration:nil]; if (isOpen) { [device setTorchMode:AVCaptureTorchModeOn]; } else { [device setTorchMode:AVCaptureTorchModeOff]; } [device unlockForConfiguration]; }}@end
1.2 AVFoundation框架扫描二维码的功能封装
上面是系统自带的二维码扫描的基本功能实现,下面我们来实现一下在实际开发中二维码扫描的实际效果,不过就是添加了一条扫描的线条。
示例代码:
Scan2CodeViewController.h
#import <UIKit/UIKit.h>@protocol ScanImageViewDelegate<NSObject>- (void)reportScanResult:(NSString *)result;@end@interface Scan2CodeViewController : UIViewController@property (nonatomic,weak)id <ScanImageViewDelegate>delegate;//代理方法传递数据@end示例代码:Scan2CodeViewController.m#import "Scan2CodeViewController.h"#import <AVFoundation/AVFoundation.h>#define SCANVIEW_EdgeTop 70.0#define SCANVIEW_EdgeLeft 50.0#define TINTCOLOR_ALPHA 0.2 //浅色透明度#define DARKCOLOR_ALPHA 0.3 //深色透明度#define VIEW_WIDTH [UIScreen mainScreen].bounds.size.width#define VIEW_HEIGHT [UIScreen mainScreen].bounds.size.heightstatic const char *kScanQRCodeQueueName = "ScanQRCodeQueue";@interface Scan2CodeViewController () <AVCaptureMetadataOutputObjectsDelegate>{ //设置扫描画面 UIView *_scanView; NSTimer *_timer; UIView *_QrCodeline; UIView *_QrCodeline1; UIImageView *_scanCropView;//扫描窗口 UIButton *_lightButton;//灯光按钮 AVCaptureSession *_captureSession; AVCaptureVideoPreviewLayer *_videoPreviewLayer;}@end@implementation Scan2CodeViewController- (void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [self stopTimer];}- (void)viewDidLoad { [super viewDidLoad]; //初始化扫描界面 [self setScanView]; // 开始扫描 [self startReading]; //启动定时器 [self createTimer];}- (BOOL)startReading{ // 获取 AVCaptureDevice 实例 NSError * error; AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; // 初始化输入流 AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error]; if (!input) { NSLog(@"%@", [error localizedDescription]); return NO; } // 创建会话 _captureSession = [[AVCaptureSession alloc] init]; //提高图片质量为1080P,提高识别效果 _captureSession.sessionPreset = AVCaptureSessionPreset1920x1080; // 添加输入流 [_captureSession addInput:input]; // 初始化输出流 AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init]; //设置扫描范围 captureMetadataOutput.rectOfInterest =CGRectMake((_scanCropView.frame.origin.y-10)/VIEW_HEIGHT, (_scanCropView.frame.origin.x-10)/VIEW_WIDTH, (_scanCropView.frame.size.width+10)/VIEW_HEIGHT, (_scanCropView.frame.size.height+10)/VIEW_WIDTH); // 添加输出流 [_captureSession addOutput:captureMetadataOutput]; // 创建dispatch queue. dispatch_queue_t dispatchQueue; dispatchQueue = dispatch_queue_create(kScanQRCodeQueueName, NULL); [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue]; // 设置元数据类型 AVMetadataObjectTypeQRCode [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]]; // 创建输出对象 _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession]; [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; [_videoPreviewLayer setFrame:_scanView.layer.bounds]; [_scanView.layer insertSublayer:_videoPreviewLayer atIndex:0]; // 开始会话 [_captureSession startRunning]; return YES;}- (void)stopReading{ // 停止会话 [_captureSession stopRunning]; _captureSession = nil;}#pragma mark -#pragma mark - AVCaptureMetadataOutputObjectsDelegate-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{ if (metadataObjects != nil && [metadataObjects count] > 0) { AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0]; NSString *result; if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) { result = metadataObj.stringValue; } else { NSLog(@"不是二维码"); } //调用代理对象的协议方法来实现数据传递 [self dismissViewControllerAnimated:YES completion:nil]; dispatch_async(dispatch_get_main_queue(), ^{ if ([self.delegate respondsToSelector:@selector(reportScanResult:)]) { [self.delegate reportScanResult:result]; } }); [self stopReading]; } return;}- (void)createTimer{ _timer=[NSTimer scheduledTimerWithTimeInterval:2.2 target:self selector:@selector(moveUpAndDownLine) userInfo:nil repeats:YES];}- (void)stopTimer{ if ([_timer isValid] == YES) { [_timer invalidate]; _timer = nil; }}// 二维码的扫描区域- (void)setScanView{ _scanView=[[UIView alloc] initWithFrame:CGRectMake(0,0, VIEW_WIDTH,VIEW_HEIGHT )]; _scanView.backgroundColor=[UIColor clearColor]; [self.view addSubview:_scanView]; //最上部view UIView *upView = [[UIView alloc] initWithFrame:CGRectMake(0,0, VIEW_WIDTH,SCANVIEW_EdgeTop)]; upView.alpha =TINTCOLOR_ALPHA; upView.backgroundColor = [UIColor blackColor]; [_scanView addSubview:upView]; //左侧的view UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, SCANVIEW_EdgeTop, SCANVIEW_EdgeLeft,VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft)]; leftView.alpha =TINTCOLOR_ALPHA; leftView.backgroundColor = [UIColor blackColor]; [_scanView addSubview:leftView]; // 中间扫描区 _scanCropView=[[UIImageView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft,SCANVIEW_EdgeTop, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft)]; //scanCropView.image=[UIImage imageNamed:@""]; _scanCropView.layer.borderColor=[UIColor greenColor].CGColor; _scanCropView.layer.borderWidth=2.0; _scanCropView.backgroundColor=[UIColor clearColor]; [_scanView addSubview:_scanCropView]; //右侧的view UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(VIEW_WIDTH - SCANVIEW_EdgeLeft,SCANVIEW_EdgeTop, SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft)]; rightView.alpha =TINTCOLOR_ALPHA; rightView.backgroundColor = [UIColor blackColor]; [_scanView addSubview:rightView]; //底部view UIView *downView = [[UIView alloc] initWithFrame:CGRectMake(0, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop, VIEW_WIDTH, VIEW_HEIGHT - (VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop))]; //downView.alpha = TINTCOLOR_ALPHA; downView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:TINTCOLOR_ALPHA]; [_scanView addSubview:downView]; //用于说明的label UILabel *labIntroudction= [[UILabel alloc] init]; labIntroudction.backgroundColor = [UIColor clearColor]; labIntroudction.frame=CGRectMake(0,5, VIEW_WIDTH,20); labIntroudction.numberOfLines=1; labIntroudction.font=[UIFont systemFontOfSize:15.0]; labIntroudction.textAlignment=NSTextAlignmentCenter; labIntroudction.textColor=[UIColor whiteColor]; labIntroudction.text=@"将二维码对准方框,即可自动扫描"; [downView addSubview:labIntroudction]; //取消button UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeCustom]; cancelButton.backgroundColor =[[UIColor blackColor] colorWithAlphaComponent:DARKCOLOR_ALPHA]; cancelButton.frame =CGRectMake(0, 90, VIEW_WIDTH, 40); cancelButton.titleLabel.font =[UIFont systemFontOfSize:15.0]; cancelButton.titleLabel.textAlignment = NSTextAlignmentCenter; [cancelButton setTitle:@"取消" forState:UIControlStateNormal]; [cancelButton addTarget:self action:@selector(cancelAction) forControlEvents:UIControlEventTouchUpInside]; [downView addSubview:cancelButton]; //用于开关灯操作的button _lightButton = [UIButton buttonWithType:UIButtonTypeCustom]; _lightButton.frame =CGRectMake(0, 40, VIEW_WIDTH, 40); [_lightButton setTitle:@"开启闪光灯" forState:UIControlStateNormal]; [_lightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; _lightButton.backgroundColor =[[UIColor blackColor] colorWithAlphaComponent:DARKCOLOR_ALPHA]; _lightButton.titleLabel.textAlignment=NSTextAlignmentCenter; _lightButton.titleLabel.font=[UIFont systemFontOfSize:15.0]; [_lightButton addTarget:self action:@selector(openLight) forControlEvents:UIControlEventTouchUpInside]; [downView addSubview:_lightButton]; //画中间的基准线 _QrCodeline = [[UIView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH- 2 * SCANVIEW_EdgeLeft, 2)]; _QrCodeline.backgroundColor = [UIColor greenColor]; [_scanView addSubview:_QrCodeline]; //画中间的基准线 _QrCodeline1 = [[UIView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH- 2 * SCANVIEW_EdgeLeft, 2)]; _QrCodeline1.backgroundColor = [UIColor greenColor]; [_scanView addSubview:_QrCodeline1]; // 先让第二根线运动一次,避免定时器执行的时差,让用户感到启动App后,横线就开始移动 [UIView animateWithDuration:2.2 animations:^{ _QrCodeline1.frame = CGRectMake(SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1); }];}// 当地一根线到达底部时,第二根线开始下落运动,此时第一根线已经在顶部,当第一根线接着下落时,第二根线到达顶部.依次循环- (void)moveUpAndDownLine{ CGFloat Y = _QrCodeline.frame.origin.y; if (Y == SCANVIEW_EdgeTop) { [UIView animateWithDuration:2.2 animations:^{ _QrCodeline.frame = CGRectMake(SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1); }]; _QrCodeline1.frame = CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1); } else if (Y == VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2) { _QrCodeline.frame = CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1); [UIView animateWithDuration:2.2 animations:^{ _QrCodeline1.frame = CGRectMake(SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1); }]; }}//照明灯光-(void)openLight{ if ([_lightButton.titleLabel.text isEqualToString:@"开启闪光灯"]) { [self systemLightSwitch:YES]; } else { [self systemLightSwitch:NO]; }}- (void)systemLightSwitch:(BOOL)open{ if (open) { [_lightButton setTitle:@"关闭闪光灯" forState:UIControlStateNormal]; } else { [_lightButton setTitle:@"开启闪光灯" forState:UIControlStateNormal]; } AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if ([device hasTorch]) { [device lockForConfiguration:nil]; if (open) { [device setTorchMode:AVCaptureTorchModeOn]; } else { [device setTorchMode:AVCaptureTorchModeOff]; } [device unlockForConfiguration]; }}// 取消button- (void)cancelAction{ [self dismissViewControllerAnimated:YES completion:nil];}@end
2. 使用ZBarSDK识别二维码
在iOS7.0以前,大部分应用识别二维码都是通过第三方库来实现的。事实上,在主流APP中二维码/条形码的作用主要分三种表现形式来集成:
- 调用手机摄像头并打开系统照相机全屏去拍摄。
- 自定义照相机视图的frame,自己控制并添加相关扫码指南。
识别相册图片中的二维码图片。
首先我们先来看一下如何集成ZBarSDK:
第一步:将 ZBarSDK导入到工程,并集成相关的框架,- AVFoundation.framework
- CoreMedia.framework
- CoreVideo.framework
- QuartzCore.framework
libiconv.dylib
如下图:
第二步:关闭代码优化
导入相关框架后,系统编译仍然不通过,提示的错误如下:
这是由于系统代码优化产生的错误,将Xcode的bitcode选项设置为No就可以通过编译了。第三步:导入头文件,初始化ZBar相机控制器,并实现相关代理;
- 调用系统相机全屏拍摄,使用ZBarReaderViewController,并声明协议。
- 自定义扫描窗口,使用ZBarReaderView,并声明协议。
- 识别相册的二维码图片,使用ZBarReaderController,并声明
2.1 调用系统相机:
示例代码:
#import "ViewController.h"#import "ZBarSDK.h"@interface ViewController ()<ZBarReaderDelegate>@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad];}- (IBAction)systemCamara:(id)sender { // 初始化扫码视图控制器 ZBarReaderViewController *reader = [ZBarReaderViewController new]; // 设置代理 reader.readerDelegate = self; // 设置识别类型 ZBarImageScanner *scanner = reader.scanner; [scanner setSymbology:ZBAR_I25 config:ZBAR_CFG_ENABLE to:0]; reader.showsZBarControls = YES; // 推出扫码视图控制器 [self presentViewController:reader animated:YES completion:nil];}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { id results = [info objectForKey:ZBarReaderControllerResults]; ZBarSymbol * symbol; for(symbol in results) { NSString *result = symbol.data; NSLog(@"%@",result); } // 退出拍照界面 [picker dismissViewControllerAnimated:YES completion:nil];}@end
注释:
直接调用系统相机来实现二维码扫描虽然简单,但是存在极大的问题,那就是这样只能做全屏扫描,不能自定义二维码扫描的选取框。
2.2 自定义扫描窗口
项目中实现的二维码扫描功能我们发现都是可以设置扫描范围内的,下面我们来看一下如何自定义扫描的窗口。
示例代码:
#import "ViewController.h"#import "ZBarSDK.h"@interface ViewController ()<ZBarReaderViewDelegate>@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad];}#pragma mark -#pragma mark - 自定义扫描窗口- (IBAction)scan2Code:(id)sender { // 初始化扫描窗口 ZBarReaderView *readerView = [[ZBarReaderView alloc] init]; // 自定义大小 readerView.frame = CGRectMake(self.view.frame.size.width/2-100, self.view.frame.size.height/2-100, 200, 200); // 设置代理 readerView.readerDelegate = self; // 添加到父视图 [self.view addSubview:readerView]; // 二维码识别设置 ZBarImageScanner *scanner = readerView.scanner; [scanner setSymbology:ZBAR_I25 config:ZBAR_CFG_ENABLE to:0]; // 开始扫描 [readerView start];}#pragma mark - ZBarReaderViewDelegate- (void)readerView:(ZBarReaderView *)readerView didReadSymbols:(ZBarSymbolSet *)symbols fromImage:(UIImage *)image { // 获取扫描的标识 ZBarSymbol *symbol = nil; for (symbol in symbols) { NSString *result = symbol.data; NSLog(@"%@",result); } // 停止扫描 [readerView stop];}@end
2.3 识别相册中的二维码图片:
使用ZBarSDK可以直接选中相册中的二维码图片进行识别,这是系统自带的识别功能所不具备的。下面是识别相册中的二维码图片的实现方法。
示例代码:
#import "ViewController.h"#import "ZBarSDK.h"@interface ViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad];}// 识别相册图片中的二维码- (IBAction)pick2Code:(id)sender { // 进入相册选中相册中的二维码图片 UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;// 图片来源为相册 imagePicker.delegate = self; // 进入相册 [self presentViewController:imagePicker animated:YES completion:nil];}#pragma mark -#pragma mark - UIImagePickerControllerDelegate// 选中图片后调用该方法- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { // 获取选中的图片 UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; CGImageRef cgImage = image.CGImage; ZBarReaderController *reader = [[ZBarReaderController alloc] init]; reader.delegate = self; ZBarSymbol *symbol = nil; for (symbol in [reader scanImage:cgImage]) { NSString *resulot = symbol.data; NSLog(@"%@",resulot); } // 识别结束后返回主界面 [picker dismissViewControllerAnimated:YES completion:nil];}@end
1 0
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 扫描二维码
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 二维码扫描
- 扫描二维码
- 二维码扫描
- 二维码扫描
- 扫描二维码
- 四:深入Nginx之事件和连接 (之一)
- mysql mysqli pdo区别
- android事件拦截处理机制---详解 onInterceptTouchEven onTouchEvent
- C/C++——set的基本操作总结
- Google推荐的图片加载库Glide介绍
- 二维码扫描
- 使用ASTView分析代码调用关系分析的具体应用
- 飞控中使用到数学函数
- CTS 源码分析(一)--CTS概况
- Emeditor ,果然很强大!
- String StringBuffer和StringBuilder异同
- QT5中文显示乱码解决方法
- 支付系统开发--简易版支付系统部署(单节点)
- 严重: The web application [] appears to have started a thread named [Thread-