【iOS】二维码扫描

  • OC
#import "ScanViewController.h"
#import 
@interface ScanViewController ()
{
    AVCaptureSession * session;
    AVCaptureMetadataOutput * output;
}
@end

@implementation ScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.hbd_barShadowHidden = YES;
    self.hbd_barTintColor = UIColor.whiteColor;
    self.hbd_tintColor = UIColor.blackColor;
    self.view.backgroundColor = UIColor.whiteColor;
    self.navigationItem.title = @"扫描二维码";
    [self createQrView];
}

-(void)createQrView{
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    
    switch (status) {
        case AVAuthorizationStatusNotDetermined:{
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (granted) {
                        [self continueConfigUI:AVMediaTypeVideo];
                    } else {
                        NSLog(@"denied");
                    }
                });
            }];
        }

            
            break;
        case AVAuthorizationStatusAuthorized:{
            [self continueConfigUI:AVMediaTypeVideo];
        }
            break;
        default:
            break;
    }
    
    
   
    
    
    
}

- (void)continueConfigUI:(AVMediaType)mediaType{
    AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:mediaType];
    if (!device) {
        return;
    }
    

    
    CGFloat W = KSWidth - 100;
    
    
    CGRect scanRect = CGRectMake(50,80, W , W );
    
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    output = [[AVCaptureMetadataOutput alloc] init];
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    session = [[AVCaptureSession alloc] init];
    if([session canAddInput:deviceInput]){
        [session addInput:deviceInput];
    }
    if([session canAddOutput:output]){
        [session addOutput:output];
    }
    // 必须放在上面设置完session之后
    output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
    
    
    AVCaptureVideoPreviewLayer *layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    layer.frame = self.view.bounds;
    [self.view.layer addSublayer:layer];
    [session startRunning];
    / 采用此方法必须放到startRunning之后
    output.rectOfInterest = [layer metadataOutputRectOfInterestForRect:scanRect];
    
    
    
    
    // 取景框图片
    UIImageView *quJingImage =[[UIImageView alloc] initWithFrame:[layer rectForMetadataOutputRectOfInterest:output.rectOfInterest]];
    quJingImage.image = [UIImage imageNamed:@"biankuang"];
    [self.view addSubview:quJingImage];
    
    
    
    UILabel *label = [[UILabel alloc] init];
    label.text = @"扫描旧手机上二维码";
    label.textAlignment = NSTextAlignmentCenter;
    label.textColor = UIColor.blackColor;
    label.font = [UIFont systemFontOfSize:18];
    [self.view addSubview:label];
    [label mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.mas_equalTo(0);
        make.top.equalTo(quJingImage.mas_bottom).offset(24);
        
    }];
    

    

}





- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    if(metadataObjects.count > 0) {
        [session stopRunning];
        AVMetadataMachineReadableCodeObject * readCode = metadataObjects.firstObject;
        UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"结果" message:readCode.stringValue preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * alertAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil];
        [alertVC addAction:alertAction];
        [self presentViewController:alertVC animated:YES completion:nil];
        NSLog(@"%@", readCode.stringValue);
    }
}

  • Swift
import UIKit
import AVFoundation
import Photos
import CoreImage
protocol ScanViewDelegate: NSObjectProtocol{
    /// 扫码数据
    ///
    /// - Parameter pileCode: 编码
    func captureOutputSuccess(pileCode:String);
}
class YMScanView: UIView,UIImagePickerControllerDelegate,UINavigationControllerDelegate,AVCaptureMetadataOutputObjectsDelegate {
    /// 创建设备
    var captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
    /// 捕获视频
    var captureSession : AVCaptureSession?
    /// 捕获视频的预览层
    var videoPreviewLayer : AVCaptureVideoPreviewLayer?
    
    /// 提示文字
    var titleLabel = UILabel()
    /// 图片
    var quJingImage:UIImageView!
    var saoMaTiaoImage : UIImageView?
    /// 开灯
    var openLampButton:UIButton!
    /// 扫码结果
    var sweepResult : ((_ resultStr : String)->())!
    // 代理
    weak var delegate : ScanViewDelegate!
    
