今回はiOSでQRコードを読み取る処理について書こうかと思います
使用バージョンは以下の通りです
Swift 5.0
カメラ起動
QRコードを読み取る処理で最初にやることと言えば、カメラ起動です
まずは、カメラ起動の流れを見ていきましょう
カメラに起動にはAVFoundation
というフレームワークを使います
カメラなどのデバイスを表すAVCaptureDevice
クラスで取得した入力データを、AVCaptureDeviceInput
クラス(サブクラス)を用いてAVCaptureSession
に渡します
AVCaptureSession
クラスから出力されるデータは、出力形式を管理するAVCaptureOutput
クラスによって、画像、動画、フレームデータ、音声データ、メターデータなど様々な形式で出力されます
つまりはAVCaptureSession
はAVCaptureInput
とAVCaptureOutput
を追加し、キャプチャのアクティビティ全体を管理するものです
まずは、デバイスの設定をしてセッションに追加します
カメラと言っても、背面カメラや前面カメラ、ビデオ撮影やフォト撮影など色々あるので、どのタイプのカメラを使うのかを設定します
class ViewController: UIViewController { // デバイスからの入力と出力を管理するオブジェクト var captureSession = AVCaptureSession() // キャプチャーの出力データを受け付けるオブジェクト var output = AVCaptureMetadataOutput? // カメラプレビュー表示用のレイヤ var cameraPreviewLayer: AVCaptureVideoPreviewLayer? override func viewDidLoad() { super.viewDidLoad() // デバイス一覧を取得(ビデオを指定) let videoDevices = AVCaptureDevice.device(for: AVMediaType.video) // カメラを前面で起動する場合の処理 for device in videoDevices { let device = device if device.position == AVCaptureDevice.Position.front { let videoDevice = device } } // 前面カメラからvideoInputを取得 let videoInput : AVCaptureDeviceInput? = try! AVCaptureDeviceInput(device: videoDevice!) // セッションに追加 if videoInput != nil { captureSession.addInput(videoInput!) output = AVCaptureOutput() captureSession.addOutput(output!) output.addMetadataObjectsDelegate(self, queue: DispatchQueue.main) output!.metadataObjectTypes = output!.availableMetadataObjectTypes } } }
次に、カメラの取得している映像の表示をします
ここでLayer
が出てくるのですが、Layer
はViewに描画する内容を管理するオブジェクトです
カメラの取得している映像を画面に表示するには、AVCaptureVideoPreviewLayer
クラスを使います
class ViewController: UIViewController { // デバイスからの入力と出力を管理するオブジェクト var captureSession = AVCaptureSession() // キャプチャーの出力データを受け付けるオブジェクト var output = AVCaptureMetadataOutput? override func viewDidLoad() { super.viewDidLoad() // デバイスの設定をしてセッションに追加した後の処理はここ self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) // キャプチャの縦横比を維持した状態で表示するように設定 self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill // プレビューレイヤの表示の向きを設定 self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait self.cameraPreviewLayer?.frame = view.frame // カメラの向きを設定 switch(UIApplication.shared.statusBarOrientation) { case UIInterfaceOrientation.portrait: self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientaion.portrait case UIInterfaceOrientation.portraitUpsideDown: self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientaion.portraitUpsideDown case UIInterfaceOrientation.landscapeLeft: self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientaion.landscapeLeft case UIInterfaceOrientation.landscapeRight: self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientaion.landscapeRight case .unknown: self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientaion.portrait @unknown default: self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientaion.portrait } self.view.layer.insertSublayer(self.cameraPreviewLayer!, at: 0) // セッションの開始 captureSession.startRunning() }
ここまででカメラの起動ができました
次にQRコードの読み取りを行う処理を実装します
QRコード読み取り
QRコードの読み取りはAVCaptureMetadataOutputObjectsDelegate
で行います
extension ViewController: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection){ for object in metadataObjects { let data = object if !(data isKind(of: AVMetadataMachineReadableCodeObject.self)) { continue } // QRのデータの場合読み取りを行う if(data.type == AVMetadataObject.ObjectType.qr) { // ここにスキャン後の処理を入れる captureSession.stopRunning() break } } } }
ここまででQRの読み取りが行えます
一連の流れを理解するのに時間がかかるかもしれないですが、カメラはiOS開発でよく使うと思うので、理解する必要があると思いました。
最後にカメラのアクセス許可をInfo.plistで設定する必要があります
keyにPrivacy - Camera Usage Description
を設定して、valueには理由などを記載します
こうすれば、カメラが起動するときにアクセス許可が求められるようになり、アプリが落ちることはなくなります