iOS-仿微信掃一掃遇伞、長按識別二維碼鸠珠,以及一句話生成二維碼

iOS-仿微信掃一掃秋麸、長按識別二維碼,以及一句話生成二維碼

1驯耻、二維碼簡介
在iOS中二維碼的實質是一個字符串,一般用于制作名片孽水,手機電商購物鏈家城看、微信掃一掃测柠,微信支付缘滥,QQ加好友,以及移動支付等赃阀。其中用的最廣的當然是大家熟知的支付寶擎颖,微信和QQ了搂捧。既然二維碼用途這么廣,很多APP里面都或多或少有二維碼的存在王凑,那么下面就掃一掃二維碼聋丝,長按識別二維碼,以及生成二維碼從無到有的過程百姓,和遇到的坑分享給大家每篷。

2焦读、進入主題
在一定的程度之后,相信大家都有封裝的思想仑嗅,那么本文有幾個分裝介紹給大家:
JWDQRCodeViewController.h 掃一掃控制器分裝
JWDPreView.h 掃一掃動畫界面封裝
JWDCreatQRCodeView.h 生成二維碼封裝
下面就這三個類進行介紹

3仓技、JWDQRCodeViewController 掃一掃控制器分裝

JWDQRCodeViewController.h
.h 沒什么可說的,給外界的接口

#import <UIKit/UIKit.h>

@interface JWDQRCodeViewController : UIViewController
- (instancetype)initWithFrame:(CGRect)frame;
@end

JWDQRCodeViewController.m
導入相應的頭文件阔逼,必須的變量
其中SafariServices/SafariServices.h框架用于url跳轉控制器地沮,是iOS9之后的新特性,可以方便打開相應的網(wǎng)頁界面危融。

#import "JWDQRCodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "JWDPreView.h"
#import <SafariServices/SafariServices.h>

@interface JWDQRCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property(nonatomic, strong)AVCaptureDeviceInput        *deviceInput;//!< 攝像頭輸入
@property(nonatomic, strong)AVCaptureMetadataOutput     *metadataOutput;//!< 輸出
@property(nonatomic, strong)AVCaptureSession            *session;//!< 會話
@property(nonatomic, strong)AVCaptureVideoPreviewLayer  *previewLayer;//!< 預覽
@property(nonatomic, strong)JWDPreView                  *preView;//!< <#value#>

@end
@implementation JWDQRCodeViewController

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super init];
    if (self) {
        self.view.frame = frame;
        [self initUiConfig];
    }
    return self;
}

