本文是用系统的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