Android二维码生成与扫描

澳门新葡亰3522平台游戏 1

本文由码农网 –
苏耀东原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

原文地址:张飞的技术博客

第三方库导入

Zxing3.1第三方库下载链接

直接import module,将上面的第三方库导入。

澳门新葡亰3522平台游戏,在导入后如果用到的icon或者字符串资源名称一样,可能会报错,解决方法(以label名重复为例):

1.在Manifest标签下添加 xmlns:tools=”

2.在Application标签下添加: tools:replace=”android:label”

澳门新葡亰3522平台游戏 1

扫一扫这个功能我们并不陌生,微信QQ加好友扫一扫,路边搞推广的扫一扫,吃饭付钱扫一扫。看来这个扫一扫应用的地方还真不少啊!打开手机看了看安装的APP,社交类APP有扫一扫,支付类的APP有扫一扫,连浏览器都有扫一扫。看来这个扫一扫不可小视!说不定哪天在你的项目中你的boss就要你给他加个扫一扫的功能呢!对于iOS开发要想做扫一扫这个功能,并不是很难,我们需要做的就是处理二维码(QRCode)而已。在iOS7之前需要借助第三方库ZBar和ZXing。在iOS7以后用自带API就能轻松搞定。不用在项目中导入臃肿的第三方库和担心编译出问题了。

扫描二维码

直接调用代码,进入二维码扫描的界面。

private void startForQrScan() {
        startActivityForResult(new Intent(xxx.this, CaptureActivity.class), 0);
}

扫描的结果在onActivityResult返回。

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK){
            Bundle bundle = data.getExtras();
            String result = bundle.getString("result");
            L.d("result: " + result);
        }
    }

二维码是个什么鬼?

二维条码是指在一维条码的基础上扩展出另一维具有可读性的条码,使用黑白矩形图案表示二进制数据,被设备扫描后可获取其中所包含的信息。—-维基百科

详细的生成细节和原理可以看看二维码的生成细节和原理这篇文章。

生成二维码

调用下面代码生成二维码图片,同时设置二维码中间的logo图标

private void generateQr(String data) {
        int width = Tools.dip2px(this, 300);
        Bitmap bitmap = EncodingUtils.createQRCode(data, width, width, 
BitmapFactory.decodeResource(getResources(), R.drawable.qr_logo));
        img_qr.setImageBitmap(bitmap);
    }

为了提高扫描的效果,可以将屏幕亮度设置到最亮

WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.screenBrightness = 1.0f;
        getWindow().setAttributes(lp);

扫描二维码

首先我们来想一想具体的步骤,大概流程应该是:1.打开设备的摄像头–>2.进行二维码图像捕获–>3.获取捕获的图像进行解析–>4.取得解析结果进行后续处理。这些流程需要用到AVFoundation这个库,注意导入。

//获取一个AVCaptureDevice对象,可以理解为打开摄像头这样的动作
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//获取一个AVCaptureDeviceInput对象,将上面的'摄像头'作为输入设备
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:nil];
//拍完照片以后,需要一个AVCaptureMetadataOutput对象将获取的'图像'输出,以便进行对其解析
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
//获取输出需要设置代理,在代理方法中获取
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//设置输出类型,如AVMetadataObjectTypeQRCode是二维码类型,下面还增加了条形码。如果扫描的是条形码也能识别
output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code,
                                    AVMetadataObjectTypeEAN8Code,
                                    AVMetadataObjectTypeCode128Code,
                                    AVMetadataObjectTypeQRCode];

上面完成了捕获的设置,但是并未正在开始’扫描’,要完成一次扫描的过程,需要用到AVCaptureSession这个类,这个session类把一次扫描看做一次会话,会话开始后才是正在的’扫描’开始,具体代码如下。

AVCaptureSession *session = [[AVCaptureSession alloc]init];
[session setSessionPreset:AVCaptureSessionPresetHigh];//扫描的质量
if ([session canAddInput:input]){
   [session addInput:input];//将输入添加到会话中
}  
if ([session canAddOutput:output]){
   [session addOutput:output];//将输出添加到会话中
}

接下来我们要做的不是立即开始会话(开始扫描),如果你现在调用会话的startRunning方法的话,你会发现屏幕是一片黑,这时由于我们还没有设置相机的取景器的大小。设置取景器需要用到AVCaptureVideoPreviewLayer这个类。具体代码如下:

AVCaptureVideoPreviewLayer *preview =[AVCaptureVideoPreviewLayer layerWithSession:session];
preview.videoGravity = AVLayerVideoGravityResize;
[preview setFrame:self.view.bounds];//设置取景器的frame
[self.view.layer insertSublayer:preview atIndex:0];

接下来我们就可以调用session的startRunning方法了,这时我们的扫描就真正开始了。想要获得扫描的结果,需要实现session的代理方法- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection,代码如下:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    [self.session stopRunning];//停止会话
    [self.preview removeFromSuperlayer];//移除取景器

    if (metadataObjects.count > 0) {
        AVMetadataMachineReadableCodeObject *obj = metadataObjects[0];
        NSString *result = obj.stringValue;//这就是扫描的结果啦
        //对结果进行处理...
    }
}

如果要做到为用户考虑的话,还得加入照明的功能或者设置兴趣区域。

  • 设设置兴趣区域

使用过微信中的扫一扫的话,你应该发现在扫描界面中间有一个矩形限定框,这个框就是兴趣区域了。这个兴趣区域是AVCaptureMetadataOutputrectOfInterest属性。rectOfInterest的值的范围都是0-1,是按比例取值而不是实际尺寸,所以设置的时候要注意的一点。还要注意rectOfInterest都是按照横屏来计算的,所以当竖屏的情况下x轴和y轴要交换一下。代码如下:

CGSize size = self.view.bounds.size;
CGSize transparentAreaSize = CGSizeMake(200,200);
CGRect cropRect = CGRectMake((size.width - transparentAreaSize.width)/2, (size.height - transparentAreaSize.height)/2, transparentAreaSize.width, transparentAreaSize.height);
output.rectOfInterest = CGRectMake(cropRect.origin.y/size.width,
                                              cropRect.origin.x/size.height,
                                              cropRect.size.height/size.height,
                                              cropRect.size.width/size.width);
  • 加入照明功能

加入照明功能能让用户在光照条件不好的情况下顺利的进行进行扫描操作,代码如下:

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
if (device.hasTorch) {  // 判断设备是否有闪光灯
    BOOL b = [device lockForConfiguration:&error];
    if (!b) {
       if (error) {
          NSLog(@"lock torch configuration error:%@", error.localizedDescription);
       }
       return;
    }
    device.torchMode = (device.torchMode == AVCaptureTorchModeOff ? AVCaptureTorchModeOn : AVCaptureTorchModeOff);
    [device unlockForConfiguration];
    }