ios7原生扫码

很多应用都有扫描二维码的功能,在开发这些功能时大家都可能接触过 ZXing 或 ZBar 这类第三方扫码库,但从 iOS 7 开始系统原生 API 就支持通过扫描获取二维码的功能。今天就来说说原生扫码的那些事。

0、相机权限

也是从 iOS 7 开始,应用要使用相机功能首先要获得用户的授权,所以要先判断授权情况。

  • 判断授权情况方法:
AVAuthorizationStatus authorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  • AVAuthorizationStatus enum 值有:
typedef NS_ENUM(NSInteger, AVAuthorizationStatus) {
  AVAuthorizationStatusNotDetermined = 0,
  AVAuthorizationStatusRestricted, // 受限,有可能开启了访问限制
  AVAuthorizationStatusDenied,
  AVAuthorizationStatusAuthorized
} NS_AVAILABLE_IOS(7_0);

  • 请求授权方法:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler: ^(BOOL granted) {
    if (granted) {
        [self startCapture]; // 获得授权
    } else {
        NSLog(@"%@", @"访问受限");
    }
}];
  • 完整授权处理逻辑:
AVAuthorizationStatus authorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
switch (authorizationStatus) {
  case AVAuthorizationStatusNotDetermined: {
    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler: ^(BOOL granted) {
      if (granted) {
        [self startCapture];
      } else {
        NSLog(@"%@", @"访问受限");
      }
    }];
    break;
  }
  case AVAuthorizationStatusAuthorized: {
    [self startCapture];
    break;
  }
  case AVAuthorizationStatusRestricted:
  case AVAuthorizationStatusDenied: {
    NSLog(@"%@", @"访问受限");
    break;
  }
  default: {
    break;
  }
}

1、扫码

  • AVCaptureSession

扫码是一个从摄像头(input)到 解析出字符串(output) 的过程,用AVCaptureSession 来协调。其中是通过 AVCaptureConnection 来连接各个 input 和 output,还可以用它来控制 input 和 output 的 数据流向。它们的关系如下图:

  • 扫码的代码很简单,如下:
AVCaptureSession *session = [[AVCaptureSession alloc] init];
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (deviceInput) {
  [session addInput:deviceInput];
  AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init];
  [metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
  [session addOutput:metadataOutput]; // 这行代码要在设置 metadataObjectTypes 前
  metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
  AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
  previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
  previewLayer.frame = self.view.frame;
  [self.view.layer insertSublayer:previewLayer atIndex:0];
  [session startRunning];
} else {
  NSLog(@"%@", error);
}
  • 扫码结果从委托方法返回:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
  AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects.firstObject;
  if ([metadataObject.type isEqualToString:AVMetadataObjectTypeQRCode] && !self.isQRCodeCaptured) { // 成功后系统不会停止扫描,可以用一个变量来控制。
    self.isQRCodeCaptured = YES;
    NSLog(@"%@", metadataObject.stringValue);
  }
}

2、从图片文件解析(iOS 8 起)

从 iOS 8 开始你也可以从图片文件解析出二维码,用到 Core Image 的 CIDetector。

代码也很简单:

CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy:CIDetectorAccuracyHigh }];
CIImage *image = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"foobar.png"]];
NSArray *features = [detector featuresInImage:image];
for (CIQRCodeFeature *feature in features) {
    NSLog(@"%@", feature.messageString);
}

(foobar.png)

3、生成二维码图片

生成二维码用到了 CIQRCodeGenerator 这种 CIFilter。它有两个字段可以设置,inputMessage 和 inputCorrectionLevel。inputMessage 是一个 NSData 对象,可以是字符串也可以是一个 URL。inputCorrectionLevel 是一个单字母(@"L", @"M", @"Q", @"H" 中的一个),表示不同级别的容错率,默认为 @"M"。

QR码有容错能力,QR码图形如果有破损,仍然可以被机器读取内容,最高可以到7%~30%面积破损仍可被读取。所以QR码可以被广泛使用在运输外箱上。

相对而言,容错率愈高,QR码图形面积愈大。所以一般折衷使用15%容错能力。

错误修正容量 L水平 7%的字码可被修正

M水平 15%的字码可被修正

Q水平 25%的字码可被修正

H水平 30%的字码可被修正

所以很多二维码的中间都有头像之类的图片但仍然可以识别出来就是这个原因。

