1、為什么使用二維碼?
在手機客戶端應用里,對二維碼的使用也比較多。常見的功能有物品信息查詢,登錄信息驗證,掃描登錄,掃描支付等。但是為什么使用它呢?
*二維碼包含更多的信息量
*二維碼采用了高密度編碼
*編碼范圍廣。二維碼可以把圖片、聲音、文字、簽字、指紋等可以數字化的信息進行編碼,用條碼表示出來;可以表示多種語言文字;可表示圖像數據
*二維碼譯碼準確。我們知道二維碼只是一個圖形,想要獲取圖形中的內容就需要對圖形進行譯碼。二維碼的譯碼誤碼率為千萬分之一,而普通條形碼的譯碼誤碼率的百分之二要低很多。
*安全。能夠引入加密措施,與條形碼相比,二維碼的保密性更好。通過在二維碼中引入加密措施,更好的保護譯碼內容不被他人獲得。
因為二維碼的這些特點,在項目里用到它的地方也會比較多。
2、怎么生成二維碼?
導入CoreImage框架,通過濾鏡CIFilter生成二維碼
二維碼的內容(傳統的條形碼只能放數字):純文本,名片,URL
// 1. 實例化二維碼濾鏡
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// 2. 恢復濾鏡的默認屬性
[filter setDefaults];
// 3. 將字符串轉換成
NSData NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
// 4. 通過KVO設置濾鏡inputMessage數據
[filter setValue:data forKey:@"inputMessage"];
// 5. 獲得濾鏡輸出的圖像
CIImage *outputImage = [filter outputImage];
// 6. 將CIImage轉換成UIImage,并放大顯示
return [UIImage imageWithCIImage:outputImage scale:20.0 orientation:UIImageOrientationUp];
3、掃描二維碼
掃描二維碼就要用到系統設備,攝像頭。這就要導入AVFoundation類庫,并遵守AVCaptureMetadataOutputObjectsDelegate協議
這里會用到 AVCaptureDevice? 捕捉用的設備、AVCaptureDeviceInput 輸入通道、AVCaptureSession 對采集到的信息的處理與傳輸、AVCaptureMetadataOutput輸出通道這幾個的對象屬性,當然還需要一張預覽視圖,為了顯示正在進行掃描,還會添加動畫效果。就是我們常見的一個上下刷動的網格線或者亮度條,其實它與采集信息無關。
#import "QRCodeVC.h"
#import <AVFoundation/AVFoundation.h>
@interface QRCodeVC ( )<AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, strong) AVCaptureDevice *device;//撲捉用的設備
@property (nonatomic, strong) AVCaptureSession *session;//采集到的信息的處理與傳輸
@property (nonatomic, strong) AVCaptureMetadataOutput *output;//輸出通道
@property (nonatomic, strong)UIView *preview;//預覽視圖
@property (nonatomic, strong)UIImageView *inamationView;//動畫View
@property (nonatomic, strong) NSTimer *timer;//刷新動畫的View
@end
接下來就是對掃描界面的搭建和程序處理,代碼符上如下:
@implementation QRCodeVC
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? [self innationQRCode];
? ? //設置UI效果
? ? //添加矩形邊框
? ? UIImage *image = [UIImage imageNamed:@"qrcode_border"];
? ? //拉伸矩形
? ? image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(25, 25, 26, 26)];
? ? UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width - 80, [[UIScreen mainScreen] bounds].size.width - 80)];
? ? [imageView setImage:image];
? ? CGPoint point = self.view.center;
? ? point.y += -50;
? ? imageView.center = point;
? ? [self.view addSubview:imageView];
? ? //剪切掉超出區域的動畫
? ? imageView.clipsToBounds = YES;
? ? //動畫效果
? ? UIImageView *anamiView = [[UIImageView alloc] initWithFrame:imageView.bounds];
? ? anamiView.image = [UIImage imageNamed:@"qrcode_scanline_qrcode"];
? ? [imageView addSubview:anamiView];
? ? self.inamationView = anamiView;
? ? self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:@selector(changeInamation) userInfo:nil repeats:YES];
}
-(void)changeInamation{
? ? //改變動畫
? ? self.inamationView.frame = CGRectOffset(self.inamationView.frame, 0, 2);
? ? if (self.inamationView.frame.origin.y >= self.inamationView.frame.size.height) {
? ? ? ? self.inamationView.frame = CGRectOffset(self.inamationView.bounds, 0, -self.inamationView.frame.size.height);
? ? }
}
-(void)viewDidAppear:(BOOL)animated{
? ? [super viewDidAppear:animated];
? ? //開啟二維碼掃描,撲捉信息
? ? [self start];
}
-(void)viewWillDisappear:(BOOL)animated{
? ? [super viewWillDisappear:animated];
? ? //停止二維碼掃描
? ? [self end];
}
//初始化配置
-(void)innationQRCode{
? ? //獲取設備
? ? self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
? ? //生成Input
? ? NSError *error;
? ? self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
? ? if (error) {
? ? ? ? NSLog(@"%@", error);
? ? ? ? return;
? ? }
? ? //初始化session并且把input添加到session
? ? self.session = [[AVCaptureSession alloc] init];
? ? if ([self.session canAddInput:self.input]) {
? ? ? ? [self.session addInput:self.input];
? ? }
? ? //初始化output
? ? AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
? ? //設置?delegate
? ? dispatch_queue_t queue;
? ? queue = dispatch_queue_create("muQueue", NULL);//串行隊列
? ? [output setMetadataObjectsDelegate:self queue:queue];
? ? self.output = output;
? ? //把output添加到session中
? ? [self.session addOutput:self.output];
? ? //配置輸出的數據類型,支持所有的數據類型
? ? [self.output setMetadataObjectTypes:self.output.availableMetadataObjectTypes];
? ? //設置預覽圖層,將session中撲捉的畫面預覽
? ? AVCaptureVideoPreviewLayer *videoLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
? ? [videoLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
? ? [videoLayer setFrame:self.view.frame];
? ? //初始化預覽視圖
? ? self.preview = [[UIView alloc] initWithFrame:self.view.bounds];
? ? [self.view addSubview:self.preview];
? ? [self.preview.layer addSublayer:videoLayer];
}
- (IBAction)cancel:(id)sender { ? ?//取消掃描
? ? [self dismissViewControllerAnimated:YES completion:nil];
}
-(void)start{ ??
? ? [self.session startRunning];
? ? [self.timer fire];
}
-(void)end{
? ? [self.session stopRunning];
? ? [self.timer invalidate];
}
-(void)result:(NSString *)str{
? ? //得到結果,停止掃描,如果是網頁,打開網頁,如果是字符串,展示字符串
? ? [self.session stopRunning];
? ? UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"resultVC"];
? ? [vc setValue:str forKey:@"result"];
? ? if (self.navigationController.viewControllers.count > 1) {
? ? ? ? return;
? ? }
? ? [self.navigationController pushViewController:vc animated:YES];
}
#pragma avcapture
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
? ? id object = metadataObjects.firstObject;
? ? //只關心機器識別碼
? ? if ([object isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {
? ? ? ? AVMetadataMachineReadableCodeObject *obj = (AVMetadataMachineReadableCodeObject *)object;
? ? ? ? NSLog(@"%@", obj);
? ? ? ? [self performSelectorOnMainThread:@selector(result:) withObject:obj.stringValue waitUntilDone:NO];
? ? }
}
@end
若有錯誤,歡迎大家指出。有好的方式或代碼,歡迎大家給我留言,吾將感激涕零,哈哈。