iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 16
0
自我挑戰組

一天一蘋果,Bug 遠離我。系列 第 16

Day 16: 製作一個 QR Code 掃描器!

透過 AVFoundation 來實作一個條碼掃描器。

https://ithelp.ithome.com.tw/upload/images/20181031/20107701mrPgZMAJag.jpg

前言:

QR Code(全稱為快速響應矩陣圖碼;英語:Quick Response Code),是二維條碼的一種,於1994年由日本 DENSO WAVE 公司發明。QR 來自英文 Quick Response 的縮寫,即快速反應,因為發明者希望 QR 碼可以讓其內容快速被解碼。(資料來源:維基百科 )

https://ithelp.ithome.com.tw/upload/images/20181031/20107701CCVw97TX0f.png

天瓏書局自助刷卡說明

現今 QR Code 已經普遍於用在各個地方,使用者可以透過簡單的相機掃描就能獲取 QR Code 內的資訊,而且不需要額外安裝任何的東西。這次的教學就教大家如何打造一個 QR Code 掃瞄器。

參考文章:


#建置 QR Code 掃瞄器

開始之前我們需要 import AVFoundation 來開發我們的 QR Code 掃瞄器,首先我們先宣告三個變數:

// 用來管理擷取活動和協調輸入及輸出數據流的對象。
var captureSession: AVCaptureSession?
// 核心動畫層,可以在擷取視頻時顯示視頻。
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
// 稍後我們為了替我們的 QR Code 加上掃描框使用。
var qrCodeFrameView: UIView?

接著我們需要讓我們的實作 QRCode 掃瞄器的 ViewController 遵循 AVCaptureMetadataOutputObjectsDelegate 這個協議,稍後會用於獲取資料並解碼取得的 QR Code。這邊我們使用程式碼來解釋每一步的過程:

func configurationScanner() {
    // 取得後置鏡頭來擷取影片
    let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera], mediaType: AVMediaType.video, position: .back)
    guard let captureDevice = deviceDiscoverySession.devices.first else {
        print("無法獲取相機裝置")
        return
    }
    do {
        // 使用前一個裝置物件 captureDevice 來取得 AVCaptureDeviceInput 類別的實例 
        let input = try AVCaptureDeviceInput(device: captureDevice)
        // 實例化 AVCaptureSession,設定 captureSession 的輸入裝置
        captureSession = AVCaptureSession()
        captureSession?.addInput(input)
        // 實例化 AVCaptureMetadataOutput 物件並將其設定做為 captureSession 的輸出
        let captureMetadataOutput = AVCaptureMetadataOutput()
        captureSession?.addOutput(captureMetadataOutput)
        // 設置 delegate 為 self,並使用預設的調度佇列來執行 Call back
        // 當一個新的元資料被擷取時,便會將其轉交給委派物件做進一步處理
        // 依照 Apple 的文件,我們這邊使用 DispatchQueue.main 來取得預設的主佇列
        captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        // 告訴 App 我們所想要處理 metadata 的對象對象類型
        captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
        // 用於顯示我們的相機畫面
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
        // 設置影片在 videoPreivewLayer 的顯示方式
        videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        videoPreviewLayer?.frame = view.layer.bounds
        view.layer.addSublayer(videoPreviewLayer!)
        // 設置 QR Code 掃描框
        settingScannerFrame()
        // 開始擷取畫面
        captureSession!.startRunning()
    } catch {
        // 假如有錯誤發生、印出錯誤描述並且 return
        print(error.localizedDescription)
        return
    }
}

設置 QR Code 掃描框:

func settingScannerFrame() {
    qrCodeFrameView = UIView()
    if let qrCodeFrameView = qrCodeFrameView {
        qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
        qrCodeFrameView.layer.borderWidth = 2
        view.addSubview(qrCodeFrameView)
        // 將 qrCodeFrameView 排至畫面最前方
        view.bringSubviewToFront(qrCodeFrameView)
    }
}

如此一來我們建置 QR Code 掃瞄器的部分就到這邊結束,這時我們還需要做一件事情,iOS 需要在 App 開發者在取用相機之前,必須取得使用者的允許。所以我們會在 Info.plist 中加入 key 為Privacy - Camera Usage Description ,而後面的值我們可以稍微描述一下為什麼需要取用相機:

https://ithelp.ithome.com.tw/upload/images/20181031/20107701SQsJNG0st5.png

#獲取掃描資訊

我們先前有遵循過 AVCaptureMetadataOutput ,當我們掃描到了我們想要識別的條碼後,會調用這個 AVCaptureMetadataOutputDelegate方法,我們需要實作此 Delegate 方法,來執行 metaData 的轉換程序:

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
  // 如果 metadataObjects 是空陣列
  // 那麼將我們搜尋框的 frame 設為 zero,並且 return
  if metadataObjects.isEmpty {
          qrCodeFrameView?.frame = CGRect.zero
          return
      }
      // 如果能夠取得 metadataObjects 並且能夠轉換成 AVMetadataMachineReadableCodeObject(條碼訊息)
      if let metadataObj = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
          // 判斷 metadataObj 的類型是否為 QR Code
          if metadataObj.type == AVMetadataObject.ObjectType.qr {
              //  如果 metadata 與 QR code metadata 相同,則更新搜尋框的 frame
              let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
              qrCodeFrameView?.frame = barCodeObject!.bounds
              if let value = metadataObj.stringValue {
                  print(value)
              }
          }
      }
}

接著讓我們來測試能不能夠印出 QR Code 上的資訊吧!可以自己新增一個 QR Code 來測試功能是否正確,這邊我提供一個 QR Code 給大家測試:

https://ithelp.ithome.com.tw/upload/images/20181031/20107701daNnnlG3BG.png

鐵人賽加油!!!

這邊我為了測試結果,所以我在掃描到 QR Code 的時候跳出一個 AlertController,並且顯示我們所獲取的資訊:


後記:

那麼這次的教學就到這邊結束了,目前我們能夠獲取 QR Code 上面的資訊,下次教學我們會額外對這個 QRCode 的掃瞄器進行額外的設定,結合出一些新的功能,希望經由這次教學大家能夠學會開發一個能夠掃條碼的應用程式。


上一篇
Day 15: 將我們的 Storyboard 切割吧!
下一篇
Day 17: 寫一個易讀的表單視圖!
系列文
一天一蘋果,Bug 遠離我。30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Andy Tsai
iT邦新手 5 級 ‧ 2018-10-31 13:33:21

噢噢噢 JJ

歐歐歐 https://ithelp.ithome.com.tw/upload/images/20181031/20107701QE0ByyU6U8.png

Andy Tsai iT邦新手 5 級 ‧ 2018-10-31 13:49:28 檢舉

阿餒母湯啦~ https://ithelp.ithome.com.tw/upload/images/20181031/20107702GHr1ED912N.png

我認輸 https://ithelp.ithome.com.tw/upload/images/20181031/20107701VnJpwcrD7R.png

我要留言

立即登入留言