二維碼掃描

原生二維碼掃描

#define QRCodeWidth 260.0 //正方形二維碼的邊長
#define SCREENWidth [UIScreen mainScreen].bounds.size.width
#define SCREENHeight [UIScreen mainScreen].bounds.size.height

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property (strong,nonatomic)AVCaptureDevice * device;
@property (strong,nonatomic)AVCaptureDeviceInput * input;
@property (strong,nonatomic)AVCaptureMetadataOutput * output;
@property (strong,nonatomic)AVCaptureSession * session;
@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupMaskView];//設(shè)置掃描區(qū)域之外的陰影視圖
    [self setupScanWindowView];//設(shè)置掃描二維碼區(qū)域的視圖
    [self beginScanning];//開始掃二維碼
}

2-1 設(shè)置掃描區(qū)域之外的陰影視圖

- (void)setupMaskView
{
    //設(shè)置統(tǒng)一的視圖顏色和視圖的透明度
    UIColor *color = [UIColor blackColor];
    float alpha = 0.7;
    
    //設(shè)置掃描區(qū)域外部上部的視圖
    UIView *topView = [[UIView alloc]init];
    topView.frame = CGRectMake(0, 64, SCREENWidth, (SCREENHeight-64-QRCodeWidth)/2.0-64);
    topView.backgroundColor = color;
    topView.alpha = alpha;
    
    //設(shè)置掃描區(qū)域外部左邊的視圖
    UIView *leftView = [[UIView alloc]init];
    leftView.frame = CGRectMake(0, 64+topView.frame.size.height, (SCREENWidth-QRCodeWidth)/2.0,QRCodeWidth);
    leftView.backgroundColor = color;
    leftView.alpha = alpha;
    
    //設(shè)置掃描區(qū)域外部右邊的視圖
    UIView *rightView = [[UIView alloc]init];
    rightView.frame = CGRectMake((SCREENWidth-QRCodeWidth)/2.0+QRCodeWidth,64+topView.frame.size.height, (SCREENWidth-QRCodeWidth)/2.0,QRCodeWidth);
    rightView.backgroundColor = color;
    rightView.alpha = alpha;
    
    //設(shè)置掃描區(qū)域外部底部的視圖
    UIView *botView = [[UIView alloc]init];
    botView.frame = CGRectMake(0, 64+QRCodeWidth+topView.frame.size.height,SCREENWidth,SCREENHeight-64-QRCodeWidth-topView.frame.size.height);
    botView.backgroundColor = color;
    botView.alpha = alpha;
    
    //將設(shè)置好的掃描二維碼區(qū)域之外的視圖添加到視圖圖層上
    [self.view addSubview:topView];
    [self.view addSubview:leftView];
    [self.view addSubview:rightView];
    [self.view addSubview:botView];
}

2-2 設(shè)置掃描二維碼區(qū)域的視圖

- (void)setupScanWindowView
{
    //設(shè)置掃描區(qū)域的位置(考慮導航欄和電池條的高度為64)
    UIView *scanWindow = [[UIView alloc]initWithFrame:CGRectMake((SCREENWidth-QRCodeWidth)/2.0,(SCREENHeight-QRCodeWidth-64)/2.0,QRCodeWidth,QRCodeWidth)];
    scanWindow.clipsToBounds = YES;
    [self.view addSubview:scanWindow];
    
    //設(shè)置掃描區(qū)域的動畫效果
    CGFloat scanNetImageViewH = 241;
    CGFloat scanNetImageViewW = scanWindow.frame.size.width;
    UIImageView *scanNetImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"scan_net"]];
    scanNetImageView.frame = CGRectMake(0, -scanNetImageViewH, scanNetImageViewW, scanNetImageViewH);
    CABasicAnimation *scanNetAnimation = [CABasicAnimation animation];
    scanNetAnimation.keyPath =@"transform.translation.y";
    scanNetAnimation.byValue = @(QRCodeWidth);
    scanNetAnimation.duration = 1.0;
    scanNetAnimation.repeatCount = MAXFLOAT;
    [scanNetImageView.layer addAnimation:scanNetAnimation forKey:nil];
    [scanWindow addSubview:scanNetImageView];
    
    //設(shè)置掃描區(qū)域的四個角的邊框
    CGFloat buttonWH = 18;
    UIButton *topLeft = [[UIButton alloc]initWithFrame:CGRectMake(0,0, buttonWH, buttonWH)];
    [topLeft setImage:[UIImage imageNamed:@"scan_1"]forState:UIControlStateNormal];
    [scanWindow addSubview:topLeft];
    
    UIButton *topRight = [[UIButton alloc]initWithFrame:CGRectMake(QRCodeWidth - buttonWH,0, buttonWH, buttonWH)];
    [topRight setImage:[UIImage imageNamed:@"scan_2"]forState:UIControlStateNormal];
    [scanWindow addSubview:topRight];
    
    UIButton *bottomLeft = [[UIButton alloc]initWithFrame:CGRectMake(0,QRCodeWidth - buttonWH, buttonWH, buttonWH)];
    [bottomLeft setImage:[UIImage imageNamed:@"scan_3"]forState:UIControlStateNormal];
    [scanWindow addSubview:bottomLeft];
    
    UIButton *bottomRight = [[UIButton alloc]initWithFrame:CGRectMake(QRCodeWidth-buttonWH,QRCodeWidth-buttonWH, buttonWH, buttonWH)];
    [bottomRight setImage:[UIImage imageNamed:@"scan_4"]forState:UIControlStateNormal];
    [scanWindow addSubview:bottomRight];
}