代码如下,应该注意的是:

  • 1)官方建议使用 NSISOLatin1StringEncoding 来编码,但经测试这种编码对中文或表情无法生成,改用 NSUTF8StringEncoding 就可以了。
  • 2)生成的图片尺寸(outputImage.extent.size)会比较小,需要对它进行缩放。
  • 3)生成的 CIImage 需要先转成 CGImage 才可以保存,因为 UIImagePNGRepresentation 接受的 UIImage 要有 CGImage,如果没有或者位图格式不对都会返回 nil。
// return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format
NSData * UIImagePNGRepresentation(UIImage *image);
NSString *urlString = @"http://weibo.com/u/2255024877";
NSData *data = [urlString dataUsingEncoding:NSISOLatin1StringEncoding]; // NSISOLatin1StringEncoding 编码

CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[filter setValue:data forKey:@"inputMessage"];

CIImage *outputImage = filter.outputImage;
NSLog(@"%@", NSStringFromCGSize(outputImage.extent.size));

CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale); // scale 为放大倍数
CIImage *transformImage = [outputImage imageByApplyingTransform:transform];

// 保存
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef imageRef = [context createCGImage:transformImage fromRect:transformImage.extent];

UIImage *qrCodeImage = [UIImage imageWithCGImage:imageRef];
[UIImagePNGRepresentation(qrCodeImage) writeToFile:path atomically:NO];

CGImageRelease(imageRef);

(生成的二维码图片)

4、扫描框

  • rectOfInterest

扫码时 previewLayer 的扫描范围是整个可视范围的,但有些需求可能需要指定扫描的区域,虽然我觉得这样很没有必要,因为整个屏幕都可以扫又何必指定到某个框呢?但如果真的需要这么做可以设定 metadataOutput 的 rectOfInterest。

需要注意的是:

  • 1) rectOfInterest 的值比较特别,需要进行转化。它的默认值是 (0.0, 0.0, 1.0, 1.0)。
metadataOutput.rectOfInterest = [previewLayer metadataOutputRectOfInterestForRect:CGRectMake(80, 80, 160, 160)]; // 假设扫码框的 Rect 是 (80, 80, 160, 160)
[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureInputPortFormatDescriptionDidChangeNotification
                                                        object:nil
                                                         queue:[NSOperationQueue currentQueue]
                                                    usingBlock: ^(NSNotification *_Nonnull note) {
      metadataOutput.rectOfInterest = [previewLayer metadataOutputRectOfInterestForRect:CGRectMake(80, 80, 160, 160)];
}];
  • 扫码框的外观

扫码框四周一般都是半透明的黑色,而它里面是没有颜色的。 

(扫码框)

你可以在扫码框四周各添加视图,但更简单的方法是自定义一个视图,在 drawRect: 画扫码框的 path。代码如下:

CGContextRef ctx = UIGraphicsGetCurrentContext();

CGFloat width = CGRectGetWidth([UIScreen mainScreen].bounds);
[[[UIColor blackColor] colorWithAlphaComponent:0.5] setFill];

CGMutablePathRef screenPath = CGPathCreateMutable();
CGPathAddRect(screenPath, NULL, self.bounds);

