iOS學習——iOS原生實現二維碼掃描

来源:https://www.cnblogs.com/mukekeheart/archive/2018/03/13/8556600.html
-Advertisement-
Play Games

最近項目上需要開發掃描二維碼進行簽到的功能,主要用於開會簽到的場景,所以為了避免作弊,我們再開發時只採用直接掃描的方式,並且要屏蔽從相冊讀取圖片,此外還在二維碼掃描成功簽到時後臺會自動上傳用戶的當前地點,如何自動定位獲取用戶的當前地點在上一篇隨筆iOS學習——自動定位中已經講過了,本文就簡單地說一下 ...


  最近項目上需要開發掃描二維碼進行簽到的功能,主要用於開會簽到的場景,所以為了避免作弊,我們再開發時只採用直接掃描的方式,並且要屏蔽從相冊讀取圖片,此外還在二維碼掃描成功簽到時後臺會自動上傳用戶的當前地點,如何自動定位獲取用戶的當前地點在上一篇隨筆iOS學習——自動定位中已經講過了,本文就簡單地說一下如何利用iOS原生的模塊實現二維碼的掃描。

  二維碼掃描是很多應用都會實現的功能,比較著名的第三方開源庫是Google出品的ZXing,其的OC的移植版本是ZXingObjc。iOS系統原生的二維碼掃描模塊是在iOS7之後推出的,它主要是利用iOS設備的後置攝像頭進行實現的。

  要調用系統的攝像頭識別二維碼,我們需要導入系統的AVFoundation庫。使用系統的攝像頭,我們一般的需要以下五個對象:一個後置攝像頭設備(AVCaptureDevice)、一個輸入(AVCaptureDeviceInput)、一個輸出(AVCaptureMetadataOutput)、一個協調控制器(AVCaptureSession)、一個預覽層(AVCaptureVideoPreviewLayer),此外為了更好的體驗效果,我們加入了縮放手勢,在進行二維碼掃描的時候可以手動進行縮放掃描區域,以獲得更好的掃描效果。

@interface CJScanQRCodeViewController () <AVCaptureMetadataOutputObjectsDelegate>

@property (strong, nonatomic) AVCaptureDevice * device; //捕獲設備,預設後置攝像頭
@property (strong, nonatomic) AVCaptureDeviceInput * input; //輸入設備
@property (strong, nonatomic) AVCaptureMetadataOutput * output;//輸出設備,需要指定他的輸出類型及掃描範圍
@property (strong, nonatomic) AVCaptureSession * session; //AVFoundation框架捕獲類的中心樞紐,協調輸入輸出設備以獲得數據
@property (strong, nonatomic) AVCaptureVideoPreviewLayer * previewLayer;//展示捕獲圖像的圖層,是CALayer的子類

@property (strong, nonatomic) UIPinchGestureRecognizer *pinchGes;//縮放手勢
@property (assign, nonatomic) CGFloat scanRegion_W;//二維碼正方形掃描區域的寬度,根據不同機型適配

@end

  首先,我們是需要進行對我們的一些設備進行配置,比喻需要用到自動定位,就需要對定位信息進行配置,接著對二維碼掃描的相關設備進行配置,然後對我們的縮放手勢進行設置,都配置完之後,直接開始啟動二維碼掃描就可以了,成功掃碼並識別到信息時候會調用對應的 AVCaptureMetadataOutputObjectsDelegate 代理的 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection 方法進行後期處理,我們需要實現代理的該方法,在其中編寫我們需要的功能邏輯。

- (void)viewDidLoad {
    [super viewDidLoad];
    //頁面標題
    self.title = @"掃一掃";
    //配置定位信息
    [self configLocation];
    //配置二維碼掃描
    [self configBasicDevice];
    //配置縮放手勢
    [self configPinchGes];
    //開始啟動
    [self.session startRunning];
}

  關於二維碼掃描設備的配置流程,一般地,我們先將需要的五大設備進行初始化,然後需要進行對應的設置沒具體的設置流程和方法見下麵的代碼和註釋。