2-3 開始掃二維碼

-(void)beginScanning
{
    //獲取攝像設(shè)備
    AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //創(chuàng)建輸入流
    AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    if (!input) return;
    //創(chuàng)建輸出流
    AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
    
    //特別注意的地方:有效的掃描區(qū)域困介,定位是以設(shè)置的右頂點為原點。屏幕寬所在的那條線為y軸蘸际,屏幕高所在的線為x軸
    CGFloat x = ((SCREENHeight-QRCodeWidth-64)/2.0)/SCREENHeight;
    CGFloat y = ((SCREENWidth-QRCodeWidth)/2.0)/SCREENWidth;
    CGFloat width = QRCodeWidth/SCREENHeight;
    CGFloat height = QRCodeWidth/SCREENWidth;
    output.rectOfInterest = CGRectMake(x, y, width, height);
    
    //設(shè)置代理在主線程里刷新
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    //初始化鏈接對象
    _session = [[AVCaptureSession alloc]init];
    //高質(zhì)量采集率
    [_session setSessionPreset:AVCaptureSessionPresetHigh];
    
    [_session addInput:input];
    [_session addOutput:output];
    //設(shè)置掃碼支持的編碼格式(如下設(shè)置條形碼和二維碼兼容)
    output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code];
    
    AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
    layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
    layer.frame=self.view.layer.bounds;
    [self.view.layer insertSublayer:layer atIndex:0];
    //開始捕獲
    [_session startRunning];
}

3.遵守協(xié)議

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    NSString *stringValue;
    if (metadataObjects.count >0) {
        //停止掃描
        [self.session stopRunning];
        AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
        stringValue = metadataObject.stringValue;
        [_session stopRunning];
    }else
    {
        NSLog(@"沒數(shù)據(jù)");
    }
}

5.若是報錯 -This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
是因為沒開啟相機權(quán)限
解決方法:
將info.plist文件以Source Code打開 (右鍵 選擇Open As)
復制粘貼下面 key value即可

<key>NSCameraUsageDescription</key>
<string>cameraDesciption</string>

celan 運行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末座哩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子粮彤,更是在濱河造成了極大的恐慌根穷,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件导坟,死亡現(xiàn)場離奇詭異屿良,居然都是意外死亡,警方通過查閱死者的電腦和手機惫周,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門尘惧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人递递,你說我怎么就攤上這事喷橙。” “怎么了登舞?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵贰逾,是天一觀的道長。 經(jīng)常有香客問我菠秒,道長疙剑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮言缤,結(jié)果婚禮上嚼蚀,老公的妹妹穿的比我還像新娘。我一直安慰自己轧简,他們只是感情好驰坊,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哮独,像睡著了一般。 火紅的嫁衣襯著肌膚如雪察藐。 梳的紋絲不亂的頭發(fā)上皮璧,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音分飞,去河邊找鬼悴务。 笑死,一個胖子當著我的面吹牛譬猫,可吹牛的內(nèi)容都是我干的讯檐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼染服,長吁一口氣:“原來是場噩夢啊……” “哼别洪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柳刮,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挖垛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秉颗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痢毒,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年蚕甥,在試婚紗的時候發(fā)現(xiàn)自己被綠了哪替。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡菇怀,死狀恐怖凭舶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敏释,我是刑警寧澤库快,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站钥顽,受9級特大地震影響义屏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一闽铐、第九天 我趴在偏房一處隱蔽的房頂上張望蝶怔。 院中可真熱鬧,春花似錦兄墅、人聲如沸踢星。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沐悦。三九已至五督,卻和暖如春藏否,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背充包。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工副签, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人基矮。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓淆储,卻偏偏與公主長得像,于是被迫代替她去往敵國和親家浇。 傳聞我的和親對象是個殘疾皇子本砰,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容