    /// 元数据输出
    let captureMetadataOutput = AVCaptureMetadataOutput()
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        createQrView()
        createScanPanelView()
    }
    /// 创建扫描设备
    func createQrView(){
        let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
        if authStatus == AVAuthorizationStatus.restricted || authStatus == AVAuthorizationStatus.denied {
            DZAlertView.sharedInstance.show(DZAlertViewType.blackViewAndClickDisappear, contentType: DZAlertContentViewType.warning, message: ["请在iPhone的“设置”-“隐私”-“相机”功能中,找到“\(Bundle.main.appDisplayName)”打开相机访问权限"])
            return
        }
        
        //给设备添加input输入
        var input : AVCaptureDeviceInput!
        do{
            input = try AVCaptureDeviceInput(device: captureDevice!)
        }catch{
            
        }
        if input == nil {
            return
        }
        captureSession = AVCaptureSession()
        captureSession?.addInput(input)
        captureSession?.addOutput(captureMetadataOutput)
        captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr,
                                                     AVMetadataObject.ObjectType.ean8,
                                                     AVMetadataObject.ObjectType.ean13,
                                                     AVMetadataObject.ObjectType.code128,
                                                     AVMetadataObject.ObjectType.code39,
                                                     AVMetadataObject.ObjectType.code93,
                                                     AVMetadataObject.ObjectType.code39Mod43,
                                                     AVMetadataObject.ObjectType.pdf417,
                                                     AVMetadataObject.ObjectType.aztec,
                                                     AVMetadataObject.ObjectType.upce
        ]
//
        
        let cropRect = CGRect(x: UIConfigure.Width / 2 - (258 * UIConfigure.SizeScale) / 2, y: 85 * UIConfigure.SizeScale, width: 258 * UIConfigure.SizeScale, height: 258 * UIConfigure.SizeScale)
        captureMetadataOutput.rectOfInterest = CGRect(x: cropRect.origin.y / UIConfigure.Height, y: cropRect.origin.x / UIConfigure.Width, width: cropRect.size.height / UIConfigure.Height , height: cropRect.size.width / UIConfigure.Width)
//        captureMetadataOutput.rectOfInterest = CGRect(x: (UIConfigure.Width - 258 * UIConfigure.SizeScale) / 2 / UIConfigure.Width , y: 85 * UIConfigure.SizeScale / (UIConfigure.Height - UIConfigure.navigationBarHeight), width: 258 * UIConfigure.SizeScale / UIConfigure.Width, height: 258 * UIConfigure.SizeScale / (UIConfigure.Height - UIConfigure.navigationBarHeight))
        /// 显示的layer
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
        let isphone = UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.phone ? true : false
        if isphone {
            videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
        }else{
            videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
        }
        
        videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        videoPreviewLayer?.frame = self.layer.bounds
        self.layer.addSublayer(videoPreviewLayer!)
        captureSession?.startRunning()
        