- (void)configBasicDevice{
    //預設使用後置攝像頭進行掃描,使用AVMediaTypeVideo表示視頻
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //設備輸入 初始化
    self.input = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:nil];
    //設備輸出 初始化,並設置代理和回調,當設備掃描到數據時通過該代理輸出隊列,一般輸出隊列都設置為主隊列,也是設置了回調方法執行所在的隊列環境
    self.output = [[AVCaptureMetadataOutput alloc]init];
    [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    //會話 初始化,通過 會話 連接設備的 輸入 輸出,並設置採樣質量為 高
    self.session = [[AVCaptureSession alloc]init];
    [self.session setSessionPreset:AVCaptureSessionPresetHigh];
    //會話添加設備的 輸入 輸出,建立連接
    if ([self.session canAddInput:self.input]) {
        [self.session addInput:self.input];
    }
    if ([self.session canAddOutput:self.output]) {
        [self.session addOutput:self.output];
    }
    //指定設備的識別類型 這裡只指定二維碼識別這一種類型 AVMetadataObjectTypeQRCode
    //指定識別類型這一步一定要在輸出添加到會話之後,否則設備的課識別類型會為空,程式會出現崩潰
    [self.output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
    //設置掃描信息的識別區域,本文設置正中央的一塊正方形區域,該區域寬度是scanRegion_W
    //這裡考慮了導航欄的高度,所以計算有點麻煩,識別區域越小識別效率越高,所以不設置整個屏幕
    CGFloat navH = self.navigationController.navigationBar.bounds.size.height;
    CGFloat viewH = ZYAppHeight - navH;
    CGFloat scanViewH = self.scanRegion_W;
    [self.output setRectOfInterest:CGRectMake((ZYAppWidth-scanViewH)/(2*ZYAppWidth), (viewH-scanViewH)/(2*viewH), scanViewH/ZYAppWidth, scanViewH/viewH)];
    //預覽層 初始化,self.session負責驅動input進行信息的採集,layer負責把圖像渲染顯示
    //預覽層的區域設置為整個屏幕,這樣可以方便我們進行移動二維碼到掃描區域,在上面我們已經對我們的掃描區域進行了相應的設置
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
    self.previewLayer.frame = CGRectMake(0, 0, ZYAppWidth, ZYAppHeight);
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:self.previewLayer];
    //掃描框 和掃描線的佈局和設置,模擬正在掃描的過程,這一塊加不加不影響我們的效果,只是起一個直觀的作用
    TNWCameraScanView *clearView = [[TNWCameraScanView alloc]initWithFrame:self.view.frame navH:navH];
    [self.view addSubview:clearView];
    //掃描框下麵的信息label佈局
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, (viewH+scanViewH)/2+10.0f, ZYAppWidth, 20.0f)];
    label.text = @"掃一掃功能僅用於會議簽到";
    label.font = FONT(15.0f);
    label.textColor = [UIColor whiteColor];
    label.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:label];
}

  接下來我們看一下如何配置我們的縮放手勢,這個相對而言就很簡單了,我們直接在self.view上添加一個縮放手勢,併在對應的方法中對我們的相機設備的焦距進行修改就達到了縮放的目的。

- (void)configPinchGes{
    self.pinchGes = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchDetected:)];
    [self.view addGestureRecognizer:self.pinchGes];
}

- (void)pinchDetected:(UIPinchGestureRecognizer*)recogniser{
    if (!_device){
        return;
    }
   //對手勢的狀態進行判斷
    if (recogniser.state == UIGestureRecognizerStateBegan){
        _initScale = _device.videoZoomFactor;
    }
    //相機設備在改變某些參數前必須先鎖定,直到改變結束才能解鎖
    NSError *error = nil;
    [_device lockForConfiguration:&error]; //鎖定相機設備
    if (!error) {
        CGFloat zoomFactor; //縮放因數
        CGFloat scale = recogniser.scale;
        if (scale < 1.0f) {
            zoomFactor = self.initScale - pow(self.device.activeFormat.videoMaxZoomFactor, 1.0f - recogniser.scale);
        } else {
            zoomFactor = self.initScale + pow(self.device.activeFormat.videoMaxZoomFactor, (recogniser.scale - 1.0f) / 2.0f);
        }
        zoomFactor = MIN(15.0f, zoomFactor);
        zoomFactor = MAX(1.0f, zoomFactor);
        _device.videoZoomFactor = zoomFactor;
        [_device unlockForConfiguration];
    }
} 

  最後,我們需要重寫代理的回調方法,實現我們在成功識別二維碼之後要實現的功能邏輯。這樣我們的二維碼掃描功能就完成了。

#pragma mark - AVCaptureMetadataOutputObjectsDelegate
//後置攝像頭掃描到二維碼的信息
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    [self.session stopRunning];   //停止掃描
    if ([metadataObjects count] >= 1) {
        //數組中包含的都是AVMetadataMachineReadableCodeObject 類型的對象,該對象中包含解碼後的數據
        AVMetadataMachineReadableCodeObject *qrObject = [metadataObjects lastObject];
        //拿到掃描內容在這裡進行個性化處理
        NSString *result = qrObject.stringValue;
        //解析數據進行處理並實現相應的邏輯
        //代碼省略
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • MySQL管理表和索引 創建表: 1、直接定義一張空表; 2、從其它表中查詢出數據,並以之創建新表; 3、以其它表為模板創建一個空表; 創建表時定義其中的欄位類型時為數值時 加 unisined表示無符號數值類型(只有正數)。 例如create table 表名 ( id int unisgned  ...
  • [root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_centos data]# /etc/init.d/mysqld restart Shutting d... ...
  • 1.啟動mysql時,一直不成功,查看錯誤日誌 /var/log/mysql/error.log 2.主要的錯誤信息有如下幾條: 3.查詢後是因為記憶體不足,查看記憶體 增加swap交換空間解決問題: 4.增加自動掛載: 在文件/etc/fstab中加入 /swapfile swap swap defa ...
  • ...
  • 前言 今天筆者要介紹的是hive相關的內容,會從概念到安裝,然後之後再一步一步深入介紹相關知識。 一、hive的相關介紹 1.1hive的相關定義 hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張資料庫表,並提供簡單的sql查詢功能,可以將sql語句轉換為MapRedu ...
  • Android P開始逐步限制特定非 SDK 介面的訪問許可權,並要求開發者使用公開 API 里的替代介面。針對該特性,更新了Android遠程桌面助手,目前支持Android P開發者預覽版。 ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...