-(void)initUiConfig {

    // 默認為后置攝像頭
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    self.deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:NULL];
    // 解析輸入的數(shù)據(jù)
    self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
    [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    // 會話
    self.session = [[AVCaptureSession alloc] init];
    if ([self.session canAddInput:self.deviceInput]){
        [self.session addInput:self.deviceInput];
    }
    if([self.session canAddOutput:self.metadataOutput]){
        [self.session addOutput:self.metadataOutput];
    }
    // 設置數(shù)據(jù)采集質量
    self.session.sessionPreset = AVCaptureSessionPresetHigh;
    // 設置需要解析的數(shù)據(jù)類型,二維碼
    self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
    JWDPreView *preView = [[JWDPreView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
    self.preView = preView;
    [self.view addSubview:preView];
    preView.session = self.session;
    preView.backPreView = ^(JWDPreView *backPreView){
        [self.session stopRunning];
        [self dismissViewControllerAnimated:YES completion:nil];
        // 銷毀定時器
        if (backPreView.timer){
            [backPreView.timer invalidate];
            backPreView.timer = nil;
        }
    };
    [self.session startRunning];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    
    for (AVMetadataMachineReadableCodeObject *obj in metadataObjects) {
        SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
        [self presentViewController:safariVC animated:YES completion:nil];
    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

上面建立采集二維碼的過濾器蛋勺,和基本的輸入和輸出的建立率寡,鏈接輸入和輸出的會話建立冶共,以及開啟和適當?shù)臅r候關閉會話的處理。

切記這里要使用攝像頭家卖,所以要者info.plist 里面設置訪問權限

Paste_Image.png

在解析獲取捕捉到的信息后會在代理 AVCaptureMetadataOutputObjectsDelegate的下面方法里面獲取信息

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    
    for (AVMetadataMachineReadableCodeObject *obj in metadataObjects) {
        SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
        [self presentViewController:safariVC animated:YES completion:nil];
    }
}

獲取到相應的數(shù)據(jù)后可以在這里面做一些業(yè)務邏輯上荡,本人在這里就用到SFSafariViewController控制器來代開網(wǎng)頁

好了下面介紹掃描界面
4.JWDPreView 掃一掃動畫界面封裝

JWDPreView.h

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@class JWDPreView;

typedef void(^backPreView) (JWDPreView *preView);

@interface JWDPreView : UIView

- (instancetype)initWithFrame:(CGRect)frame;

@property(nonatomic, strong)AVCaptureSession    *session;//!< 渲染會話層
@property (nonatomic, copy) backPreView         backPreView;//!< 返回按鈕回調
@property(nonatomic, strong)NSTimer             *timer;//!< <#value#>

@end

JWDPreView.m

#import "JWDPreView.h"

@interface JWDPreView ()
{
    UIImageView   *_imageView;
    UIImageView   *_lineImageView;
    UIButton      *_backBtn;
}

@end

@implementation JWDPreView

// 修改當前View 的圖層類別
+(Class)layerClass {

    return [AVCaptureVideoPreviewLayer class];
}

-(void)setSession:(AVCaptureSession *)session {

    _session = session;
    AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
    layer.session = session;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initUiConfig];
    }
    return self;
}
- (void)initUiConfig {
    
    _backBtn = [[UIButton alloc] initWithFrame:CGRectMake(30, 50, 40, 20)];
    [_backBtn setTitle:@"返回" forState:UIControlStateNormal];
    [_backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [_backBtn addTarget:self action:@selector(backButtonDid) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:_backBtn];
    
    _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pick_bg.png"]];
    _imageView.frame = CGRectMake(self.bounds.size.width * 0.5 - 140, self.bounds.size.height * 0.5 - 140, 280, 280);
    [self addSubview:_imageView];
    
    _lineImageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 10, 220, 2)];
    _lineImageView.image = [UIImage imageNamed:@"line.png"];
    [_imageView addSubview:_lineImageView];
    
    _timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(animation) userInfo:nil repeats:YES];
}
- (void)animation
{
    [UIView animateWithDuration:2.8 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        
        _lineImageView.frame = CGRectMake(30, 260, 220, 2);
        
    } completion:^(BOOL finished) {
        _lineImageView.frame = CGRectMake(30, 10, 220, 2);
    }];
}

- (void)backButtonDid {

    if (self.backPreView){
        self.backPreView(self);
    }
}

@end

在.m中一個重點就是 掃一掃界面瀏覽layer的修改

Paste_Image.png

在UIView中默認的 為 [CALayer class]而這不是二維碼掃描所需的layer,所以修改逛薇。這樣強轉后的layer才有session的會話設置

// 修改當前View 的圖層類別
+(Class)layerClass {

   return [AVCaptureVideoPreviewLayer class];
}

-(void)setSession:(AVCaptureSession *)session {

   _session = session;
   AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
   layer.session = session;
}

5.JWDCreatQRCodeView 生成二維碼封裝

JWDCreatQRCodeView.h

一句話生成二維碼的接口

#import <UIKit/UIKit.h>

@interface JWDQRCodeViewController : UIViewController
- (instancetype)initWithFrame:(CGRect)frame;
@end

JWDCreatQRCodeView.m

#import "JWDQRCodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "JWDPreView.h"
#import <SafariServices/SafariServices.h>

