曾静的博客

但行好事,莫问前程.

嗨,我是曾静 (@devzeng),目前暂居深圳。


这是我用来记录平日学习笔记的地方,欢迎您的访问.

iOS中的二维码扫描

二维码(Two-dimensional code),又称二维条码,它是用特定的几何图形按一定规律在平面(二维方向)上分布的黑白相间的图形,是所有信息数据的一把钥匙。在现代商业活动中,可实现的应用十分广泛,如:产品防伪/溯源、广告推送、网站链接、数据下载、商品交易、定位/导航、电子凭证、车辆管理、信息传递、名片交流、wifi共享等。如今智能手机扫一扫功能的应用使得二维码更加普遍。

ZXing

ZXing是一个开源的条码生成和扫描库,支持众多的条码格式,而且有各种语言的实现版本,支持的语言包括Java、C++、C#、Objective-C等,但是目前已经不再维护。

1、下载ZXing源码,对源码工程进行处理 首先去Google Code或Github将ZXing的代码下载下来,整个工程比较大,我们只需要其中涉及iOS的部分,所以最好做一些裁剪。简单来说,我们只需要保留cppiphone这两个文件夹,其余的文件和文件夹全部删掉。接着继续裁剪,对于cpp这个目录,只保留cpp/core/src/zxingcpp/core/src/bigint下面的内容,其余内容也可以删掉了。但是整个目录结构必须保持原样。 完成之后如下图所示:

ios_zxing_dir.png

2、配置Xcode

(1)把裁剪后的zxing目录整个移动到iOS项目的目录下,把ZXingWidget.xcodeproj文件拖动到iOS工程中,如下图所示。

zxing_xcode_profile.png

(2)在Xcode的Target->Build Phases中添加如下配置:

1)在Target Dependencies中添加ZXingWidget(ZXingWidget)

2)在Link Binary With Libraries中添加AVFoundationAudioToolboxCoreVideoCoreMedialibiconvAddressBookAddressBookUIlibZXingWidget.a

(3)在在Xcode的Target->Build Settings中添加如下配置:

1)在TargetZXingWidgetBuild Settings中调整Build Active Architecture OnlyNO

2)在主工程的Target的Build SettingsHeader Search Paths添加下面两行:

./zxing/iphone/ZXingWidget/Classes【recursive】

./zxing/cpp/core/src 【non-recursive】

3、实现二维码的扫描

将引用到ZXing的类的后缀名改成.mm

(1)直接使用ZXingWidgetController扫描二维码

- (void)onZxingClicked:(id)sender
{
    ZXingWidgetController *widController = [[ZXingWidgetController alloc] initWithDelegate:self showCancel:YES OneDMode:NO];
    NSMutableSet *readers = [[NSMutableSet alloc] init];
    QRCodeReader *qrcodeReader = [[QRCodeReader alloc] init];
    [readers addObject:qrcodeReader];
    widController.readers = readers;
    [self presentViewController:widController animated:YES completion:nil];
}

实现ZXingDelegate协议的代理方法

//扫描出结果调用的函数
- (void)zxingController:(ZXingWidgetController*)c didScanResult:(NSString *)result
{
    [c dismissViewControllerAnimated:YES completion:nil];
    NSLog(@"%@", result);
}

//取消处理回调的函数
- (void)zxingControllerDidCancel:(ZXingWidgetController*)controller
{
    [controller dismissViewControllerAnimated:YES completion:nil];
}

(2)使用AVFoundation获取Camera的实时图像然后对图像进行解析

1)获取Camera的实时图像

获取Camera的实时图像的方法过长,会在接下来的博文中进行介绍。

2)解析图像的内容

//解析图像的内容
- (void)decoderQRCode:(UIImage *)image
{
    NSMutableSet *qrReaderConfig = [[NSMutableSet alloc ] init];
    QRCodeReader* qrcodeReader = [[QRCodeReader alloc] init];
    [qrReaderConfig addObject:qrcodeReader];
    Decoder *d = [[Decoder alloc] init];
    d.readers = qrReaderConfig;
    d.delegate = self;
    [d decodeImage:image];
}
//开始解析图片
- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset
{
    
}

//已经完成解析
- (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)result
{
    NSLog(@"【Decoder Result】->%@", result.text);
}

//解析失败
- (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason
{
    NSLog(@"【Decoder Error】->%@", reason);
}

- (void)decoder:(Decoder *)decoder foundPossibleResultPoint:(CGPoint)point
{
    
}

iOS7中自带的AVFoundation

1、创建AVCaptureSession对象

- (AVCaptureSession *)setupCaptureSession
{
    NSError *error;
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    
    if (!input) {
        NSLog(@"%@", [error localizedDescription]);
        return NO;
    }
    
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    // Set the input device on the capture session.
    [session addInput:input];
    
    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
    [session addOutput:captureMetadataOutput];
    
    // Create a new serial dispatch queue.
    dispatch_queue_t dispatchQueue;
    dispatchQueue = dispatch_queue_create("com.devzeng.qrcode.queue", NULL);
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
    
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
    //[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeQRCode, nil]];
    
    [session startRunning];
    
    return session;
}

2、实现AVCaptureMetadataOutputObjectsDelegate代理方法

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    if(!self.isReading)
    {
        return;
    }
    
    if (metadataObjects != nil && [metadataObjects count] > 0)
    {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        NSLog(@"%@", metadataObj.stringValue);
    }
}

参考资料

1、《在iOS中使用ZXing库》

2、《iOS项目开发中使用了ZXing》

3、《在iOS和Android中使用二维码ZXing库及常见问题解决和整合后的代码》

4、《Undefined symbols for architecture armv7 when using ZXing library in XCode 4.5》

5、《解决Xcode5.1编译ZXing出错的问题》

最近的文章

iOS中的URL Scheme

在iOS的SDK中提供了一个非常有意思的功能,它能将iOS的Application同自定义的URL Schema绑定,同时可以通过URL Scheme在浏览器或者是其他应用中启动这个Application。本文主要介绍如何通过URL Scheme的方式启动应用和参数的传递。创建URL Scheme1、首先在*-Info.plist中添加一行,选择URL types,效果如下图所示:2、在展开的Item 0中填写URL identifier,这个用来唯一标识用户自定义的URL Scheme,...…

iOS继续阅读
更早的文章

Java使用JNDI配置WEB项目数据源

JNDI(Java Naming and Directory Interface,Java命名与目录接口)是Java提供的一种标准的命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI SPI(Service Provider Interface,服务提供者接口)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。使用传统的方式一般对于普通的项目,习惯上使用.properties的文件来配...…

Java继续阅读