//        if captureDevice!.isFocusPointOfInterestSupported && captureDevice!.isFocusModeSupported(AVCaptureDevice.FocusMode.autoFocus) {
//            input.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
//        }
        
    }
    
    /// 创建扫描面板
    func createScanPanelView(){
        // 取景框图片
        quJingImage = UIImageView(image: BaseImage(named: "QSD_Scan_ScanQr")?.image)
        self.addSubview(quJingImage)
        quJingImage.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(85 * UIConfigure.SizeScale)
            make.centerX.equalTo(self.snp.centerX)
            make.width.equalTo(258 * UIConfigure.SizeScale)
            make.height.equalTo(258 * UIConfigure.SizeScale)
        }
        self.layoutIfNeeded()
        
        // 上下左右四个遮盖黑边
        let topView = UIView()
        self.addSubview(topView)
        topView.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(0)
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.bottom.equalTo(quJingImage.snp.top)
        }
        topView.backgroundColor = UIColor.black
        topView.alpha = 0.5
        
        let leftView = UIView()
        self.addSubview(leftView)
        leftView.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(topView.snp.bottom)
            make.left.equalTo(0)
            make.right.equalTo(quJingImage.snp.left)
            make.bottom.equalTo(quJingImage.snp.bottom)
        }
        leftView.backgroundColor = UIColor.black
        leftView.alpha = 0.5
        
        let rightView = UIView()
        self.addSubview(rightView)
        rightView.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(topView.snp.bottom)
            make.left.equalTo(quJingImage.snp.right)
            make.right.equalTo(0)
            make.bottom.equalTo(quJingImage.snp.bottom)
        }
        rightView.backgroundColor = UIColor.black
        rightView.alpha = 0.5
        
        let bottomView = UIView()
        self.addSubview(bottomView)
        bottomView.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(quJingImage.snp.bottom)
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.bottom.equalTo(0)
        }
        bottomView.backgroundColor = UIColor.black
        bottomView.alpha = 0.5
        
        //提示文字
        self.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(quJingImage.snp.bottom).offset(10)
            make.left.equalTo(40)
            make.right.equalTo(-40)
        }
        titleLabel.numberOfLines = 0
        titleLabel.textAlignment = NSTextAlignment.center
        titleLabel.text = "将二维码/条形码放入框内,即可自动扫描"
        titleLabel.textColor = UIColor.white
        titleLabel.font = UIConfigure.Font14
        
        self.bringSubviewToFront(titleLabel)
        //扫描条不断动的那个
        saoMaTiaoImage = UIImageView(image: BaseImage(named: "QSD_Scan_ScanQrLIne")?.image)
        self.addSubview(saoMaTiaoImage!)
        saoMaTiaoImage!.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(quJingImage.snp.top)
            make.centerX.equalTo(quJingImage.snp.centerX)
            make.width.equalTo(200 * UIConfigure.SizeScale)
            make.height.equalTo(1)
        }
        saoMaTiaoImage?.isHidden = false
        
        changeStyle()
        
        //闪光灯按钮
        openLampButton = UIButton()
        self.addSubview(openLampButton)
        openLampButton.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(titleLabel.snp.bottom).offset(30)
            make.width.equalTo(60 * UIConfigure.SizeScale)
            make.height.equalTo(60 * UIConfigure.SizeScale)
            make.centerX.equalTo(self.snp.centerX)
        }
        openLampButton.setImage(BaseImage(named: "open_flash")?.image, for: UIControl.State.normal)
        openLampButton.setImage(BaseImage(named: "close_flash")?.image, for: UIControl.State.selected)
        openLampButton.addTarget(self, action: #selector(openShanGuang(sender:)), for: UIControl.Event.touchUpInside)
        openLampButton.setTitleColor(UIConfigure.ThemeColor, for: UIControl.State.normal)
//        openLampButton.titleLabel?.textColor = UIConfigure.ThemeColor
//        openLampButton.backgroundColor = UIColor.white
//        openLampButton.layer.cornerRadius = UIConfigure.CornerRadius
//        openLampButton.layer.masksToBounds = true
//        openLampButton.layer.borderColor = UIConfigure.ThemeColor.cgColor
//        openLampButton.layer.borderWidth = 0.5
    }
    
    /**
     扫描条不断的移动
     */
    func changeStyle(){
        guard self.saoMaTiaoImage != nil else {
            return
        }
        self.saoMaTiaoImage?.isHidden  = false
        UIView.animate(withDuration: 3.5, animations: { [weak self] () -> Void in
            if(self != nil){
                self!.saoMaTiaoImage?.transform = CGAffineTransform(translationX: 0, y: 258 * UIConfigure.SizeScale)
            }
        }) { [weak self](end) -> Void in
            if(self != nil){
                UIView.animate(withDuration: 3.5, animations: { [weak self] in
                    if(self != nil){
                        self!.saoMaTiaoImage?.transform = CGAffineTransform.identity
                    }
                    }, completion: { [weak self](end) in
                        if self != nil {
                            self!.changeStyle()
                        }
                })
            }
        }
    }
    
    /// 开闪光
    @objc func openShanGuang(sender:UIButton){
        sender.isSelected = !sender.isSelected
        if captureDevice != nil && captureDevice!.hasFlash && captureDevice!.hasTorch {
            do {
                try captureDevice?.lockForConfiguration()
                if sender.isSelected {
                    captureDevice!.flashMode = AVCaptureDevice.FlashMode.on
                    captureDevice!.torchMode = AVCaptureDevice.TorchMode.on
                }else{
                    captureDevice!.flashMode = AVCaptureDevice.FlashMode.off
                    captureDevice!.torchMode = AVCaptureDevice.TorchMode.off
                    
                }
                
                captureDevice?.unlockForConfiguration()
            }catch{
                
            }
        }else{
            DZAlertView.sharedInstance.show(DZAlertViewType.blackViewAndClickDisappear, contentType: DZAlertContentViewType.warning, message: ["不能打开设备的闪光灯"])
        }
    }
    
    
    

    