@interface JWDQRCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property(nonatomic, strong)AVCaptureDeviceInput        *deviceInput;//!< 攝像頭輸入
@property(nonatomic, strong)AVCaptureMetadataOutput     *metadataOutput;//!< 輸出
@property(nonatomic, strong)AVCaptureSession            *session;//!< 會話
@property(nonatomic, strong)AVCaptureVideoPreviewLayer  *previewLayer;//!< 預覽
@property(nonatomic, strong)JWDPreView                  *preView;//!< <#value#>

@end

@implementation JWDQRCodeViewController

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super init];
    if (self) {
        self.view.frame = frame;
        [self initUiConfig];
    }
    return self;
}

-(void)initUiConfig {

    // 默認為后置攝像頭
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    self.deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:NULL];
    // 解析輸入的數(shù)據(jù)
    self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
    [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    // 會話
    self.session = [[AVCaptureSession alloc] init];
    if ([self.session canAddInput:self.deviceInput]){
        [self.session addInput:self.deviceInput];
    }
    if([self.session canAddOutput:self.metadataOutput]){
        [self.session addOutput:self.metadataOutput];
    }
    // 設置數(shù)據(jù)采集質量
    self.session.sessionPreset = AVCaptureSessionPresetHigh;
    // 設置需要解析的數(shù)據(jù)類型啤呼,二維碼
    self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
    JWDPreView *preView = [[JWDPreView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
    self.preView = preView;
    [self.view addSubview:preView];
    preView.session = self.session;
    preView.backPreView = ^(JWDPreView *backPreView){
        [self.session stopRunning];
        [self dismissViewControllerAnimated:YES completion:nil];
        // 銷毀定時器
        if (backPreView.timer){
            [backPreView.timer invalidate];
            backPreView.timer = nil;
        }
    };
    [self.session startRunning];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    
    for (AVMetadataMachineReadableCodeObject *obj in metadataObjects) {
        SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
        [self presentViewController:safariVC animated:YES completion:nil];
    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
Paste_Image.png
Paste_Image.png

好了官扣,這樣介紹完了惕蹄,上面的幾個類就可以實現(xiàn)功能治专。

6.下面介紹
ViewController繼承基本的全部功能

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "JWDPreView.h"
#import <SafariServices/SafariServices.h>
#import "JWDQRCodeViewController.h"
#import "JWDCreatQRCodeView.h"

@interface ViewController ()

@property(nonatomic, strong)UIButton              *code;//!< <#value#>
@property(nonatomic, strong)UIButton              *code1;//!< <#value#>
@property(nonatomic, strong)JWDCreatQRCodeView    *creatQRCodeView;//!< <#value#>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    CGFloat X = (self.view.frame.size.width - 2*100)/3.0;
    
    _code = [[UIButton alloc] initWithFrame:CGRectMake(X, 100, 100, 60)];
    _code.backgroundColor = [UIColor yellowColor];
    [_code setTitle:@"掃一掃" forState:UIControlStateNormal];
    [_code setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [_code addTarget:self action:@selector(codeDidClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_code];
    
    
    _code1 = [[UIButton alloc] initWithFrame:CGRectMake(2*X + 100, 100, 100, 60)];
    _code1.backgroundColor = [UIColor yellowColor];
    [_code1 setTitle:@"生成二維碼" forState:UIControlStateNormal];
    [_code1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [_code1 addTarget:self action:@selector(code1DidClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_code1];
    
}
- (void)codeDidClick {
    
    JWDQRCodeViewController *QRCodeVC = [[JWDQRCodeViewController alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    [self presentViewController:QRCodeVC animated:YES completion:nil];

}

- (void)code1DidClick {

    UIView *qrCodeView = [[UIView alloc] initWithFrame:CGRectMake((self.view.frame.size.width-200)*0.5, 250, 200, 220)];
    [self.view addSubview:qrCodeView];
    
    JWDCreatQRCodeView *creatQRCodeView = [[JWDCreatQRCodeView alloc] initWithFrame:CGRectMake(0, 0, 200, 200) withQRCodeString:@"http://www.reibang.com/users/5b9953c3d3ad/latest_articles" withQRCodeCenterImage:@"me"];
    self.creatQRCodeView = creatQRCodeView;
    
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, 200, 20)];
    label.text = @"長按識別二維碼看靠,跳轉網(wǎng)頁";
    label.font = [UIFont systemFontOfSize:12];
    label.textAlignment = NSTextAlignmentCenter;
    [qrCodeView addSubview:label];
    
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDid)];
    creatQRCodeView.userInteractionEnabled = YES;
    [creatQRCodeView addGestureRecognizer:longPress];
    
    [qrCodeView addSubview:creatQRCodeView];
    
}

- (void)longPressDid{
    
    // 0.創(chuàng)建上下文
    CIContext *context = [[CIContext alloc] init];
    
    // 1.創(chuàng)建一個探測器
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
    
    // 2.直接開始識別圖片,獲取圖片特征
    CIImage *imageCI = [[CIImage alloc] initWithImage:self.creatQRCodeView.image];
    NSArray<CIFeature *> *features = [detector featuresInImage:imageCI];
    CIQRCodeFeature *codef = (CIQRCodeFeature *)features.firstObject;
    
    // 彈框
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"識別圖中二維碼" message:nil preferredStyle:UIAlertControllerStyleAlert];
    [alertC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"取消");
    }]];
    __weak ViewController *weakSelf = self;
    [alertC addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:codef.messageString]];
        [weakSelf presentViewController:safariVC animated:YES completion:nil];
    }]];
    [self presentViewController:alertC animated:YES completion:nil];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

