SwiftでQRコードを読み込む画面を作ろうとした時、複数のコードをまとめて読み取る方法を調べたので紹介します。
SwiftでQRコードを読み取る流れ
SwiftでQRコードを読み取ろうと思った際、すごく大雑把に説明すると、以下の機能を利用します。
- AVCaptureDevice
OSのカメラを使うためのクラス
- AVCaptureSession
AVCaptureDeviceのデータを元に、データを解析し出力してくれるクラス
QRコードの解析もこのクラスを介して行います
- AVCaptureVideoPreviewLayer
カメラ映像、解析情報を画面に表示するために使うクラス
AVCaptureDeviceで端末のカメラを起動して、AVCaptureSessionを介してQRコードを読み取り、AVCaptureVideoPreviewLayerで画面に表示する、といった流れになります。
カメラ起動までの具体例
カメラを起動するまでの具体例です。
self.cameraViewがカメラ映像を表示するViewになります。
private func configureSession() {
// カメラの準備
guard let captureDeviceVideo = AVCaptureDevice.default(for: .video) else {
return
}
self.captureSession = AVCaptureSession()
var captureMetadataOutput: AVCaptureMetadataOutput
do {
let captureDeviceInputVideo = try AVCaptureDeviceInput(device: captureDeviceVideo)
if (self.captureSession.canAddInput(captureDeviceInputVideo)) {
self.captureSession.addInput(captureDeviceInputVideo)
}
captureMetadataOutput = AVCaptureMetadataOutput()
if (self.captureSession.canAddOutput(captureMetadataOutput)) {
self.captureSession.addOutput(captureMetadataOutput)
}
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: .main)
// 読み込み対象としてQRコードを指定
captureMetadataOutput.metadataObjectTypes = [.qr]
} catch {
self.captureSession = nil
return
}
self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
self.previewLayer.frame = self.cameraView.layer.bounds
self.previewLayer.videoGravity = .resizeAspectFill
self.cameraView.layer.addSublayer(self.previewLayer)
self.captureSession.startRunning()
}
QRコードを検知する処理の具体例
カメラ画像からQRコードを検出した際、metadataOutputのdelegateメソッドが呼びだされます。
この中で検知したQRコードに対する処理を行いましょう。
extension QrReaderViewController: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(
_ output: AVCaptureMetadataOutput,
didOutput metadataObjects: [AVMetadataObject],
from connection: AVCaptureConnection
) {
for metadataObject in metadataObjects {
guard let readableCodeObject = metadataObject as? AVMetadataMachineReadableCodeObject,
let stringValue = readableCodeObject.stringValue,
!stringValue.isEmpty else {
return
}
// stringValueがQRコードに埋め込まれている文字列
// ここで必要な処理を行う
}
}
}
上記サンプルでmetadataObjectsに対してforEachで処理していることからわかるように、検知したデータが複数まとめて渡されてきます。
検知したQR全てまとめて処理したい場合は、全てのデータに対して処理してあげるだけで、一括読み取り等が実現できます。特段工夫することなく、複数まとめて読み取れました。
逆に一つのみ対象としたい場合は、metadataObjects.first等で最初の一つだけ処理するようにすると良いでしょう。
どれくらい一括で処理できるのか?
端末やOSバージョンによって異なるかもしれませんが、私が試した環境(iPhone11 Pro、iOS17.6.1)では、最大で4つまで検出可能でした。思ったよりも少ないなという印象ですね…
※古い情報ですが、Appleのテクニカルノートにも最大4つと記載がありました。
まとめ
最大4つという制限はあるものの、複数まとめてQRコードを読み込めることがわかりました。
4つを超える場合、1度での読み込みはできないものの、連続読み取りできるように画面操作の流れを工夫するといったこともできると思います。
本記事で紹介したサンプルコードは、GitHubで公開していますので、よろしければ参考にしてください。
https://github.com/u-pt/QrReaderViewController
コメント