CIDetector 这个api是苹果在ios8之后提供的。所以用苹果自带的AVFundation扫描,如果从相册获取图片识别二维码,则需要8.0系统以上。
- (void)viewDidLoad {
[super viewDidLoad];
_captureSession = nil;
//初始化扫描界面
[self setScanView];
}
-(void)viewWillAppear:(BOOL)animated {
//10.开始扫描
[_captureSession startRunning];
[self createTimer];
}
-(void)viewWillDisappear:(BOOL)animated {
[self stopTimer];
[self stopReading];
}
//二维码的扫描区域
- (void)setScanView
{
self.view.backgroundColor = [UIColor clearColor];
UIView *scanView=[[UIView alloc] initWithFrame:CGRectMake(0,0, VIEW_WIDTH,VIEW_HEIGHT)];
[self.view addSubview:scanView];
_scanView = scanView;
_scanView.backgroundColor=[UIColor clearColor];
//最上部view
UIView* navView = [[UIView alloc] initWithFrame:CGRectMake(0,0, VIEW_WIDTH,SCANVIEW_EdgeTop - 40)];
navView.backgroundColor = kMainColorOfApp;
[_scanView addSubview:navView];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake((screenWith - 200)/2, 20, 200, 44)];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.text = AppLocalizedString(@"Scan QR code");
[titleLabel setBackgroundColor:[UIColor clearColor]];
[navView addSubview:titleLabel];
//导航左边的按钮
UIButton *leftBarbtn = [[UIButton alloc] initWithFrame:CGRectMake(15, 30, 22, 22)];
[leftBarbtn setBackgroundImage:[UIImage imageNamed:@"back_normal_icon"] forState:UIControlStateNormal];
[leftBarbtn setBackgroundImage:[UIImage imageNamed:@"back_down_icon"] forState:UIControlStateHighlighted];
leftBarbtn.tag = kTagBtnLeft;
[leftBarbtn addTarget:self action:@selector(onBarbtnClick:) forControlEvents:UIControlEventTouchUpInside];
[navView addSubview:leftBarbtn];
//导航右边的按钮
UIButton *rightBarbtn = [[UIButton alloc] initWithFrame:CGRectMake(screenWith - 60 - 10, 20, 60, 44)];
[rightBarbtn setTitle:AppLocalizedString(@"Album") forState:UIControlStateNormal];
[rightBarbtn setTitle:AppLocalizedString(@"Album") forState:UIControlStateHighlighted];
rightBarbtn.tag = kTagBtnRight;
[rightBarbtn setTintColor:[UIColor blueColor]];
[rightBarbtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[rightBarbtn addTarget:self action:@selector(onBarbtnClick:) forControlEvents:UIControlEventTouchUpInside];
[navView addSubview:rightBarbtn];
[self setReadView];
//最上部view
UIView* upView = [[UIView alloc] initWithFrame:CGRectMake(0,SCANVIEW_EdgeTop - 40, VIEW_WIDTH,40)];
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];
//右侧的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-(SCANVIEW_EdgeTop+VIEW_WIDTH-2*SCANVIEW_EdgeLeft))];
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 = AppLocalizedString(@"Align the QR Code within the frame to scan");
[downView addSubview:labIntroudction];
}
- (void)setReadView{
NSError *error;
//1.初始化捕捉设备(AVCaptureDevice),类型为AVMediaTypeVideo
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//2.用captureDevice创建输入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
CCLog(@"扫描错误%@", [error localizedDescription]);
return ;
}
//3.创建媒体数据输出流
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
//4.实例化捕捉会话
_captureSession = [[AVCaptureSession alloc] init];
//高质量采集率
[_captureSession setSessionPreset:AVCaptureSessionPresetHigh];
//4.1.将输入流添加到会话
[_captureSession addInput:input];
//4.2.将媒体输出流添加到会话中
[_captureSession addOutput:captureMetadataOutput];
//5.1.设置代理
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//5.2.设置输出媒体数据类型为QRCode
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
//6.实例化预览图层
AVCaptureVideoPreviewLayer *readerView = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
_readerView = readerView;
//7.设置预览图层填充方式
[readerView setVideoGravity:AVLayerVideoGravityResizeAspectFill];
//8.设置图层的frame
readerView.frame = CGRectMake(0,SCANVIEW_EdgeTop-40,screenWith,screenHeight-SCANVIEW_EdgeTop+40);
//9.将图层添加到预览view的图层上
[_scanView.layer insertSublayer:readerView atIndex:0];
//10.设置扫描范围
captureMetadataOutput.rectOfInterest = CGRectMake(0.2f, 0.2f, 0.8f, 0.8f);
//10.1.扫描框
UIImageView *boxView = [[UIImageView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft,SCANVIEW_EdgeTop, VIEW_WIDTH-2*SCANVIEW_EdgeLeft,VIEW_WIDTH-2*SCANVIEW_EdgeLeft)];
_boxView = boxView;
boxView.image=[UIImage imageNamed:@"pick_bg.png"];
boxView.backgroundColor=[UIColor clearColor];
[_scanView addSubview:boxView];
//10.2.画中间的扫描线
// _QrCodeline = [[UIImageView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft,SCANVIEW_EdgeTop, VIEW_WIDTH-2*SCANVIEW_EdgeLeft,5)];
_QrCodeline = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,_boxView.frame.size.width,5)];
[_QrCodeline setImage:[UIImage imageNamed:@"line.png"]];
_QrCodeline.backgroundColor = [UIColor clearColor];
[_boxView addSubview:_QrCodeline];
}
//二维码的横线移动
- (void)moveScanLayer
{
CGRect frame = _QrCodeline.frame;
if (_boxView.frame.size.height-3 <= _QrCodeline.frame.origin.y) {
frame.origin.y = 0;
_QrCodeline.frame = frame;
frame.origin.y = _boxView.frame.size.height-2;
[UIView beginAnimations:nil context:nil]; //开始动画,第一个参数是该动画的名字
[UIView setAnimationDuration:1.6f]; //动画持续时间
_QrCodeline.frame = frame;
[UIView commitAnimations]; //结束动画
}else{
frame.origin.y = _boxView.frame.size.height-2;
[UIView beginAnimations:nil context:nil]; //开始动画,第一个参数是该动画的名字
[UIView setAnimationDuration:1.6f]; //动画持续时间
_QrCodeline.frame = frame;
[UIView commitAnimations]; //结束动画
}
}
- (void)createTimer
{
//创建一个时间计数
_timer=[NSTimer scheduledTimerWithTimeInterval:1.6f target:self selector:@selector(moveScanLayer) userInfo:nil repeats:YES];
[_timer fire];
}
- (void)stopTimer
{
if ([_timer isValid] == YES) {
[_timer invalidate];
_timer =nil;
}
}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
[_captureSession stopRunning];
//判断是否有数据
if (metadataObjects != nil && [metadataObjects count] > 0) {
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
//判断回传的数据类型
if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
[self readQRCodeActionWithCode:[metadataObj stringValue]];
}
}
}
-(void)stopReading{
[_captureSession stopRunning];
_captureSession = nil;
[_readerView removeFromSuperlayer];
[_QrCodeline removeFromSuperview];
}
/**
* 识别出来二维码之后的逻辑处理,以后有新的页面调用扫描时直接在这个方法里面增加逻辑就可以了
*
* @param symbolStr
*/
- (void)readQRCodeActionWithCode:(NSString *)symbolStr
{
if([symbolStr hasPrefix:kQrcodeFriend]){
NSRange range = [symbolStr rangeOfString:kQrcodeFriend options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound && range.location == 0) {
NSString *userId = [symbolStr stringByReplacingCharactersInRange:range withString:@""];
self.requestType = NearbyServiceType;
[[NearbyService sharedInstance] serchFriendbyUserIdOrNumber:userId andTarget:self andSuccessSelector:self.successSelector andFailureSelector:self.failureSelector];
} else {
//错误提示
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:AppLocalizedString(@"AppName") message:AppLocalizedString(@"QR code error") delegate:self cancelButtonTitle:AppLocalizedString(@"OK") otherButtonTitles:nil, nil];
alert.tag = kTagAlertDismiss;
[alert show];
}
}else if ([symbolStr hasPrefix:kQrcodeBalance]){
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] objectForKey:GETWALLETINFO]];
NSMutableDictionary *dic1 = [dic objectForKey:[[CloudCall2AppDelegate sharedInstance] getUserID]];
NSNumber *isexist = [dic1 objectForKey:@"isexist"];
NSString *usertype = [dic1 objectForKey:@"usertype"];
NSRange range = [symbolStr rangeOfString:kQrcodeBalance options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound && range.location == 0) {
if (!isexist.boolValue&&[usertype isEqualToString:@"V"]) {
[self showSetPayPasswordAlert];
}else if([usertype isEqualToString:@"M"]){
//错误提示
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:AppLocalizedString(@"Pay function is forbid for Merchant account .") delegate:nil cancelButtonTitle:AppLocalizedString(@"OK") otherButtonTitles: nil];
alert.tag = kTagAlertDismiss;
[alert show];
}else{
NSString *gid = [symbolStr stringByReplacingCharactersInRange:range withString:@""];
self.requestType = BalanceServiceType;
[[BalanceService sharedInstance] initOrderWithGid:gid andTarget:self andSuccessSelector:self.successSelector andFailureSelector:self.failureSelector];
}
} else {
//错误提示
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:AppLocalizedString(@"AppName") message:AppLocalizedString(@"QR code error") delegate:self cancelButtonTitle:AppLocalizedString(@"OK") otherButtonTitles:nil, nil];
alert.tag = kTagAlertDismiss;
[alert show];
}
}else if ([symbolStr hasPrefix:kQrcodeAd]){
//给服务端发送一个请求
self.requestType = ADPlatformServiceType;
//截取二维码里面的广告id(依据后台服务端返回的协议)
NSArray *stringSeparateArr = [symbolStr componentsSeparatedByString:@"|"];
NSString *firstString = stringSeparateArr[0];
NSString *adIdString = [firstString substringFromIndex:4];//前面Adv# 这4个字符是固定的广告二维码标识,后面紧跟的是广告id
[[ADPlatformService sharedInstance] scanAdTwoDimensCodeWithADId:adIdString QrCode:symbolStr Target:self SuccessSelector:self.successSelector FailureSelector:self.failureSelector];
}else if ([symbolStr hasPrefix:kQrcodeWebLogin]){
//加密userid,格式化,再转json
NSString *userId = [[CloudCall2AppDelegate sharedInstance] getUserID];
NSData *useridData = [userId dataUsingEncoding:NSUTF8StringEncoding];
NSString *userIdBase64 = [useridData base64Encoding];
NSString *userIdFormat = [NSString stringWithFormat:@"\"userid\":\"%@\"",userIdBase64];
// NSString *userIdJson = [userIdFormat JSONString];
//格式化uuid
NSString *uuid = [symbolStr substringFromIndex:6];
NSString *uuidJson = [NSString stringWithFormat:@"\"uuid\":\"%@\"",uuid];
//格式化sessionid 再加密
NSString *sessionId = [NSString stringWithFormat:@"{%@,%@}",userIdFormat,uuidJson];
NSData *sessionIdData = [sessionId dataUsingEncoding:NSUTF8StringEncoding];
NSString *sessionIdBase64 = [sessionIdData base64Encoding];
//作为参数上送
NSDictionary *sessidDicParam = @{@"sessionId":sessionIdBase64};
if (self.qrCodeWebLoginParamDic == nil) {
self.qrCodeWebLoginParamDic = sessidDicParam;
}
[[AFHttpRequest instance] ASyncPOSTHTTPS:kScanQRCodeLoginUrl andParameters:[sessidDicParam mutableCopy] andUserInfo:[NSMutableDictionary dictionaryWithObjectsAndKeys:@"scanQRCodeLogin",@"reqtype",nil] andTarget:self andSuccessSelector:@selector(scanQRCodeRequestSuccess:andResponse:) andFailureSelector:@selector(scanQRCodeRequestFailed:andError:)];
}else{
[self dismissViewControllerAnimated:NO completion:^{
if ([symbolStr rangeOfString:@".aero"].length>0||[symbolStr rangeOfString:@".arpa"].length>0||[symbolStr rangeOfString:@".biz"].length>0||[symbolStr rangeOfString:@".com"].length>0||[symbolStr rangeOfString:@".coop"].length>0||[symbolStr rangeOfString:@".edu"].length>0||[symbolStr rangeOfString:@".gov"].length>0||[symbolStr rangeOfString:@".info"].length>0||[symbolStr rangeOfString:@".int"].length>0||[symbolStr rangeOfString:@".jobs"].length>0||[symbolStr rangeOfString:@".mil"].length>0||[symbolStr rangeOfString:@".name"].length>0||[symbolStr rangeOfString:@".museum"].length>0||[symbolStr rangeOfString:@".nato"].length>0||[symbolStr rangeOfString:@".net"].length>0||[symbolStr rangeOfString:@".org"].length>0||[symbolStr rangeOfString:@".pro"].length>0||[symbolStr rangeOfString:@".cn"].length>0||[symbolStr rangeOfString:@".co"].length>0) {
[self OpenWebBrowser:symbolStr];
}else if ([symbolStr hasPrefix:@"http:"] || [symbolStr hasPrefix:@"https:"] || [symbolStr hasPrefix:@"www."]){
[self OpenWebBrowser:symbolStr];
}else{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.nav.view addSubview:HUD];
HUD.mode = MBProgressHUDModeCustomView;
HUD.labelText = AppLocalizedString(@"QR code error");
[HUD show:YES];
[HUD hide:YES afterDelay:2];
}
}];
}
}
#pragma mark - Action- (void)onBarbtnClick:(id)sender { UIButton *btn = (UIButton *)sender; if (btn.tag == kTagBtnLeft) { [self dismissViewControllerAnimated:YES completion:nil]; } else if(btn.tag == kTagBtnRight) { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.allowsEditing = YES; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [self presentViewController:picker animated:YES completion:^{}]; }}#pragma mark - UIImagePickerControllerDelegate- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ if (SystemVersion < 8.0) { [self imagePickerControllerForiOS7:picker didFinishPickingMediaWithInfo:info]; return; }else{ //获取用户设备型号 BOOL isIphone4and5 = NO; //如果不是iphone5以上设备(于如果没有适配大屏,分辨率永远是568,这层拦截失效) CGFloat height = [[UIScreen mainScreen] bounds].size.height; if (height <= 568) { //获取用户设备具体型号 struct utsname systemInfo; uname(&systemInfo); NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; //iphone5/iphone5c/iphone4s设备 if ([deviceString isEqualToString:@" iPhone5,3"]||[deviceString isEqualToString:@"iPhone5,4"]||[deviceString isEqualToString:@"iPhone5,1"]||[deviceString isEqualToString:@"iPhone5,2"]||[deviceString isEqualToString:@"iPhone4,1"]) { isIphone4and5 = YES; } } if (isIphone4and5) { [self imagePickerControllerForiOS7:picker didFinishPickingMediaWithInfo:info]; return; } } //1.获取选择的图片 UIImage * image = [info objectForKey:UIImagePickerControllerOriginalImage]; //2.初始化一个监测器 CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}]; [picker dismissViewControllerAnimated:YES completion:^{ //监测到的结果数组 NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]]; if (features.count >=1) { /**结果对象 */ CIQRCodeFeature *feature = [features objectAtIndex:0]; NSString *scannedResult = feature.messageString; if (scannedResult.length) { [self readQRCodeActionWithCode:scannedResult]; } else { [[[UIAlertView alloc] initWithTitle:AppLocalizedString(@"AppName") message:AppLocalizedString(@"Decoding image file is not correct") delegate:nil cancelButtonTitle:AppLocalizedString(@"OK") otherButtonTitles:nil, nil]show]; } }else { [[[UIAlertView alloc] initWithTitle:AppLocalizedString(@"AppName") message:AppLocalizedString(@"Decoding image file is not correct") delegate:nil cancelButtonTitle:AppLocalizedString(@"OK") otherButtonTitles:nil, nil]show]; } }]; [picker removeFromParentViewController];}- (void)imagePickerControllerForiOS7:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ [picker dismissViewControllerAnimated:YES completion:^{ UIImage * image = [info objectForKey:UIImagePickerControllerOriginalImage]; //初始化 ZBarReaderController * read = [ZBarReaderController new]; //设置代理 read.readerDelegate = self; CGImageRef cgImageRef = image.CGImage; ZBarSymbol * symbol = nil; idresults = [read scanImage:cgImageRef];
if ([info count]>2) {
int quality = 0;
for(ZBarSymbol *sym in results) {
int q = sym.quality;
if(quality < q) {
quality = q;
symbol = sym;
}
}
}else {
for(symbol in results)
break;
}
if (symbol != nil) {
NSString *symbolStr = [NSString stringWithCString:[symbol.data cStringUsingEncoding: NSShiftJISStringEncoding] encoding:NSUTF8StringEncoding];
[self readQRCodeActionWithCode:symbolStr];
//不用代理,统一在这里执行
// if(_codeScanDelegate && [_codeScanDelegate respondsToSelector:@selector(CodeScanFinishWith:andResultCode:)]) {
// [_codeScanDelegate CodeScanFinishWith:self andResultCode:symbolStr];
// }
} else {
[[[UIAlertView alloc] initWithTitle:AppLocalizedString(@"AppName") message:AppLocalizedString(@"Decoding image file is not correct") delegate:nil cancelButtonTitle:AppLocalizedString(@"OK") otherButtonTitles:nil, nil]show];
}
}];
[picker removeFromParentViewController];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:^{}];
}