//    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
//        if metadataObjects == nil || metadataObjects.count == 0 {
//            return
//        }
//        
        playSoundEffect(name: "Qcodesound.caf")
//        let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
//        captureSession?.stopRunning()
//        print("刚刚扫描出来!!!\(metadataObj.stringValue)")
//        delegate.captureOutputSuccess(pileCode: metadataObj.stringValue!)
        if metadataObj.type == AVMetadataObjectTypeQRCode {
            if metadataObj.stringValue != nil {
                captureSession?.stopRunning()
                print("刚刚扫描出来!!!\(metadataObj.stzzzzringValue)")
                delegate.captureOutputSuccess(pileCode: metadataObj.stringValue!)
            }
        }
//        
//    }
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        if metadataObjects.count == 0 {
            return
        }
        
        let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
        sweepResult(String(describing: metadataObj.stringValue!))
        DebugLog(object: "刚刚扫描出来!!!\(String(describing: metadataObj.stringValue!))")
        
//        let obj = videoPreviewLayer?.transformedMetadataObject(for: metadataObjects.last!) as! AVMetadataMachineReadableCodeObject
//        delegate.captureOutputSuccess(pileCode: metadataObj.stringValue!)
        
        captureSession?.stopRunning()
        
    }
    
//    func changeVideoScale(objc : AVMetadataMachineReadableCodeObject){
//        let array = objc.corners
//        let point = CGPoint.zero
//        var index = 0
//        let dic = array[index += 1] as! CFDictionary
//    }
    

    /// 扫描成功后播放声音
    ///
    /// - Parameter name: 地址
    func playSoundEffect(name : String){
        let audioFile = Bundle.main.path(forResource: name, ofType: nil)
        let fileUrl = URL(fileURLWithPath: audioFile!)
        var soundID : SystemSoundID = 0
        
        AudioServicesCreateSystemSoundID(fileUrl as CFURL, &soundID)
        AudioServicesAddSystemSoundCompletion(soundID, nil, nil, { (SounID, clientData) in
            print("播放完成")
        }, nil)
        
        AudioServicesPlaySystemSound(soundID)
    }
    
    // 打开相册
    func openPhoto(){
        let status = PHPhotoLibrary.authorizationStatus()
        if status == PHAuthorizationStatus.denied || status == .restricted {
            APPDelStatic.showNoPhotoPhotoAlertView()
            return
        }else{
            //没有被禁用
            //先设定sourceType为相机,然后判断相机是否可用(ipod)没相机,不可用将sourceType设定为相片库
//            var sourceType = UIImagePickerControllerSourceType.photoLibrary
//            if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary){
//                sourceType = UIImagePickerControllerSourceType.photoLibrary
//            }
            let picker = UIImagePickerController()
            picker.allowsEditing = true
            picker.delegate = self
            picker.sourceType = UIImagePickerController.SourceType.savedPhotosAlbum
            self.ViewController()?.present(picker, animated: true, completion: nil)
        }
    }

     func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
        
        var image = info[UIImagePickerController.InfoKey.editedImage];
        if image == nil {
            image = info[UIImagePickerController.InfoKey.originalImage]
        }
        var detector : CIDetector?
        if #available(iOS 9.0, *) {
            detector = CIDetector(ofType: CIDetectorTypeText, context: nil, options: nil)
        } else {
            // Fallback on earlier versions
        }
        picker.dismiss(animated: true) {
            
            if let imageData = (image as! UIImage).pngData() {
                if let ciimage = CIImage(data: imageData) {
                    
                    if let features = detector?.features(in: ciimage) {
                        if features.count >= 1 {
                            let feature = features[0] as! CIQRCodeFeature
                            let scannedResult = feature.messageString
//                            delegate.captureOutputSuccess(pileCode: scannedResult)
                            DebugLog(object: "刚刚扫描照片出来!!!\(scannedResult!)")
                        }else{
                            DebugLog(object: "不是二维码!!")
                           
                        }
                    }
                }
            }
        }
        
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

请大家关注我的个人公众号:
【iOS】二维码扫描_第1张图片

你可能感兴趣的:(Swift,OC)