iOS
Scanner di codici QR
Ricerca…
introduzione
I codici QR (Quick Response) sono codici a barre bidimensionali ampiamente utilizzati su etichette ottiche leggibili a macchina. iOS fornisce un modo per leggere i codici QR utilizzando il framework AVFoundation
da iOS 7 in poi. Questo framework fornisce una serie di API per configurare / aprire la telecamera e leggere i codici QR dal feed della telecamera.
Scansione UIViewController per QR e visualizzazione dell'ingresso video
import AVFoundation
class QRScannerViewController: UIViewController,
AVCaptureMetadataOutputObjectsDelegate {
func viewDidLoad() {
self.initCaptureSession()
}
private func initCaptureSession() {
let captureDevice = AVCaptureDevice
.defaultDevice(withMediaType: AVMediaTypeVideo)
do {
let input = try AVCaptureDeviceInput(device: captureDevice)
let captureMetadataOutput = AVCaptureMetadataOutput()
self.captureSession?.addOutput(captureMetadataOutput)
captureMetadataOutput.setMetadataObjectsDelegate(self,
queue: DispatchQueue.main)
captureMetadataOutput
.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
self.videoPreviewLayer =
AVCaptureVideoPreviewLayer(session: self.captureSession)
self.videoPreviewLayer?
.videoGravity = AVLayerVideoGravityResizeAspectFill
self.videoPreviewLayer?.frame =
self.view.layer.bounds
self._viewController?.view.layer
.addSublayer(videoPreviewLayer!)
self.captureSession?.startRunning()
} catch {
//TODO: handle input open error
}
}
private func dismissCaptureSession() {
if let running = self.captureSession?.isRunning, running {
self.captureSession?.stopRunning()
}
self.captureSession = nil
self.videoPreviewLayer?.removeFromSuperLayer()
self.videoPreviewLayer = nil
}
func captureOutput(_ captureOutput: AVCaptureOutput,
didOutputMetadataObjects metadataObjects: [Any]!,
from connection: AVCaptureConnection) {
guard metadataObjects != nil && metadataObjects.count != 0 else {
//Nothing captured
return
}
if let metadataObj =
metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
guard metadataObj.type == AVMetadataObjectTypeQRCode else {
return
}
let barCodeObject = videoPreviewLayer?
.transformedMetadataObject(for:
metadataObj as AVMetadataMachineReadableCodeObject)
as! AVMetadataMachineReadableCodeObject
if let qrValue = metadataObj.stringValue {
self.handleQRRead(value: qrValue)
}
}
}
private handleQRRead(value: String) {
//TODO: Handle the read qr
}
private captureSession: AVCaptureSession?
private videoPreviewLayer: AVCaptureVideo
}
handleQRRead
- verrà richiamato su una scansione di successo initCaptureSession
- inizializza la scansione per QR e l'input della telecamera dismissCaptureSession
- nasconde l'input della videocamera e interrompe la scansione
Scansione del codice QR con framework AVFoudation
Prima di iOS 7 quando si desidera eseguire la scansione di un codice QR, potrebbe essere necessario affidarsi a framework o librerie di terze parti come zBar o zXing . Ma Apple ha introdotto AVCaptureMetaDataOutput
da iOS 7 per la lettura dei codici a barre.
Per leggere il codice QR utilizzando AVFoundation
è necessario configurare / creare AVCaptureSession
e utilizzare captureOutput:didOutputMetadataObjects:fromConnection:
delegate method.
Passo 1
Importa il framework AVFoundation
e conferma al protocollo AVCaptureMetadataOutputObjectsDelegate
import AVFoundation class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate
Passo 2
La lettura del codice QR è totalmente basata sulla cattura video. Quindi per acquisire video continui creare una AVCaptureSession
e impostare l'input e l'output del dispositivo. Aggiungi il codice seguente nel metodo viewDidLoad
controller di visualizzazione
// Create an instance of the AVCaptureDevice and provide the video as the media type parameter. let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) do { // Create an instance of the AVCaptureDeviceInput class using the device object and intialise capture session let input = try AVCaptureDeviceInput(device: captureDevice) captureSession = AVCaptureSession() captureSession?.addInput(input) // Create a instance of AVCaptureMetadataOutput object and set it as the output device the capture session. let captureMetadataOutput = AVCaptureMetadataOutput() captureSession?.addOutput(captureMetadataOutput) // Set delegate with a default dispatch queue captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) //set meta data object type as QR code, here we can add more then one type as well captureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode] // Initialize the video preview layer and add it as a sublayer to the viewcontroller view's layer. videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill videoPreviewLayer?.frame = view.layer.bounds view.layer.addSublayer(videoPreviewLayer!) // Start capture session. captureSession?.startRunning() } catch { // If any error occurs, let the user know. For the example purpose just print out the error print(error) return }
Passaggio 3
Implementare il metodo delegato AVCaptureMetadataOutputObjectsDelegate
per leggere il codice QR
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { // Check if the metadataObjects array contains at least one object. If not no QR code is in our video capture if metadataObjects == nil || metadataObjects.count == 0 { // NO QR code is being detected. return } // Get the metadata object and cast it to `AVMetadataMachineReadableCodeObject` let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if metadataObj.type == AVMetadataObjectTypeQRCode { // If the found metadata is equal to the QR code metadata then get the string value from meta data let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) if metadataObj.stringValue != nil { // metadataObj.stringValue is our QR code } } }
qui l'oggetto metadati può darti anche i limiti del codice QR letto sul feed della telecamera. Per ottenere i limiti basta passare l'oggetto metadati al metodo transformedMetadataObject
di videoPreviewLayer
come sotto.
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) qrCodeFrameView?.frame = barCodeObject!.bounds