iOS native implementation of scanning QR code and barcode function limits scanning area

  • 2021-12-13 09:51:59
  • OfStack

Now Apple iOS system has natively supported the function of 2D code scanning, and it is necessary to import AVFoundation to scan natively.

Scanning preparation

1. Acquisition of camera equipment:


device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)

2. Create an input stream


do {
  try input = AVCaptureDeviceInput(device: device)
} catch let e as NSError {
  print(e.localizedDescription)
}

3. Create an output stream


output = AVCaptureMetadataOutput()
//  Sets the agent to refresh in the main thread 
output?.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

4. Initialize the connection object


session = AVCaptureSession()
//  High quality acquisition rate 
session?.canSetSessionPreset(AVCaptureSessionPresetHigh)
session?.addOutput(output)
session?.addInput(input)

5. Set the scan area


//  Special attention: Effective scanning area, positioning is to set the right vertex as the origin. The line where the screen width lies is y Axis, the line where the screen height is x Shaft 
let x = ((SCREENHeight - QRCodeWidth - topViewHeight) / 2.0) / SCREENHeight
let y = ((SCREENWidth - QRCodeWidth) / 2.0) / SCREENWidth
let width = QRCodeWidth / SCREENHeight
let height = QRCodeWidth / SCREENWidth
output?.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)

6. Set the coding format supported by scan code (set bar code and 2D code compatibility as follows)


output?.metadataObjectTypes = [AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]

Step 7 Start capturing


preview = AVCaptureVideoPreviewLayer(session: session)
preview?.videoGravity = AVLayerVideoGravityResizeAspectFill
preview?.frame = self.view.layer.bounds
self.view.layer.insertSublayer(preview!, at: 0)
session?.startRunning()

Scan animation

The animation here is the scan box animation imitating Alipay

We create a new method to deal with our animation.


fileprivate func scanAnimation() -> CABasicAnimation {
   let scanNetAnimation = CABasicAnimation()
    //  Along Y Axial motion 
   scanNetAnimation.keyPath = "transform.translation.y"
   //  The height of the scan box. Note: This is the opposite of the actual height 
   scanNetAnimation.byValue = QRCodeWidth
    //  Duration of animation 
   scanNetAnimation.duration = 1.5
   //  Number of repetitions of animation 
   scanNetAnimation.repeatCount = MAXFLOAT
   return scanNetAnimation
}

Use animation:

When we created the interface, the scan box had an UIImageView, and we needed to add our animation to this ImageView.


scanImageView?.layer.add(scanAnimation(), forKey: nil)

Processing after scanning


func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
  if metadataObjects.count > 0 {
    session?.stopRunning()
    let metadataObject = metadataObjects[0] as AnyObject
    let stringValue: String = metadataObject.stringValue
    let vc = QRCodeResultViewController.instantiate()
    vc.resultStr = stringValue
    self.navigationController?.pushViewController(vc, animated: true)
  }
}

Click on the processing of scan results


do {
  try input = AVCaptureDeviceInput(device: device)
} catch let e as NSError {
  print(e.localizedDescription)
}
0

We can use


do {
  try input = AVCaptureDeviceInput(device: device)
} catch let e as NSError {
  print(e.localizedDescription)
}
1

Open the connection in Safari. However, it is best to control the events in its own program. After iOS 9, Apple introduced SFSafariViewController, which can be used to display the web pages to be browsed.


do {
  try input = AVCaptureDeviceInput(device: device)
} catch let e as NSError {
  print(e.localizedDescription)
}
2

Related articles: