swift 二维码识别的实现

本文是用系统的AVFoundation来实现二维码的扫描(注意:只支持真机)

代码地址

https://github.com/jinliyuelong/LYJSwiftDemo

1.创建viewcontroller来显示按钮进行进入扫描窗口


import UIKit
import AVFoundation

class QRcodeViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        

        self.setupUi()
    }
    
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func setupUi()  {
        self.view.backgroundColor = UIColor.white
        
                let button = UIButton(frame: CGRect(x: (UIScreen.main.bounds.size.width-100) * 0.5, y: (UIScreen.main.bounds.size.height-30) * 0.5, width: 100, height: 30))
                button.setTitle("扫一扫", for: UIControlState())
                button.setTitleColor(UIColor.blue, for: UIControlState())
                button.addTarget(self, action: #selector(QRcodeViewController.buttonAction(_:)), for: UIControlEvents.touchUpInside)
                self.view.addSubview(button)
        
    }
    
    func buttonAction(_ sender : AnyObject){
        print("扫一扫")
        
        if self.cameraPermissions() {
        
        let  scanner = ScannerViewController()
        self.navigationController?.pushViewController(scanner, animated: true)
        }else{
        
            self.displayAlertControllerWithMessage("当前设备没有相机权限")
        }
        
        
    }
    
    
    
    /**
     判断相机权限
     
     - returns: 有权限返回true,没权限返回false
     */
    func cameraPermissions() -> Bool{
        
        let authStatus:AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
        
        debugPrint("当前的权限是=====\(authStatus.rawValue)")
        
        if(authStatus == AVAuthorizationStatus.authorized || authStatus == AVAuthorizationStatus.notDetermined) {
            return true
        }else {
            return false
        }
        
    }
    
    
    
    



}
2.创建扫描viewcontroller


里面有一个用来显示组件的view:ScannerBackgroundView和controller

import UIKit

class ScannerBackgroundView: UIView {
    
    
    var scanResult = UITextField()
    
    var scanResultPlaceHolder:String = ""
    
    
    
    
    //屏幕扫描区域视图
    let barcodeView = UIView(frame: CGRect(x: screenWidth  * 0.2, y:  screenHeight * 0.15, width: screenWidth  * 0.6, height: screenWidth  * 0.6))
    //扫描线
    let scanLine = UIImageView()
    
    var timer = Timer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
    }
    
    
    func stopScan()  {
        timer.invalidate()
    }
    
    
    
    init(frame: CGRect, scanResultPlaceHolder:String) {
        
        super.init(frame: frame)
        
        self.scanResultPlaceHolder = scanResultPlaceHolder
        
        self.setupUi()
    }
    
    
    func setupUi()  {
        barcodeView.layer.borderWidth = 1.0
        barcodeView.layer.borderColor = UIColor.white.cgColor
        self.addSubview(barcodeView)
        
        //设置扫描线
        scanLine.frame = CGRect(x: 0, y: 0, width: barcodeView.frame.size.width, height: 5)
        scanLine.image = UIImage(named: "QRCodeScanLine")
        
        //添加扫描线图层
        barcodeView.addSubview(scanLine)
        
        self.createBackGroundView()
        
        
        timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(moveScannerLayer(_:)), userInfo: nil, repeats: true)
        
        
    }
    
    
    func  createBackGroundView() {
        let topView = UIView(frame: CGRect(x: 0, y: 0,  width: screenWidth , height:  screenHeight * 0.15))
        let bottomView = UIView(frame: CGRect(x: 0, y: screenWidth  * 0.6 +  screenHeight * 0.15, width: screenWidth , height:  screenHeight * 0.85 - screenWidth * 0.6))
        
        let leftView = UIView(frame: CGRect(x: 0, y:  screenHeight * 0.15, width: screenWidth  * 0.2, height: screenWidth  * 0.6))
        let rightView = UIView(frame: CGRect(x: screenWidth  * 0.8, y:  screenHeight * 0.15, width: screenWidth  * 0.2, height: screenWidth  * 0.6))
        
        topView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        bottomView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        leftView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        rightView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        
        let label = UILabel(frame: CGRect(x: 0, y: 10, width: screenWidth , height: 21))
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 14)
        label.textColor = UIColor.white
        label.text = "将二维码/条形码放入扫描框内,即自动扫描"
        
        bottomView.addSubview(label)
        
        bottomView.addSubview(scanResult)
        
        
        self.addscanResult()
        
        self.addSubview(topView)
        self.addSubview(bottomView)
        self.addSubview(leftView)
        self.addSubview(rightView)
        
        
        
    }
    
    
    func addscanResult()  {
        
        self.scanResultP()
        self.scanResultF()
    }
    
    
    //设置reslut
    func scanResultP()  {
        
        scanResult.textAlignment = .left
        
        scanResult.textColor = UIColor.white
        
        scanResult.layer.masksToBounds = true
        
        scanResult.layer.borderColor = mygrayColor.cgColor
        
        scanResult.layer.borderWidth = 1
        
        scanResult.leftViewMode = .always
        
        
        scanResult.attributedPlaceholder = NSAttributedString(string: self.scanResultPlaceHolder, attributes: [NSForegroundColorAttributeName:UIColor.white ])
        
        scanResult.layer.cornerRadius = 3
        
        scanResult.font = UIFont.systemFont(ofSize: CGFloat(mylableSize))
        
        
    }
    
    func scanResultF()  {
        
        scanResult.frame = CGRect.init(x: screenWidth * 0.1, y: 10 + screenHeight * 0.1, width: screenWidth * 0.8, height: 40)
        
    }
    
    
    
    func scanResultD(reslut:String){
        
        scanResult.text = " " + reslut
        
        
    }
    
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    
    
    //让扫描线滚动
    func moveScannerLayer(_ timer : Timer) {
        scanLine.frame = CGRect(x: 0, y: 0, width: self.barcodeView.frame.size.width, height: 12);
        UIView.animate(withDuration: 2) {
            self.scanLine.frame = CGRect(x: self.scanLine.frame.origin.x, y: self.scanLine.frame.origin.y + self.barcodeView.frame.size.height - 10, width: self.scanLine.frame.size.width, height: self.scanLine.frame.size.height);
            
        }
        
    }
}
controller为:

import AVFoundation
import UIKit
import Photos

class ScannerViewController: UIViewController,AVCaptureMetadataOutputObjectsDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
    
    //相机显示视图
    let cameraView = ScannerBackgroundView(frame: UIScreen.main.bounds ,scanResultPlaceHolder:"请输入扫描设备")
    
    
    let captureSession = AVCaptureSession()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.black
        //失效相册
        //设置导航栏
                let barButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.add, target: self, action: #selector(ScannerViewController.selectPhotoFormPhotoLibrary(_:)))
                self.navigationItem.rightBarButtonItem = barButtonItem
        
        //
        self.view.addSubview(cameraView)
        
        //初始化捕捉设备(AVCaptureDevice),类型AVMdeiaTypeVideo
        let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        
        let input :AVCaptureDeviceInput
        
        //创建媒体数据输出流
        let output = AVCaptureMetadataOutput()
        
        //捕捉异常
        do{
            debugPrint("进入do循环")
            //创建输入流
            input = try AVCaptureDeviceInput(device: captureDevice)
            
            //把输入流添加到会话
            captureSession.addInput(input)
            
            //把输出流添加到会话
            captureSession.addOutput(output)
        }catch {
            print("异常")
        }
        
        //创建串行队列
        let dispatchQueue = DispatchQueue(label: "queue", attributes: [])
        
        //设置输出流的代理
        output.setMetadataObjectsDelegate(self, queue: dispatchQueue)
        
        //设置输出媒体的数据类型
        output.metadataObjectTypes = NSArray(array: [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]) as [AnyObject]
        
        //创建预览图层
        let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        
        //设置预览图层的填充方式
        videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
        
        //设置预览图层的frame
        videoPreviewLayer?.frame = cameraView.bounds
        
        //将预览图层添加到预览视图上
        cameraView.layer.insertSublayer(videoPreviewLayer!, at: 0)
        
        //设置扫描范围
        output.rectOfInterest = CGRect(x: 0.2, y: 0.15, width: 0.6, height: 0.6)
        
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.tabBarController?.tabBar.isHidden = true
        self.scannerStart()
    }
    
    func scannerStart(){
        captureSession.startRunning()
        debugPrint("开始扫描")
        
    }
    
    func scannerStop() {
        captureSession.stopRunning()
        debugPrint("结束扫描")
        
        cameraView.stopScan()
    }
    
    
    
    //扫描代理方法
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
        if metadataObjects != nil && metadataObjects.count > 0 {
            let metaData = metadataObjects.first
            
            debugPrint("进入代理方法")
            
            debugPrint("扫描结果是=======\((metaData as AnyObject).stringValue ?? " ")")
            //            print((metaData as AnyObject).stringValue ?? " ")
            DispatchQueue.main.async(execute: {
                let result:String = (metaData as AnyObject).stringValue ?? " "
                
                self.cameraView.scanResultD(reslut: result)
                
                self.cameraView.isUserInteractionEnabled = false
                
            })
            
            self.scannerStop()
            
            //            captureSession.stopRunning()
        }
        
        
    }
    
    
    
    //从相册中选择图片
    func selectPhotoFormPhotoLibrary(_ sender : AnyObject){
        
        if self.PhotoLibraryPermissions(){
            let picture = UIImagePickerController()
            picture.sourceType = UIImagePickerControllerSourceType.photoLibrary
            picture.delegate = self
            self.present(picture, animated: true, completion: nil)
            
            
        }else{
            
            
            self.displayAlertControllerWithMessage("该设备没有相册权限")
        }
        
        
    }
    
    //选择相册中的图片完成,进行获取二维码信息
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        
        let image = info[UIImagePickerControllerOriginalImage]
        
        let imageData = UIImagePNGRepresentation(image as! UIImage)
        
        let ciImage = CIImage(data: imageData!)
        
        let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])
        
        let array = detector?.features(in: ciImage!)
        
        let result : CIQRCodeFeature = array!.first as! CIQRCodeFeature
        
        
        debugPrint("扫描结果是=======\((result.messageString))")
        
        
        let resultView = WebViewController()
        resultView.url = result.messageString
        
        self.navigationController?.pushViewController(resultView, animated: true)
        picker.dismiss(animated: true, completion: nil)
        print(result.messageString ?? "错误信息")
    }
    
   
    
    
    
    
    /**
     判断相册权限
     
     - returns: 有权限返回ture, 没权限返回false
     */
    
    func PhotoLibraryPermissions() -> Bool {
        
        
        
        let library:PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
        
        if(library == PHAuthorizationStatus.denied || library == PHAuthorizationStatus.restricted){
            return false
        }else {
            return true
        }
        
    }
    
}