CGMutablePathRef scanPath = CGPathCreateMutable();
CGPathAddRect(scanPath, NULL, CGRectMake(80, 80, 160, 160);

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddPath(path, NULL, screenPath);
CGPathAddPath(path, NULL, scanPath);

CGContextAddPath(ctx, path);
CGContextDrawPath(ctx, kCGPathEOFill); // kCGPathEOFill 方式

CGPathRelease(screenPath);
CGPathRelease(scanPath);
CGPathRelease(path);  
时间: 2024-08-28 04:07:56

ios7原生扫码的相关文章

iOS开发——iOS7(及以后版本) SDK自带二维码(含条形码)扫码、二维码生成

本文转载至 http://www.cnblogs.com/leotangcn/p/4357907.html 现在很多APP都涉及了二维码扫码功能,这个功能简单实用,很多情况下用户乐于使用,现在本文带来iOS7自带二维码扫码的教程,也包括扫条形码,足以满足简单的扫码要求,而且避免使用第三方的繁琐. 后期项目中需要生成二维码,我在git上找到一个很方便使用的轻量级开源库,推荐给有需要的朋友:https://github.com/moqod/ios-qr-code-encoder 下面介绍如何使用iO

微信原生支付 Native扫码支付( V3.3.7 版本)

[尊重别人的劳动成果,转载请注明出处:一缕晨光工作室,www.wispdawn.com] 前言 辛苦研究三天,遇到各种困难,最终还是克服了,把我的理解和思路分享给需要帮助的人,如果你觉的好,请帮我分享一下,谢谢. 在没有做之前,我以为和支付宝,以及银联一样,会在官网找到相应的demo,照葫芦画瓢即可,没有什么复杂的,真正去做的时候,发现各种错误,很多时候都莫名其妙找不到北, 在网上搜了不知道多少遍,有V3版的,不过都是js api版本的,没有找到原生扫码支付,下了几个V2版本的微信支付c#dem

使用IOS7原生API进行二维码条形码的扫描

使用IOS7原生API进行二维码条形码的扫描 IOS7之前,开发者进行扫码编程时,一般会借助第三方库.常用的是ZBarSDK,IOS7之后,系统的AVMetadataObject类中,为我们提供了解析二维码的接口.经过测试,使用原生API扫描和处理的效率非常高,远远高于第三方库. 一.使用方法示例 官方提供的接口非常简单,代码如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

PHP原生代码写的微信扫码支付实例

一款PHP原生代码写的微信扫码支付,不基于任何框架,完全手写. 扫码支付只要授权域名对就OK,本地是无法测试.跟openid也没有关系,所以跟支付授权目录页没关系. 微信商户信息配置地址:weixinpay\lib\WxPay.Config.php 第25行 1 const APPID = 'wx422126b0b6bbfcfc'; // 绑定支付的APPID(必须配置,开户邮件中可查看) 2 const MCHID = '1349825901'; // 商户号(必须配置,开户邮件中可查看) 3

微信支付之扫码支付(java版 native原生支付)

本文直接从代码调用微信扫码支付讲起.账号配置,参数生成等请参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 微信扫码支付.简单来说,就是你把微信支付需要的信息,生成到二维码图片中.通过微信扫一扫,发起支付.我们需要做的就是二件事: 一是:按照微信扫码支付规则生成二维码信息. 二是:微信没有提供生成二维码图片的接口.需要我们自己把二维码信息生成到二维码图片中. 1.模式选择: 微信扫码支付,有两种模式,文档中有

微信扫码支付方式二的测试实现

申请微信支付通过审核,系统会给一个商户账号,登录商户账号里面可以设置32位的密匙和下载证书. 通过在公众号里面设置相关的测试白名单,授权目录和验证地址(网络地址带HTTP).下载微信官方demo,修改参数配置,根据需要注释了一些代理设置,因为没用到.发布服务器进行支付测试验证.之前尝试采用扫码模式一,根据生成的日志文件可以看到返回的信息提示(XML格式).老出现原生支付URL参数错误,支付订单号不存在(签名提示成功)等情况.查了很多资料针对订单号不存在的情况,官方有把常见的错误列表给出,并提示注

微信公众号 扫码支付 模式二 demo

扫码支付 本文附有代码,在下方,如果不熟悉场景的可以看看下面的场景介绍 场景介绍 官网介绍地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 用户扫描商户展示在各种场景的二维码进行支付. 步骤1:商户根据微信支付的规则,为不同商品生成不同的二维码(如图6.1),展示在各种场景,用于用户扫描购买. 步骤2:用户使用微信"扫一扫"(如图6.2)扫描二维码后,获取商品支付信息,引导用户完成支付(如图6.3). 图6

扫码支付

关于微信原生支付(扫码支付)的两种支付模式的理解和比较... 标签: 微信支付扫码支付支付微信 2015-12-14 21:40 9964人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. 关于微信原生支付(扫码支付)的两种支付模式的理解和比较... by:一起奋斗(转载请注明出处)http://blog.csdn.net/u011852706/article/details/50300915 1.[模式一]:商户后台系统根据微信支付规则链接生成二维码,链接中带

微信支付-扫码支付备忘

1,使用官方的Demo,然后,登陆微信公众平台,进行参数设置,下面贴一段微信官方的说法: 1.开通支付权限 在微信公众平台设置支付权限,进入栏目微信支付->开发配置->修改,如图6.6所示. 图6.6原生支付参数设置栏目入口 进入修改页面后,找到公众号支付->Native原生支付,勾选Native原生支付开通该权限,在支付回调URL上填写商户支付后台系统的网页地址. 图6.7原生支付设置权限及支付回调地址 微信公众平台需要设置的东西就这么多,然后我们回到Demo上的代码,如下图: 然后我