完結,小小的一個demo嗦哆,可能還有不完善的地方老速,當你發(fā)現(xiàn)了還請不吝賜教,謝謝橘券。
最后奉上demo 地址 https://github.com/weidongjiang/JWD-QRCode

如果對你有用旁舰,解決了你的問題,得到了幫助箭窜,還請star磺樱。相互學習。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末芜辕,一起剝皮案震驚了整個濱河市活孩,隨后出現(xiàn)的幾起案子乖仇,更是在濱河造成了極大的恐慌询兴,老刑警劉巖诗舰,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜀铲,居然都是意外死亡属百,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門厌丑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怒竿,“玉大人扩氢,你說我怎么就攤上這事÷疾颍” “怎么了双饥?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長领舰。 經(jīng)常有香客問我迟螺,道長,這世上最難降的妖魔是什么锉桑? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任民轴,我火速辦了婚禮,結果婚禮上后裸,老公的妹妹穿的比我還像新娘微驶。我一直安慰自己,他們只是感情好因苹,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布扶檐。 她就那樣靜靜地躺著,像睡著了一般官卡。 火紅的嫁衣襯著肌膚如雪醋虏。 梳的紋絲不亂的頭發(fā)上哮翘,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天饭寺,我揣著相機與錄音,去河邊找鬼限煞。 笑死员凝,一個胖子當著我的面吹牛,可吹牛的內容都是我干的旺上。 我是一名探鬼主播糖埋,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼征候!你這毒婦竟也來了?” 一聲冷哼從身側響起兆解,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤痪宰,失蹤者是張志新(化名)和其女友劉穎畔裕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扮饶,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡甜无,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年岂丘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铜邮。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡寨蹋,死狀恐怖,靈堂內的尸體忽然破棺而出秸苗,到底是詐尸還是另有隱情运褪,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布胁后,位于F島的核電站嗦枢,受9級特大地震影響文虏,放射性物質發(fā)生泄漏殖演。R本人自食惡果不足惜年鸳,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望彼棍。 院中可真熱鬧膳算,春花似錦、人聲如沸华匾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至葱跋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矢否。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工脑溢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屑彻,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓粪薛,卻偏偏與公主長得像蝶防,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淮椰,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容