运行效果为



注意事项:代码需要引入我写的一个扩展和工具文件

 UIColor+Extension

//
//  UIColor+Extension.swift
//  MyswiftDemo
//
//  Created by Liyanjun on 2017/1/14.
//  Copyright © 2017年 hand. All rights reserved.
//

import UIKit
import Foundation

extension UIColor {
    
    /**
     Convenient initializer for RGB color code with default alpha 1.0
     
     - Parameters:
     - red: The integer code for red
     - green: The integer code for green
     - blue: The integer code for blue
     */
    convenience init(red: Int, green: Int, blue: Int) {
        assert(red >= 0 && red <= 255, "Invalid red component")
        assert(green >= 0 && green <= 255, "Invalid green component")
        assert(blue >= 0 && blue <= 255, "Invalid blue component")
        
        self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
    }
    
    /**
     Convenient initializer for pure hex color code
     
     - Parameter hex: The hex code of color
     */
    convenience init(hex: Int) {
        self.init(red: (hex >> 16) & 0xff, green: (hex >> 8) & 0xff, blue: hex & 0xff)
    }
    
    static let system = UIColor(hex: 0x035d9a)
    static let background = UIColor(hex: 0xf4f5f7)
    static let systemGray = UIColor(hex: 0xe2e2e2)
    
    
}
和工具文件
//
//  LYJPch.swift
//  Colliers-CFIM
//
//  Created by Liyanjun on 2017/1/14.
//  Copyright © 2017年 hand. All rights reserved.
//
import UIKit
import SnapKit



let myBlackColr = UIColor(hex: 0x424243)//常用的黑色

let mygrayColor = UIColor(hex: 0xb2b2b2)//常用的灰色


let TitlelableColor =  myBlackColr//系统常用的黑色


//常用字体大小
let mylableSize = 15//设置常用字体大小为16

let mycommonEdge:CGFloat = 13//上下左右编剧


let commonCellHeight = CGFloat(37.0 + 6)//常用tableCell的高度



var keyWindow: UIWindow? {
    return UIApplication.shared.keyWindow
}

var isChinese: Bool {
    if let code = NSLocale.preferredLanguages.first, code.hasPrefix("zh") {
        return true
    }
    return false
}

var screenWidth:CGFloat {
    return UIScreen.main.bounds.width
}

var screenHeight:CGFloat {
    return UIScreen.main.bounds.height
}













AVFoundation



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值