├── Assets ├── 1.PNG ├── 2.PNG ├── 3.PNG ├── 4.PNG ├── 5.PNG ├── 6.PNG ├── 7.PNG └── 8.PNG ├── README.md ├── SwiftScan.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── jason.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ ├── SwiftScan.xcscheme │ │ └── SwiftScanner.xcscheme └── xcuserdata │ └── jason.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── SwiftScan ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon@2x.png │ │ └── Icon@3x.png │ ├── Contents.json │ ├── alipay.imageset │ │ ├── Contents.json │ │ ├── alipay@2x.png │ │ └── alipay@3x.png │ ├── avatar.imageset │ │ ├── Contents.json │ │ └── avatar.png │ ├── default.imageset │ │ ├── Contents.json │ │ ├── default@2x.png │ │ └── default@3x.png │ └── wechat.imageset │ │ ├── Contents.json │ │ ├── wechat@2x.png │ │ └── wechat@3x.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── GenerateCodeVC.swift ├── Info.plist └── ViewController.swift └── SwiftScanner ├── Common └── Common.swift ├── Controllers ├── CameraVC.swift ├── HeaderVC.swift ├── HeaderVC.xib └── ScannerVC.swift ├── Extensions ├── AVMetadataObject+Extensions.swift ├── Platform.swift ├── ScanAnimation.swift ├── UIImage+Extensions.swift └── UIViewController+Extensions.swift ├── Info.plist ├── Model ├── CornerLocation.swift ├── ScanAnimationStyle.swift └── TorchMode.swift ├── SwiftScanner.bundle ├── Info.plist ├── ScanLine@2x.png ├── ScanLine@3x.png ├── ScanNet@2x.png ├── ScanNet@3x.png ├── flashOff@2x.png ├── flashOff@3x.png ├── flashOn@3x 2.png ├── flashOn@3x.png ├── icon_back@2x.png └── icon_back@3x.png ├── SwiftScanner.h └── Views └── ScanView.swift /Assets/1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/1.PNG -------------------------------------------------------------------------------- /Assets/2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/2.PNG -------------------------------------------------------------------------------- /Assets/3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/3.PNG -------------------------------------------------------------------------------- /Assets/4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/4.PNG -------------------------------------------------------------------------------- /Assets/5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/5.PNG -------------------------------------------------------------------------------- /Assets/6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/6.PNG -------------------------------------------------------------------------------- /Assets/7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/7.PNG -------------------------------------------------------------------------------- /Assets/8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/Assets/8.PNG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Swift](https://img.shields.io/badge/Swift-4.2-orange.svg) 2 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 3 | ![Platform](https://img.shields.io/badge/Platform-iOS-red.svg) 4 | 5 | # SwiftScan 6 | 7 | ## 主要内容的介绍 8 | 9 | * `生成二维码/条形码`
10 | 11 | * `扫描二维码/条形码`
12 | 13 | * `根据光线强弱开启手电筒`
14 | 15 | * `扫描成功之后界面之间逻辑跳转处理`
16 | 17 | * `扫描界面可自定义(线扫描条样式以及网格样式)`
18 | 19 | * `扫描界面仿微信、支付宝(请根据项目需求,自行布局或调整)`
20 | 21 | - [Requirements](#requirements) 22 | - [Installation](#installation) 23 | - [Usage](#usage) 24 | 25 | 26 | ## Requirements 27 | 28 | - Swift 4.2 29 | - iOS 9.0.0+ 30 | - Xcode 9.x 31 | 32 |
33 | 34 | ## Installation 35 | 36 | ### Carthage 37 | 38 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 39 | 40 | To integrate **SwiftScan** into your Xcode project using Carthage, specify it in your `Cartfile`: 41 | 42 | ```ogdl 43 | github "chenjie1219/SwiftScan" 44 | ``` 45 | 46 | Run `carthage update` to build the framework and drag the built `SwiftScanner.framework` into your Xcode project. 47 | 48 | ### Manually 49 | 50 | Just download the project, and drag and drop the "SwiftScanner" folder in your project. 51 | 52 |
53 | 54 | ## Usage 55 | 56 | #### 1、在 info.plist 中添加以下字段(iOS 10 之后需添加的字段) 57 | 58 | * `NSCameraUsageDescription (相机权限访问)`
59 | 60 | #### 2、二维码扫描 61 | 62 | ##### Push方式弹出扫描页面 63 | 64 | ```Swift 65 | /// 创建二维码扫描 66 | let vc = ScannerVC() 67 | 68 | //设置标题、颜色、扫描样式(线条、网格) 69 | vc.setupScanner("微信扫一扫", .green, .default) { (code) in 70 | //扫描回调方法 71 | <#code#> 72 | 73 | //关闭扫描页面 74 | self.navigationController?.popViewController(animated: true) 75 | } 76 | 77 | //push到扫描页面 78 | navigationController?.pushViewController(vc, animated: true) 79 | ``` 80 | ##### Present方式弹出扫描页面 81 | 82 | ```Swift 83 | /// 创建二维码扫描 84 | let vc = ScannerVC() 85 | 86 | //设置标题、颜色、扫描样式(线条、网格) 87 | vc.setupScanner("支付宝扫一扫", .blue, .grid) { (code) in 88 | //扫描回调方法 89 | <#code#> 90 | 91 | //关闭扫描页面 92 | self.dismiss(animated: true, completion: nil) 93 | } 94 | 95 | //Present到扫描页面 96 | present(vc, animated: true, completion: nil) 97 | ``` 98 | 99 | #### 3、二维码生成 100 | 101 | ```Swift 102 | /// 带 logo 的二维码(logoImage为nil则不带logo) 103 | QRCodeView.image = UIImage.generateQRCode("https://github.com/chenjie1219", 300, logoImage, .orange) 104 | ``` 105 | 106 | #### 4、条形码生成 107 | 108 | ```Swift 109 | /// 条形码 110 | barCodeView.image = UIImage.generateCode128("https://github.com/chenjie1219", CGSize(width: 300, height: 100, .blue) 111 | ``` 112 | 113 | 114 | ## 效果图 115 | ![1](Assets/1.PNG) 116 | ![2](Assets/2.PNG) 117 | ![3](Assets/3.PNG) 118 | ![4](Assets/4.PNG) 119 | ![5](Assets/5.PNG) 120 | ![6](Assets/6.PNG) 121 | ![7](Assets/7.PNG) 122 | ![8](Assets/8.PNG) 123 | 124 | 125 | ## Author 126 | 127 | * Email:4234115@qq.com 128 | 129 | * Wechat:4234115 -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 96148F2F21B50BB500BA639B /* ScanAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96148F2E21B50BB500BA639B /* ScanAnimation.swift */; }; 11 | 96148F3121B519A300BA639B /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96148F3021B519A300BA639B /* UIImage+Extensions.swift */; }; 12 | 96538B5921B6454A00470AD7 /* GenerateCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96538B5821B6454A00470AD7 /* GenerateCodeVC.swift */; }; 13 | 9656A3AB21B0ED5900AC7C3A /* ScannerVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9656A3A921B0ED5900AC7C3A /* ScannerVC.swift */; }; 14 | 9656A3AF21B114B800AC7C3A /* CameraVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9656A3AD21B114B800AC7C3A /* CameraVC.swift */; }; 15 | 9656A3B321B11FBD00AC7C3A /* ScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9656A3B221B11FBD00AC7C3A /* ScanView.swift */; }; 16 | 9656A3B521B1208500AC7C3A /* CornerLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9656A3B421B1208500AC7C3A /* CornerLocation.swift */; }; 17 | 9656A3B721B121FA00AC7C3A /* ScanAnimationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9656A3B621B121FA00AC7C3A /* ScanAnimationStyle.swift */; }; 18 | 969C481321AFB96000ECA382 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C481221AFB96000ECA382 /* AppDelegate.swift */; }; 19 | 969C481521AFB96000ECA382 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C481421AFB96000ECA382 /* ViewController.swift */; }; 20 | 969C481821AFB96000ECA382 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 969C481621AFB96000ECA382 /* Main.storyboard */; }; 21 | 969C481A21AFB96A00ECA382 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 969C481921AFB96A00ECA382 /* Assets.xcassets */; }; 22 | 969C481D21AFB96A00ECA382 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 969C481B21AFB96A00ECA382 /* LaunchScreen.storyboard */; }; 23 | 969C482D21AFBD1100ECA382 /* SwiftScanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 969C482B21AFBD1100ECA382 /* SwiftScanner.h */; settings = {ATTRIBUTES = (Public, ); }; }; 24 | 969C483021AFBD1100ECA382 /* SwiftScanner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 969C482921AFBD1100ECA382 /* SwiftScanner.framework */; }; 25 | 969C483121AFBD1100ECA382 /* SwiftScanner.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 969C482921AFBD1100ECA382 /* SwiftScanner.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 26 | 969C483721AFBD2700ECA382 /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C483621AFBD2700ECA382 /* Platform.swift */; }; 27 | 969C483A21AFBE5200ECA382 /* AVMetadataObject+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C483921AFBE5200ECA382 /* AVMetadataObject+Extensions.swift */; }; 28 | 969C483C21AFBF0600ECA382 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C483B21AFBF0600ECA382 /* UIViewController+Extensions.swift */; }; 29 | 969C483E21AFC15700ECA382 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C483D21AFC15700ECA382 /* Common.swift */; }; 30 | 969C484221AFC1ED00ECA382 /* TorchMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C484121AFC1ED00ECA382 /* TorchMode.swift */; }; 31 | 969C489221AFC78E00ECA382 /* SwiftScanner.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 969C489121AFC78E00ECA382 /* SwiftScanner.bundle */; }; 32 | 969C489821AFD3CF00ECA382 /* HeaderVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C489621AFD3CF00ECA382 /* HeaderVC.swift */; }; 33 | 969C489921AFD3CF00ECA382 /* HeaderVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 969C489721AFD3CF00ECA382 /* HeaderVC.xib */; }; 34 | 969C489A21AFDD6D00ECA382 /* SwiftScanner.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 969C489121AFC78E00ECA382 /* SwiftScanner.bundle */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXContainerItemProxy section */ 38 | 969C482E21AFBD1100ECA382 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = 969C480721AFB96000ECA382 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = 969C482821AFBD1100ECA382; 43 | remoteInfo = SwiftScanner; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXCopyFilesBuildPhase section */ 48 | 969C483521AFBD1100ECA382 /* Embed Frameworks */ = { 49 | isa = PBXCopyFilesBuildPhase; 50 | buildActionMask = 2147483647; 51 | dstPath = ""; 52 | dstSubfolderSpec = 10; 53 | files = ( 54 | 969C483121AFBD1100ECA382 /* SwiftScanner.framework in Embed Frameworks */, 55 | ); 56 | name = "Embed Frameworks"; 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | 96148F2E21B50BB500BA639B /* ScanAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAnimation.swift; sourceTree = ""; }; 63 | 96148F3021B519A300BA639B /* UIImage+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extensions.swift"; sourceTree = ""; }; 64 | 96538B5821B6454A00470AD7 /* GenerateCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateCodeVC.swift; sourceTree = ""; }; 65 | 9656A3A921B0ED5900AC7C3A /* ScannerVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerVC.swift; sourceTree = ""; }; 66 | 9656A3AD21B114B800AC7C3A /* CameraVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraVC.swift; sourceTree = ""; }; 67 | 9656A3B221B11FBD00AC7C3A /* ScanView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanView.swift; sourceTree = ""; }; 68 | 9656A3B421B1208500AC7C3A /* CornerLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLocation.swift; sourceTree = ""; }; 69 | 9656A3B621B121FA00AC7C3A /* ScanAnimationStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAnimationStyle.swift; sourceTree = ""; }; 70 | 969C480F21AFB96000ECA382 /* SwiftScan.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftScan.app; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | 969C481221AFB96000ECA382 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 72 | 969C481421AFB96000ECA382 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 73 | 969C481721AFB96000ECA382 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 74 | 969C481921AFB96A00ECA382 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 75 | 969C481C21AFB96A00ECA382 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 76 | 969C481E21AFB96A00ECA382 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 77 | 969C482921AFBD1100ECA382 /* SwiftScanner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftScanner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 969C482B21AFBD1100ECA382 /* SwiftScanner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftScanner.h; sourceTree = ""; }; 79 | 969C482C21AFBD1100ECA382 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | 969C483621AFBD2700ECA382 /* Platform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = ""; }; 81 | 969C483921AFBE5200ECA382 /* AVMetadataObject+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVMetadataObject+Extensions.swift"; sourceTree = ""; }; 82 | 969C483B21AFBF0600ECA382 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; 83 | 969C483D21AFC15700ECA382 /* Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = ""; }; 84 | 969C484121AFC1ED00ECA382 /* TorchMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorchMode.swift; sourceTree = ""; }; 85 | 969C489121AFC78E00ECA382 /* SwiftScanner.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = SwiftScanner.bundle; sourceTree = ""; }; 86 | 969C489621AFD3CF00ECA382 /* HeaderVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderVC.swift; sourceTree = ""; }; 87 | 969C489721AFD3CF00ECA382 /* HeaderVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HeaderVC.xib; sourceTree = ""; }; 88 | /* End PBXFileReference section */ 89 | 90 | /* Begin PBXFrameworksBuildPhase section */ 91 | 969C480C21AFB96000ECA382 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | 969C483021AFBD1100ECA382 /* SwiftScanner.framework in Frameworks */, 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 969C482621AFBD1100ECA382 /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | 9656A3B121B11FA400AC7C3A /* Views */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 9656A3B221B11FBD00AC7C3A /* ScanView.swift */, 113 | ); 114 | path = Views; 115 | sourceTree = ""; 116 | }; 117 | 969C480621AFB96000ECA382 = { 118 | isa = PBXGroup; 119 | children = ( 120 | 969C481121AFB96000ECA382 /* SwiftScan */, 121 | 969C482A21AFBD1100ECA382 /* SwiftScanner */, 122 | 969C481021AFB96000ECA382 /* Products */, 123 | ); 124 | sourceTree = ""; 125 | }; 126 | 969C481021AFB96000ECA382 /* Products */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 969C480F21AFB96000ECA382 /* SwiftScan.app */, 130 | 969C482921AFBD1100ECA382 /* SwiftScanner.framework */, 131 | ); 132 | name = Products; 133 | sourceTree = ""; 134 | }; 135 | 969C481121AFB96000ECA382 /* SwiftScan */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 969C481221AFB96000ECA382 /* AppDelegate.swift */, 139 | 969C481421AFB96000ECA382 /* ViewController.swift */, 140 | 96538B5821B6454A00470AD7 /* GenerateCodeVC.swift */, 141 | 969C481621AFB96000ECA382 /* Main.storyboard */, 142 | 969C481921AFB96A00ECA382 /* Assets.xcassets */, 143 | 969C481B21AFB96A00ECA382 /* LaunchScreen.storyboard */, 144 | 969C481E21AFB96A00ECA382 /* Info.plist */, 145 | ); 146 | path = SwiftScan; 147 | sourceTree = ""; 148 | }; 149 | 969C482A21AFBD1100ECA382 /* SwiftScanner */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 969C482B21AFBD1100ECA382 /* SwiftScanner.h */, 153 | 969C489121AFC78E00ECA382 /* SwiftScanner.bundle */, 154 | 969C483F21AFC1BE00ECA382 /* Common */, 155 | 969C483821AFBE0F00ECA382 /* Extensions */, 156 | 969C484021AFC1C700ECA382 /* Model */, 157 | 969C489321AFCDCB00ECA382 /* Controllers */, 158 | 9656A3B121B11FA400AC7C3A /* Views */, 159 | 969C482C21AFBD1100ECA382 /* Info.plist */, 160 | ); 161 | path = SwiftScanner; 162 | sourceTree = ""; 163 | }; 164 | 969C483821AFBE0F00ECA382 /* Extensions */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 969C483621AFBD2700ECA382 /* Platform.swift */, 168 | 96148F3021B519A300BA639B /* UIImage+Extensions.swift */, 169 | 969C483921AFBE5200ECA382 /* AVMetadataObject+Extensions.swift */, 170 | 969C483B21AFBF0600ECA382 /* UIViewController+Extensions.swift */, 171 | 96148F2E21B50BB500BA639B /* ScanAnimation.swift */, 172 | ); 173 | path = Extensions; 174 | sourceTree = ""; 175 | }; 176 | 969C483F21AFC1BE00ECA382 /* Common */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 969C483D21AFC15700ECA382 /* Common.swift */, 180 | ); 181 | path = Common; 182 | sourceTree = ""; 183 | }; 184 | 969C484021AFC1C700ECA382 /* Model */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 969C484121AFC1ED00ECA382 /* TorchMode.swift */, 188 | 9656A3B421B1208500AC7C3A /* CornerLocation.swift */, 189 | 9656A3B621B121FA00AC7C3A /* ScanAnimationStyle.swift */, 190 | ); 191 | path = Model; 192 | sourceTree = ""; 193 | }; 194 | 969C489321AFCDCB00ECA382 /* Controllers */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 969C489621AFD3CF00ECA382 /* HeaderVC.swift */, 198 | 969C489721AFD3CF00ECA382 /* HeaderVC.xib */, 199 | 9656A3AD21B114B800AC7C3A /* CameraVC.swift */, 200 | 9656A3A921B0ED5900AC7C3A /* ScannerVC.swift */, 201 | ); 202 | path = Controllers; 203 | sourceTree = ""; 204 | }; 205 | /* End PBXGroup section */ 206 | 207 | /* Begin PBXHeadersBuildPhase section */ 208 | 969C482421AFBD1100ECA382 /* Headers */ = { 209 | isa = PBXHeadersBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 969C482D21AFBD1100ECA382 /* SwiftScanner.h in Headers */, 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | /* End PBXHeadersBuildPhase section */ 217 | 218 | /* Begin PBXNativeTarget section */ 219 | 969C480E21AFB96000ECA382 /* SwiftScan */ = { 220 | isa = PBXNativeTarget; 221 | buildConfigurationList = 969C482121AFB96A00ECA382 /* Build configuration list for PBXNativeTarget "SwiftScan" */; 222 | buildPhases = ( 223 | 969C480B21AFB96000ECA382 /* Sources */, 224 | 969C480C21AFB96000ECA382 /* Frameworks */, 225 | 969C480D21AFB96000ECA382 /* Resources */, 226 | 969C483521AFBD1100ECA382 /* Embed Frameworks */, 227 | ); 228 | buildRules = ( 229 | ); 230 | dependencies = ( 231 | 969C482F21AFBD1100ECA382 /* PBXTargetDependency */, 232 | ); 233 | name = SwiftScan; 234 | productName = SwiftScan; 235 | productReference = 969C480F21AFB96000ECA382 /* SwiftScan.app */; 236 | productType = "com.apple.product-type.application"; 237 | }; 238 | 969C482821AFBD1100ECA382 /* SwiftScanner */ = { 239 | isa = PBXNativeTarget; 240 | buildConfigurationList = 969C483221AFBD1100ECA382 /* Build configuration list for PBXNativeTarget "SwiftScanner" */; 241 | buildPhases = ( 242 | 969C482421AFBD1100ECA382 /* Headers */, 243 | 969C482521AFBD1100ECA382 /* Sources */, 244 | 969C482621AFBD1100ECA382 /* Frameworks */, 245 | 969C482721AFBD1100ECA382 /* Resources */, 246 | ); 247 | buildRules = ( 248 | ); 249 | dependencies = ( 250 | ); 251 | name = SwiftScanner; 252 | productName = SwiftScanner; 253 | productReference = 969C482921AFBD1100ECA382 /* SwiftScanner.framework */; 254 | productType = "com.apple.product-type.framework"; 255 | }; 256 | /* End PBXNativeTarget section */ 257 | 258 | /* Begin PBXProject section */ 259 | 969C480721AFB96000ECA382 /* Project object */ = { 260 | isa = PBXProject; 261 | attributes = { 262 | LastSwiftUpdateCheck = 1010; 263 | LastUpgradeCheck = 1010; 264 | ORGANIZATIONNAME = Jason; 265 | TargetAttributes = { 266 | 969C480E21AFB96000ECA382 = { 267 | CreatedOnToolsVersion = 10.1; 268 | }; 269 | 969C482821AFBD1100ECA382 = { 270 | CreatedOnToolsVersion = 10.1; 271 | LastSwiftMigration = 1010; 272 | }; 273 | }; 274 | }; 275 | buildConfigurationList = 969C480A21AFB96000ECA382 /* Build configuration list for PBXProject "SwiftScan" */; 276 | compatibilityVersion = "Xcode 9.3"; 277 | developmentRegion = en; 278 | hasScannedForEncodings = 0; 279 | knownRegions = ( 280 | en, 281 | Base, 282 | ); 283 | mainGroup = 969C480621AFB96000ECA382; 284 | productRefGroup = 969C481021AFB96000ECA382 /* Products */; 285 | projectDirPath = ""; 286 | projectRoot = ""; 287 | targets = ( 288 | 969C480E21AFB96000ECA382 /* SwiftScan */, 289 | 969C482821AFBD1100ECA382 /* SwiftScanner */, 290 | ); 291 | }; 292 | /* End PBXProject section */ 293 | 294 | /* Begin PBXResourcesBuildPhase section */ 295 | 969C480D21AFB96000ECA382 /* Resources */ = { 296 | isa = PBXResourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 969C489A21AFDD6D00ECA382 /* SwiftScanner.bundle in Resources */, 300 | 969C481D21AFB96A00ECA382 /* LaunchScreen.storyboard in Resources */, 301 | 969C481A21AFB96A00ECA382 /* Assets.xcassets in Resources */, 302 | 969C481821AFB96000ECA382 /* Main.storyboard in Resources */, 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | }; 306 | 969C482721AFBD1100ECA382 /* Resources */ = { 307 | isa = PBXResourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 969C489221AFC78E00ECA382 /* SwiftScanner.bundle in Resources */, 311 | 969C489921AFD3CF00ECA382 /* HeaderVC.xib in Resources */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | /* End PBXResourcesBuildPhase section */ 316 | 317 | /* Begin PBXSourcesBuildPhase section */ 318 | 969C480B21AFB96000ECA382 /* Sources */ = { 319 | isa = PBXSourcesBuildPhase; 320 | buildActionMask = 2147483647; 321 | files = ( 322 | 969C481521AFB96000ECA382 /* ViewController.swift in Sources */, 323 | 96538B5921B6454A00470AD7 /* GenerateCodeVC.swift in Sources */, 324 | 969C481321AFB96000ECA382 /* AppDelegate.swift in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | 969C482521AFBD1100ECA382 /* Sources */ = { 329 | isa = PBXSourcesBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | 969C484221AFC1ED00ECA382 /* TorchMode.swift in Sources */, 333 | 969C489821AFD3CF00ECA382 /* HeaderVC.swift in Sources */, 334 | 969C483E21AFC15700ECA382 /* Common.swift in Sources */, 335 | 96148F2F21B50BB500BA639B /* ScanAnimation.swift in Sources */, 336 | 9656A3AF21B114B800AC7C3A /* CameraVC.swift in Sources */, 337 | 969C483A21AFBE5200ECA382 /* AVMetadataObject+Extensions.swift in Sources */, 338 | 9656A3B321B11FBD00AC7C3A /* ScanView.swift in Sources */, 339 | 969C483C21AFBF0600ECA382 /* UIViewController+Extensions.swift in Sources */, 340 | 9656A3AB21B0ED5900AC7C3A /* ScannerVC.swift in Sources */, 341 | 969C483721AFBD2700ECA382 /* Platform.swift in Sources */, 342 | 96148F3121B519A300BA639B /* UIImage+Extensions.swift in Sources */, 343 | 9656A3B721B121FA00AC7C3A /* ScanAnimationStyle.swift in Sources */, 344 | 9656A3B521B1208500AC7C3A /* CornerLocation.swift in Sources */, 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | }; 348 | /* End PBXSourcesBuildPhase section */ 349 | 350 | /* Begin PBXTargetDependency section */ 351 | 969C482F21AFBD1100ECA382 /* PBXTargetDependency */ = { 352 | isa = PBXTargetDependency; 353 | target = 969C482821AFBD1100ECA382 /* SwiftScanner */; 354 | targetProxy = 969C482E21AFBD1100ECA382 /* PBXContainerItemProxy */; 355 | }; 356 | /* End PBXTargetDependency section */ 357 | 358 | /* Begin PBXVariantGroup section */ 359 | 969C481621AFB96000ECA382 /* Main.storyboard */ = { 360 | isa = PBXVariantGroup; 361 | children = ( 362 | 969C481721AFB96000ECA382 /* Base */, 363 | ); 364 | name = Main.storyboard; 365 | sourceTree = ""; 366 | }; 367 | 969C481B21AFB96A00ECA382 /* LaunchScreen.storyboard */ = { 368 | isa = PBXVariantGroup; 369 | children = ( 370 | 969C481C21AFB96A00ECA382 /* Base */, 371 | ); 372 | name = LaunchScreen.storyboard; 373 | sourceTree = ""; 374 | }; 375 | /* End PBXVariantGroup section */ 376 | 377 | /* Begin XCBuildConfiguration section */ 378 | 969C481F21AFB96A00ECA382 /* Debug */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | ALWAYS_SEARCH_USER_PATHS = NO; 382 | CLANG_ANALYZER_NONNULL = YES; 383 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 384 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 385 | CLANG_CXX_LIBRARY = "libc++"; 386 | CLANG_ENABLE_MODULES = YES; 387 | CLANG_ENABLE_OBJC_ARC = YES; 388 | CLANG_ENABLE_OBJC_WEAK = YES; 389 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 390 | CLANG_WARN_BOOL_CONVERSION = YES; 391 | CLANG_WARN_COMMA = YES; 392 | CLANG_WARN_CONSTANT_CONVERSION = YES; 393 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 394 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 395 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 396 | CLANG_WARN_EMPTY_BODY = YES; 397 | CLANG_WARN_ENUM_CONVERSION = YES; 398 | CLANG_WARN_INFINITE_RECURSION = YES; 399 | CLANG_WARN_INT_CONVERSION = YES; 400 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 401 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 402 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 403 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 404 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 405 | CLANG_WARN_STRICT_PROTOTYPES = YES; 406 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 407 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 408 | CLANG_WARN_UNREACHABLE_CODE = YES; 409 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 410 | CODE_SIGN_IDENTITY = "iPhone Developer"; 411 | COPY_PHASE_STRIP = NO; 412 | DEBUG_INFORMATION_FORMAT = dwarf; 413 | ENABLE_STRICT_OBJC_MSGSEND = YES; 414 | ENABLE_TESTABILITY = YES; 415 | GCC_C_LANGUAGE_STANDARD = gnu11; 416 | GCC_DYNAMIC_NO_PIC = NO; 417 | GCC_NO_COMMON_BLOCKS = YES; 418 | GCC_OPTIMIZATION_LEVEL = 0; 419 | GCC_PREPROCESSOR_DEFINITIONS = ( 420 | "DEBUG=1", 421 | "$(inherited)", 422 | ); 423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 425 | GCC_WARN_UNDECLARED_SELECTOR = YES; 426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 427 | GCC_WARN_UNUSED_FUNCTION = YES; 428 | GCC_WARN_UNUSED_VARIABLE = YES; 429 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 430 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 431 | MTL_FAST_MATH = YES; 432 | ONLY_ACTIVE_ARCH = YES; 433 | SDKROOT = iphoneos; 434 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 435 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 436 | }; 437 | name = Debug; 438 | }; 439 | 969C482021AFB96A00ECA382 /* Release */ = { 440 | isa = XCBuildConfiguration; 441 | buildSettings = { 442 | ALWAYS_SEARCH_USER_PATHS = NO; 443 | CLANG_ANALYZER_NONNULL = YES; 444 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 445 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 446 | CLANG_CXX_LIBRARY = "libc++"; 447 | CLANG_ENABLE_MODULES = YES; 448 | CLANG_ENABLE_OBJC_ARC = YES; 449 | CLANG_ENABLE_OBJC_WEAK = YES; 450 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 451 | CLANG_WARN_BOOL_CONVERSION = YES; 452 | CLANG_WARN_COMMA = YES; 453 | CLANG_WARN_CONSTANT_CONVERSION = YES; 454 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 455 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 456 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 457 | CLANG_WARN_EMPTY_BODY = YES; 458 | CLANG_WARN_ENUM_CONVERSION = YES; 459 | CLANG_WARN_INFINITE_RECURSION = YES; 460 | CLANG_WARN_INT_CONVERSION = YES; 461 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 462 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 463 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 464 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 465 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 466 | CLANG_WARN_STRICT_PROTOTYPES = YES; 467 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 468 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 469 | CLANG_WARN_UNREACHABLE_CODE = YES; 470 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 471 | CODE_SIGN_IDENTITY = "iPhone Developer"; 472 | COPY_PHASE_STRIP = NO; 473 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 474 | ENABLE_NS_ASSERTIONS = NO; 475 | ENABLE_STRICT_OBJC_MSGSEND = YES; 476 | GCC_C_LANGUAGE_STANDARD = gnu11; 477 | GCC_NO_COMMON_BLOCKS = YES; 478 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 479 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 480 | GCC_WARN_UNDECLARED_SELECTOR = YES; 481 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 482 | GCC_WARN_UNUSED_FUNCTION = YES; 483 | GCC_WARN_UNUSED_VARIABLE = YES; 484 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 485 | MTL_ENABLE_DEBUG_INFO = NO; 486 | MTL_FAST_MATH = YES; 487 | SDKROOT = iphoneos; 488 | SWIFT_COMPILATION_MODE = wholemodule; 489 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 490 | VALIDATE_PRODUCT = YES; 491 | }; 492 | name = Release; 493 | }; 494 | 969C482221AFB96A00ECA382 /* Debug */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 498 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 499 | CODE_SIGN_STYLE = Automatic; 500 | DEVELOPMENT_TEAM = 5RAQYULZ5E; 501 | INFOPLIST_FILE = SwiftScan/Info.plist; 502 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 503 | LD_RUNPATH_SEARCH_PATHS = ( 504 | "$(inherited)", 505 | "@executable_path/Frameworks", 506 | ); 507 | PRODUCT_BUNDLE_IDENTIFIER = com.SwiftScan; 508 | PRODUCT_NAME = "$(TARGET_NAME)"; 509 | SWIFT_VERSION = 4.2; 510 | TARGETED_DEVICE_FAMILY = "1,2"; 511 | }; 512 | name = Debug; 513 | }; 514 | 969C482321AFB96A00ECA382 /* Release */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 518 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 519 | CODE_SIGN_STYLE = Automatic; 520 | DEVELOPMENT_TEAM = 5RAQYULZ5E; 521 | INFOPLIST_FILE = SwiftScan/Info.plist; 522 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 523 | LD_RUNPATH_SEARCH_PATHS = ( 524 | "$(inherited)", 525 | "@executable_path/Frameworks", 526 | ); 527 | PRODUCT_BUNDLE_IDENTIFIER = com.SwiftScan; 528 | PRODUCT_NAME = "$(TARGET_NAME)"; 529 | SWIFT_VERSION = 4.2; 530 | TARGETED_DEVICE_FAMILY = "1,2"; 531 | }; 532 | name = Release; 533 | }; 534 | 969C483321AFBD1100ECA382 /* Debug */ = { 535 | isa = XCBuildConfiguration; 536 | buildSettings = { 537 | CLANG_ENABLE_MODULES = YES; 538 | CODE_SIGN_IDENTITY = ""; 539 | CODE_SIGN_STYLE = Automatic; 540 | CURRENT_PROJECT_VERSION = 1; 541 | DEFINES_MODULE = YES; 542 | DYLIB_COMPATIBILITY_VERSION = 1; 543 | DYLIB_CURRENT_VERSION = 1; 544 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 545 | INFOPLIST_FILE = SwiftScanner/Info.plist; 546 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 547 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 548 | LD_RUNPATH_SEARCH_PATHS = ( 549 | "$(inherited)", 550 | "@executable_path/Frameworks", 551 | "@loader_path/Frameworks", 552 | ); 553 | PRODUCT_BUNDLE_IDENTIFIER = com.SwiftScanner; 554 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 555 | SKIP_INSTALL = YES; 556 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 557 | SWIFT_VERSION = 4.2; 558 | TARGETED_DEVICE_FAMILY = "1,2"; 559 | VERSIONING_SYSTEM = "apple-generic"; 560 | VERSION_INFO_PREFIX = ""; 561 | }; 562 | name = Debug; 563 | }; 564 | 969C483421AFBD1100ECA382 /* Release */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | CLANG_ENABLE_MODULES = YES; 568 | CODE_SIGN_IDENTITY = ""; 569 | CODE_SIGN_STYLE = Automatic; 570 | CURRENT_PROJECT_VERSION = 1; 571 | DEFINES_MODULE = YES; 572 | DYLIB_COMPATIBILITY_VERSION = 1; 573 | DYLIB_CURRENT_VERSION = 1; 574 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 575 | INFOPLIST_FILE = SwiftScanner/Info.plist; 576 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 577 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 578 | LD_RUNPATH_SEARCH_PATHS = ( 579 | "$(inherited)", 580 | "@executable_path/Frameworks", 581 | "@loader_path/Frameworks", 582 | ); 583 | PRODUCT_BUNDLE_IDENTIFIER = com.SwiftScanner; 584 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 585 | SKIP_INSTALL = YES; 586 | SWIFT_VERSION = 4.2; 587 | TARGETED_DEVICE_FAMILY = "1,2"; 588 | VERSIONING_SYSTEM = "apple-generic"; 589 | VERSION_INFO_PREFIX = ""; 590 | }; 591 | name = Release; 592 | }; 593 | /* End XCBuildConfiguration section */ 594 | 595 | /* Begin XCConfigurationList section */ 596 | 969C480A21AFB96000ECA382 /* Build configuration list for PBXProject "SwiftScan" */ = { 597 | isa = XCConfigurationList; 598 | buildConfigurations = ( 599 | 969C481F21AFB96A00ECA382 /* Debug */, 600 | 969C482021AFB96A00ECA382 /* Release */, 601 | ); 602 | defaultConfigurationIsVisible = 0; 603 | defaultConfigurationName = Release; 604 | }; 605 | 969C482121AFB96A00ECA382 /* Build configuration list for PBXNativeTarget "SwiftScan" */ = { 606 | isa = XCConfigurationList; 607 | buildConfigurations = ( 608 | 969C482221AFB96A00ECA382 /* Debug */, 609 | 969C482321AFB96A00ECA382 /* Release */, 610 | ); 611 | defaultConfigurationIsVisible = 0; 612 | defaultConfigurationName = Release; 613 | }; 614 | 969C483221AFBD1100ECA382 /* Build configuration list for PBXNativeTarget "SwiftScanner" */ = { 615 | isa = XCConfigurationList; 616 | buildConfigurations = ( 617 | 969C483321AFBD1100ECA382 /* Debug */, 618 | 969C483421AFBD1100ECA382 /* Release */, 619 | ); 620 | defaultConfigurationIsVisible = 0; 621 | defaultConfigurationName = Release; 622 | }; 623 | /* End XCConfigurationList section */ 624 | }; 625 | rootObject = 969C480721AFB96000ECA382 /* Project object */; 626 | } 627 | -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/xcshareddata/xcschemes/SwiftScan.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/xcshareddata/xcschemes/SwiftScanner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/xcuserdata/jason.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SwiftScan.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftScan.xcscheme_^#shared#^_ 8 | 9 | isShown 10 | 11 | orderHint 12 | 0 13 | 14 | SwiftScanner.xcscheme_^#shared#^_ 15 | 16 | isShown 17 | 18 | orderHint 19 | 1 20 | 21 | 22 | SuppressBuildableAutocreation 23 | 24 | 969C480E21AFB96000ECA382 25 | 26 | primary 27 | 28 | 29 | 969C482821AFBD1100ECA382 30 | 31 | primary 32 | 33 | 34 | 969C484621AFC2A100ECA382 35 | 36 | primary 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SwiftScan/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftScan 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "ios-marketing", 47 | "size" : "1024x1024", 48 | "scale" : "1x" 49 | } 50 | ], 51 | "info" : { 52 | "version" : 1, 53 | "author" : "xcode" 54 | } 55 | } -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/AppIcon.appiconset/Icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/AppIcon.appiconset/Icon@3x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/alipay.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "alipay@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "alipay@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/alipay.imageset/alipay@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/alipay.imageset/alipay@2x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/alipay.imageset/alipay@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/alipay.imageset/alipay@3x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/avatar.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "avatar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/avatar.imageset/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/avatar.imageset/avatar.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/default.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "default@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "default@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/default.imageset/default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/default.imageset/default@2x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/default.imageset/default@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/default.imageset/default@3x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/wechat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "wechat@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "wechat@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/wechat.imageset/wechat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/wechat.imageset/wechat@2x.png -------------------------------------------------------------------------------- /SwiftScan/Assets.xcassets/wechat.imageset/wechat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScan/Assets.xcassets/wechat.imageset/wechat@3x.png -------------------------------------------------------------------------------- /SwiftScan/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /SwiftScan/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /SwiftScan/GenerateCodeVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GenerateCodeVC.swift 3 | // SwiftScan 4 | // 5 | // Created by Jason on 2018/12/4. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class GenerateCodeVC: UIViewController { 12 | 13 | @IBOutlet weak var QRCodeView: UIImageView! 14 | 15 | @IBOutlet weak var barCodeView: UIImageView! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | let screenWidth = UIScreen.main.bounds.width 21 | 22 | let myWechat = "https://u.wechat.com/EOgrqGHTuducITFPPMgka4M" 23 | 24 | let myWechatNum = "4234115" 25 | 26 | QRCodeView.image = UIImage.generateQRCode(myWechat, screenWidth - 80, UIImage(named: "avatar"), .orange) 27 | 28 | barCodeView.image = UIImage.generateCode128(myWechatNum, CGSize(width: screenWidth - 80, height: (screenWidth - 80)/3), .blue) 29 | 30 | } 31 | 32 | 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /SwiftScan/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | NSCameraUsageDescription 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /SwiftScan/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftScan 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftScanner 11 | 12 | class ViewController: UITableViewController { 13 | 14 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 15 | 16 | let vc = ScannerVC() 17 | 18 | switch indexPath.row { 19 | case 0: 20 | 21 | //默认(push) 22 | vc.setupScanner { (code) in 23 | 24 | print(code) 25 | 26 | self.navigationController?.popViewController(animated: true) 27 | } 28 | 29 | navigationController?.pushViewController(vc, animated: true) 30 | 31 | case 1: 32 | 33 | //默认(present) 34 | vc.setupScanner() { (code) in 35 | 36 | print(code) 37 | 38 | self.dismiss(animated: true, completion: nil) 39 | } 40 | 41 | present(vc, animated: true, completion: nil) 42 | 43 | case 2: 44 | 45 | //微信 46 | vc.setupScanner("微信扫一扫", .green, .default) { (code) in 47 | 48 | print(code) 49 | 50 | self.navigationController?.popViewController(animated: true) 51 | } 52 | 53 | navigationController?.pushViewController(vc, animated: true) 54 | 55 | case 3: 56 | 57 | //支付宝 58 | vc.setupScanner("支付宝扫一扫", .blue, .grid) { (code) in 59 | 60 | print(code) 61 | 62 | self.navigationController?.popViewController(animated: true) 63 | } 64 | 65 | navigationController?.pushViewController(vc, animated: true) 66 | 67 | default: 68 | break 69 | } 70 | 71 | 72 | } 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /SwiftScanner/Common/Common.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Common.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let bundle = Bundle(path: Bundle.main.path(forResource: "SwiftScanner.bundle", ofType: nil) ?? "") 12 | 13 | let screenWidth = UIScreen.main.bounds.width 14 | 15 | let screenHeight = UIScreen.main.bounds.height 16 | 17 | let statusHeight = UIApplication.shared.statusBarFrame.height 18 | 19 | 20 | public func imageNamed(_ name:String)-> UIImage{ 21 | 22 | guard let image = UIImage(named: name, in: bundle, compatibleWith: nil) else{ 23 | return UIImage() 24 | } 25 | 26 | return image 27 | 28 | } 29 | -------------------------------------------------------------------------------- /SwiftScanner/Controllers/CameraVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CameraVC.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/30. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | protocol CameraViewControllerDelegate: class { 13 | 14 | func didOutput(_ code:String) 15 | 16 | func didReceiveError(_ error: Error) 17 | 18 | } 19 | 20 | 21 | public class CameraVC: UIViewController { 22 | 23 | weak var delegate:CameraViewControllerDelegate? 24 | 25 | lazy var animationImage = UIImage() 26 | 27 | /// 动画样式 28 | var animationStyle:ScanAnimationStyle = .default{ 29 | didSet{ 30 | if animationStyle == .default { 31 | animationImage = imageNamed("ScanLine") 32 | }else{ 33 | animationImage = imageNamed("ScanNet") 34 | } 35 | } 36 | } 37 | 38 | lazy var scannerColor:UIColor = .red 39 | 40 | public lazy var flashBtn: UIButton = .init(type: .custom) 41 | 42 | private var torchMode:TorchMode = .off { 43 | didSet{ 44 | guard let captureDevice = captureDevice, 45 | captureDevice.hasFlash else { 46 | return 47 | } 48 | guard captureDevice.isTorchModeSupported(torchMode.captureTorchMode) else{ 49 | return 50 | } 51 | 52 | do { 53 | try captureDevice.lockForConfiguration() 54 | captureDevice.torchMode = torchMode.captureTorchMode 55 | captureDevice.unlockForConfiguration() 56 | }catch{} 57 | 58 | flashBtn.setImage(torchMode.image, for: .normal) 59 | } 60 | } 61 | 62 | 63 | 64 | /// `AVCaptureMetadataOutput` metadata object types. 65 | var metadata = [AVMetadataObject.ObjectType]() 66 | 67 | // MARK: - Video 68 | 69 | /// Video preview layer. 70 | private var videoPreviewLayer: AVCaptureVideoPreviewLayer? 71 | /// Video capture device. This may be nil when running in Simulator. 72 | private lazy var captureDevice = AVCaptureDevice.default(for: .video) 73 | /// Capture session. 74 | private lazy var captureSession = AVCaptureSession() 75 | 76 | lazy var scanView = ScanView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)) 77 | 78 | override public func viewDidLoad() { 79 | super.viewDidLoad() 80 | 81 | setupUI() 82 | 83 | } 84 | 85 | 86 | public override func viewDidAppear(_ animated: Bool) { 87 | super.viewDidAppear(animated) 88 | 89 | scanView.startAnimation() 90 | 91 | } 92 | 93 | public override func viewDidDisappear(_ animated: Bool) { 94 | super.viewDidDisappear(animated) 95 | 96 | scanView.stopAnimation() 97 | 98 | } 99 | 100 | } 101 | 102 | 103 | 104 | // MARK: - CustomMethod 105 | extension CameraVC { 106 | 107 | func setupUI() { 108 | 109 | view.backgroundColor = .black 110 | 111 | videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 112 | 113 | videoPreviewLayer?.videoGravity = .resizeAspectFill 114 | 115 | videoPreviewLayer?.frame = view.layer.bounds 116 | 117 | guard let videoPreviewLayer = videoPreviewLayer else { 118 | return 119 | } 120 | 121 | view.layer.addSublayer(videoPreviewLayer) 122 | 123 | scanView.scanAnimationImage = animationImage 124 | 125 | scanView.scanAnimationStyle = animationStyle 126 | 127 | scanView.cornerColor = scannerColor 128 | 129 | view.addSubview(scanView) 130 | 131 | setupCamera() 132 | 133 | setupTorch() 134 | 135 | } 136 | 137 | 138 | /// 创建手电筒按钮 139 | func setupTorch() { 140 | 141 | let buttonSize:CGFloat = 37 142 | 143 | flashBtn.frame = CGRect(x: screenWidth - 20 - buttonSize, y: statusHeight + 44 + 20, width: buttonSize, height: buttonSize) 144 | 145 | flashBtn.addTarget(self, action: #selector(flashBtnClick), for: .touchUpInside) 146 | 147 | flashBtn.isHidden = true 148 | 149 | view.addSubview(flashBtn) 150 | 151 | view.bringSubviewToFront(flashBtn) 152 | 153 | torchMode = .off 154 | 155 | } 156 | 157 | 158 | 159 | // 设置相机 160 | func setupCamera() { 161 | 162 | setupSessionInput() 163 | 164 | setupSessionOutput() 165 | 166 | } 167 | 168 | 169 | //捕获设备输入流 170 | private func setupSessionInput() { 171 | 172 | guard !Platform.isSimulator else { 173 | return 174 | } 175 | 176 | guard let device = captureDevice else { 177 | return 178 | } 179 | 180 | do { 181 | let newInput = try AVCaptureDeviceInput(device: device) 182 | 183 | captureSession.beginConfiguration() 184 | 185 | if let currentInput = captureSession.inputs.first as? AVCaptureDeviceInput { 186 | captureSession.removeInput(currentInput) 187 | } 188 | 189 | captureSession.addInput(newInput) 190 | 191 | captureSession.commitConfiguration() 192 | 193 | }catch{ 194 | delegate?.didReceiveError(error) 195 | } 196 | 197 | } 198 | 199 | //捕获元数据输出流 200 | private func setupSessionOutput() { 201 | 202 | guard !Platform.isSimulator else { 203 | return 204 | } 205 | 206 | let videoDataOutput = AVCaptureVideoDataOutput() 207 | 208 | videoDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main) 209 | 210 | captureSession.addOutput(videoDataOutput) 211 | 212 | let output = AVCaptureMetadataOutput() 213 | 214 | captureSession.addOutput(output) 215 | 216 | output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) 217 | 218 | for type in metadata { 219 | if !output.availableMetadataObjectTypes.contains(type){ 220 | return 221 | } 222 | } 223 | 224 | output.metadataObjectTypes = metadata 225 | 226 | videoPreviewLayer?.session = captureSession 227 | 228 | view.setNeedsLayout() 229 | } 230 | 231 | 232 | 233 | /// 开始扫描 234 | func startCapturing() { 235 | 236 | guard !Platform.isSimulator else { 237 | return 238 | } 239 | 240 | captureSession.startRunning() 241 | 242 | } 243 | 244 | 245 | /// 停止扫描 246 | func stopCapturing() { 247 | 248 | guard !Platform.isSimulator else { 249 | return 250 | } 251 | 252 | captureSession.stopRunning() 253 | 254 | } 255 | 256 | 257 | } 258 | 259 | 260 | 261 | 262 | // MARK: - AVCaptureMetadataOutputObjectsDelegate 263 | extension CameraVC:AVCaptureMetadataOutputObjectsDelegate{ 264 | 265 | public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 266 | 267 | stopCapturing() 268 | 269 | guard let object = metadataObjects.first as? AVMetadataMachineReadableCodeObject else { 270 | return 271 | } 272 | 273 | delegate?.didOutput(object.stringValue ?? "") 274 | 275 | } 276 | 277 | } 278 | 279 | 280 | 281 | // MARK: - AVCaptureVideoDataOutputSampleBufferDelegate 282 | extension CameraVC:AVCaptureVideoDataOutputSampleBufferDelegate{ 283 | 284 | public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 285 | 286 | let metadataDict = CMCopyDictionaryOfAttachments(allocator: nil,target: sampleBuffer, attachmentMode: kCMAttachmentMode_ShouldPropagate) 287 | 288 | guard let metadata = metadataDict as? [String:Any], 289 | let exifMetadata = metadata[kCGImagePropertyExifDictionary as String] as? [String:Any], 290 | let brightnessValue = exifMetadata[kCGImagePropertyExifBrightnessValue as String] as? Double else{ 291 | return 292 | } 293 | 294 | // 判断光线强弱 295 | if brightnessValue < -1.0 { 296 | 297 | flashBtn.isHidden = false 298 | 299 | }else{ 300 | 301 | if torchMode == .on{ 302 | flashBtn.isHidden = false 303 | }else{ 304 | flashBtn.isHidden = true 305 | } 306 | 307 | } 308 | 309 | } 310 | } 311 | 312 | 313 | 314 | // MARK: - Click 315 | extension CameraVC{ 316 | 317 | @objc func flashBtnClick(sender:UIButton) { 318 | 319 | torchMode = torchMode.next 320 | 321 | } 322 | 323 | } 324 | -------------------------------------------------------------------------------- /SwiftScanner/Controllers/HeaderVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderVC.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol HeaderViewControllerDelegate: class{ 12 | 13 | func didClickedCloseButton() 14 | 15 | } 16 | 17 | 18 | public class HeaderVC: UIViewController { 19 | 20 | 21 | /// 设置present方式时的导航栏标题 22 | public override var title: String? { 23 | didSet{ 24 | titleItem.title = title 25 | } 26 | } 27 | 28 | public lazy var closeImage = imageNamed("icon_back") 29 | 30 | @IBOutlet weak public var navigationBar: UINavigationBar! 31 | 32 | @IBOutlet weak var closeBtn: UIBarButtonItem! 33 | 34 | @IBOutlet weak var titleItem: UINavigationItem! 35 | 36 | public weak var delegate:HeaderViewControllerDelegate? 37 | 38 | public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 39 | 40 | let bundle = Bundle(for: HeaderVC.self) 41 | 42 | super.init(nibName: nibNameOrNil, bundle: bundle) 43 | 44 | view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: statusHeight + navigationBar.frame.height) 45 | 46 | } 47 | 48 | 49 | required init?(coder aDecoder: NSCoder) { 50 | fatalError("init(coder:) has not been implemented") 51 | } 52 | 53 | 54 | public override func viewWillAppear(_ animated: Bool) { 55 | 56 | super.viewWillAppear(animated) 57 | 58 | setupUI() 59 | 60 | } 61 | 62 | @IBAction func closeBtnClick(_ sender: Any) { 63 | 64 | delegate?.didClickedCloseButton() 65 | } 66 | 67 | 68 | } 69 | 70 | 71 | 72 | 73 | // MARK: - CustomMethod 74 | extension HeaderVC{ 75 | 76 | func setupUI() { 77 | 78 | closeBtn.setBackgroundImage(closeImage, for: .normal, barMetrics: .default) 79 | 80 | } 81 | } 82 | 83 | 84 | extension HeaderVC:UINavigationBarDelegate { 85 | 86 | public func position(for bar: UIBarPositioning) -> UIBarPosition { 87 | return .topAttached 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /SwiftScanner/Controllers/HeaderVC.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /SwiftScanner/Controllers/ScannerVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScannerVC.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/30. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | public class ScannerVC: UIViewController { 13 | 14 | 15 | public lazy var headerViewController:HeaderVC = .init() 16 | 17 | public lazy var cameraViewController:CameraVC = .init() 18 | 19 | /// 动画样式 20 | public var animationStyle:ScanAnimationStyle = .default{ 21 | didSet{ 22 | cameraViewController.animationStyle = animationStyle 23 | } 24 | } 25 | 26 | // 扫描框颜色 27 | public var scannerColor:UIColor = .red{ 28 | didSet{ 29 | cameraViewController.scannerColor = scannerColor 30 | } 31 | } 32 | 33 | /// `AVCaptureMetadataOutput` metadata object types. 34 | public var metadata = AVMetadataObject.ObjectType.metadata { 35 | didSet{ 36 | cameraViewController.metadata = metadata 37 | } 38 | } 39 | 40 | public var successBlock:((String)->())? 41 | 42 | public var errorBlock:((Error)->())? 43 | 44 | 45 | /// 设置标题 46 | public override var title: String?{ 47 | 48 | didSet{ 49 | 50 | if navigationController == nil { 51 | headerViewController.title = title 52 | } 53 | } 54 | 55 | } 56 | 57 | 58 | /// 设置Present模式时关闭按钮的图片 59 | public var closeImage: UIImage?{ 60 | 61 | didSet{ 62 | 63 | if navigationController == nil { 64 | headerViewController.closeImage = closeImage ?? UIImage() 65 | } 66 | } 67 | 68 | } 69 | 70 | override public func viewDidLoad() { 71 | super.viewDidLoad() 72 | 73 | setupUI() 74 | 75 | } 76 | 77 | 78 | public override func viewDidAppear(_ animated: Bool) { 79 | super.viewDidAppear(animated) 80 | 81 | cameraViewController.startCapturing() 82 | } 83 | 84 | 85 | 86 | 87 | } 88 | 89 | 90 | 91 | 92 | // MARK: - CustomMethod 93 | extension ScannerVC{ 94 | 95 | func setupUI() { 96 | 97 | if title == nil { 98 | title = "扫一扫" 99 | } 100 | 101 | view.backgroundColor = .black 102 | 103 | headerViewController.delegate = self 104 | 105 | cameraViewController.metadata = metadata 106 | 107 | cameraViewController.animationStyle = animationStyle 108 | 109 | cameraViewController.delegate = self 110 | 111 | add(cameraViewController) 112 | 113 | if navigationController == nil { 114 | 115 | add(headerViewController) 116 | 117 | view.bringSubviewToFront(headerViewController.view) 118 | 119 | } 120 | 121 | 122 | } 123 | 124 | 125 | public func setupScanner(_ title:String? = nil, _ color:UIColor? = nil, _ style:ScanAnimationStyle? = nil,_ success:@escaping ((String)->())){ 126 | 127 | if title != nil { 128 | self.title = title 129 | } 130 | 131 | if color != nil { 132 | scannerColor = color! 133 | } 134 | 135 | if style != nil { 136 | animationStyle = style! 137 | } 138 | 139 | successBlock = success 140 | 141 | } 142 | 143 | 144 | } 145 | 146 | 147 | 148 | 149 | // MARK: - HeaderViewControllerDelegate 150 | extension ScannerVC:HeaderViewControllerDelegate{ 151 | 152 | 153 | /// 点击关闭 154 | public func didClickedCloseButton() { 155 | 156 | dismiss(animated: true, completion: nil) 157 | 158 | } 159 | 160 | } 161 | 162 | 163 | 164 | extension ScannerVC:CameraViewControllerDelegate{ 165 | 166 | func didOutput(_ code: String) { 167 | 168 | successBlock?(code) 169 | 170 | } 171 | 172 | func didReceiveError(_ error: Error) { 173 | 174 | errorBlock?(error) 175 | 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /SwiftScanner/Extensions/AVMetadataObject+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVMetadataObject+Extensions.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | 11 | extension AVMetadataObject.ObjectType{ 12 | 13 | public static let upca:AVMetadataObject.ObjectType = .init(rawValue: "org.gs1.UPC-A") 14 | 15 | /// `AVCaptureMetadataOutput` metadata object types. 16 | public static var metadata = [ 17 | 18 | AVMetadataObject.ObjectType.aztec, 19 | 20 | AVMetadataObject.ObjectType.code128, 21 | 22 | AVMetadataObject.ObjectType.code39, 23 | 24 | AVMetadataObject.ObjectType.code39Mod43, 25 | 26 | AVMetadataObject.ObjectType.code93, 27 | 28 | AVMetadataObject.ObjectType.dataMatrix, 29 | 30 | AVMetadataObject.ObjectType.ean13, 31 | 32 | AVMetadataObject.ObjectType.ean8, 33 | 34 | AVMetadataObject.ObjectType.face, 35 | 36 | AVMetadataObject.ObjectType.interleaved2of5, 37 | 38 | AVMetadataObject.ObjectType.itf14, 39 | 40 | AVMetadataObject.ObjectType.pdf417, 41 | 42 | AVMetadataObject.ObjectType.qr, 43 | 44 | AVMetadataObject.ObjectType.upce 45 | 46 | ] 47 | 48 | } 49 | -------------------------------------------------------------------------------- /SwiftScanner/Extensions/Platform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Platform.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Platform { 12 | static let isSimulator: Bool = { 13 | #if swift(>=4.1) 14 | #if targetEnvironment(simulator) 15 | return true 16 | #else 17 | return false 18 | #endif 19 | #else 20 | #if (arch(i386) || arch(x86_64)) && os(iOS) 21 | return true 22 | #else 23 | return false 24 | #endif 25 | #endif 26 | }() 27 | } 28 | -------------------------------------------------------------------------------- /SwiftScanner/Extensions/ScanAnimation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScanAnimation.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/12/3. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ScanAnimation:NSObject{ 12 | 13 | static let shared:ScanAnimation = { 14 | 15 | let instance = ScanAnimation() 16 | 17 | return instance 18 | }() 19 | 20 | lazy var animationImageView = UIImageView() 21 | 22 | var displayLink:CADisplayLink? 23 | 24 | var tempFrame:CGRect? 25 | 26 | var contentHeight:CGFloat? 27 | 28 | func startWith(_ rect:CGRect, _ parentView:UIView, imageView:UIImageView) { 29 | 30 | tempFrame = rect 31 | 32 | imageView.frame = tempFrame ?? CGRect.zero 33 | 34 | animationImageView = imageView 35 | 36 | contentHeight = parentView.bounds.height 37 | 38 | parentView.addSubview(imageView) 39 | 40 | setupDisplayLink() 41 | 42 | } 43 | 44 | 45 | @objc func animation() { 46 | 47 | if animationImageView.frame.maxY > contentHeight! + 20 { 48 | animationImageView.frame = tempFrame ?? CGRect.zero 49 | } 50 | 51 | animationImageView.transform = CGAffineTransform(translationX: 0, y: 2).concatenating(animationImageView.transform) 52 | 53 | } 54 | 55 | 56 | func setupDisplayLink() { 57 | 58 | displayLink = CADisplayLink(target: self, selector: #selector(animation)) 59 | 60 | displayLink?.add(to: .current, forMode: .common) 61 | 62 | displayLink?.isPaused = true 63 | 64 | } 65 | 66 | 67 | func startAnimation() { 68 | 69 | displayLink?.isPaused = false 70 | 71 | } 72 | 73 | 74 | func stopAnimation() { 75 | 76 | displayLink?.invalidate() 77 | 78 | displayLink = nil 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /SwiftScanner/Extensions/UIImage+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Extensions.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/12/3. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIImage{ 12 | 13 | /// 更改图片颜色 14 | public func changeColor(_ color : UIColor) -> UIImage{ 15 | 16 | UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) 17 | 18 | color.setFill() 19 | 20 | let bounds = CGRect.init(x: 0, y: 0, width: self.size.width, height: self.size.height) 21 | 22 | UIRectFill(bounds) 23 | 24 | self.draw(in: bounds, blendMode: CGBlendMode.destinationIn, alpha: 1.0) 25 | 26 | let tintedImage = UIGraphicsGetImageFromCurrentImageContext() 27 | UIGraphicsEndImageContext() 28 | 29 | guard let image = tintedImage else { 30 | return UIImage() 31 | } 32 | 33 | return image 34 | } 35 | 36 | 37 | ///生成二维码 38 | public class func generateQRCode(_ text: String,_ width:CGFloat,_ fillImage:UIImage? = nil, _ color:UIColor? = nil) -> UIImage? { 39 | 40 | //给滤镜设置内容 41 | guard let data = text.data(using: .utf8) else { 42 | return nil 43 | } 44 | 45 | if let filter = CIFilter(name: "CIQRCodeGenerator") { 46 | filter.setValue(data, forKey: "inputMessage") 47 | 48 | // 设置生成的二维码的容错率 49 | // value = @"L/M/Q/H" 50 | filter.setValue("H", forKey: "inputCorrectionLevel") 51 | 52 | //获取生成的二维码 53 | guard let outPutImage = filter.outputImage else { 54 | return nil 55 | } 56 | 57 | // 设置二维码颜色 58 | let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage":outPutImage,"inputColor0":CIColor(cgColor: color?.cgColor ?? UIColor.black.cgColor),"inputColor1":CIColor(cgColor: UIColor.clear.cgColor)]) 59 | 60 | //获取带颜色的二维码 61 | guard let newOutPutImage = colorFilter?.outputImage else { 62 | return nil 63 | } 64 | 65 | let scale = width/newOutPutImage.extent.width 66 | 67 | let transform = CGAffineTransform(scaleX: scale, y: scale) 68 | 69 | let output = newOutPutImage.transformed(by: transform) 70 | 71 | let QRCodeImage = UIImage(ciImage: output) 72 | 73 | guard let fillImage = fillImage else { 74 | return QRCodeImage 75 | } 76 | 77 | let imageSize = QRCodeImage.size 78 | 79 | UIGraphicsBeginImageContext(imageSize) 80 | 81 | QRCodeImage.draw(in: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)) 82 | 83 | let fillRect = CGRect(x: (width - width/5)/2, y: (width - width/5)/2, width: width/5, height: width/5) 84 | 85 | fillImage.draw(in: fillRect) 86 | 87 | guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else { return QRCodeImage } 88 | 89 | UIGraphicsEndImageContext() 90 | 91 | return newImage 92 | 93 | } 94 | 95 | return nil 96 | 97 | } 98 | 99 | 100 | ///生成条形码 101 | public class func generateCode128(_ text:String, _ size:CGSize,_ color:UIColor? = nil ) -> UIImage? 102 | { 103 | //给滤镜设置内容 104 | guard let data = text.data(using: .utf8) else { 105 | return nil 106 | } 107 | 108 | if let filter = CIFilter(name: "CICode128BarcodeGenerator") { 109 | 110 | filter.setDefaults() 111 | 112 | filter.setValue(data, forKey: "inputMessage") 113 | 114 | //获取生成的条形码 115 | guard let outPutImage = filter.outputImage else { 116 | return nil 117 | } 118 | 119 | // 设置条形码颜色 120 | let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage":outPutImage,"inputColor0":CIColor(cgColor: color?.cgColor ?? UIColor.black.cgColor),"inputColor1":CIColor(cgColor: UIColor.clear.cgColor)]) 121 | 122 | //获取带颜色的条形码 123 | guard let newOutPutImage = colorFilter?.outputImage else { 124 | return nil 125 | } 126 | 127 | let scaleX:CGFloat = size.width/newOutPutImage.extent.width 128 | 129 | let scaleY:CGFloat = size.height/newOutPutImage.extent.height 130 | 131 | let transform = CGAffineTransform(scaleX: scaleX, y: scaleY) 132 | 133 | let output = newOutPutImage.transformed(by: transform) 134 | 135 | let barCodeImage = UIImage(ciImage: output) 136 | 137 | return barCodeImage 138 | 139 | } 140 | 141 | return nil 142 | } 143 | 144 | 145 | 146 | } 147 | -------------------------------------------------------------------------------- /SwiftScanner/Extensions/UIViewController+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+Extensions.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIViewController{ 12 | 13 | public func add(_ childController:UIViewController) { 14 | 15 | childController.willMove(toParent: self) 16 | 17 | addChild(childController) 18 | 19 | view.addSubview(childController.view) 20 | 21 | childController.didMove(toParent: self) 22 | 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /SwiftScanner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftScanner/Model/CornerLocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CornerLocation.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/30. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum CornerLocation { 12 | /// 默认与边框线同中心点 13 | case `default` 14 | /// 在边框线内部 15 | case inside 16 | /// 在边框线外部 17 | case outside 18 | } 19 | -------------------------------------------------------------------------------- /SwiftScanner/Model/ScanAnimationStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScanAnimationStyle.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/30. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum ScanAnimationStyle { 12 | /// 单线扫描样式 13 | case `default` 14 | /// 网格扫描样式 15 | case grid 16 | } 17 | -------------------------------------------------------------------------------- /SwiftScanner/Model/TorchMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TorchMode.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | import UIKit 11 | 12 | /// Wrapper around `AVCaptureTorchMode`. 13 | public enum TorchMode { 14 | case on 15 | case off 16 | 17 | /// Returns the next torch mode. 18 | var next: TorchMode { 19 | switch self { 20 | case .on: 21 | return .off 22 | case .off: 23 | return .on 24 | } 25 | } 26 | 27 | /// Torch mode image. 28 | var image: UIImage { 29 | switch self { 30 | case .on: 31 | return imageNamed("flashOn") 32 | case .off: 33 | return imageNamed("flashOff") 34 | } 35 | } 36 | 37 | /// Returns `AVCaptureTorchMode` value. 38 | var captureTorchMode: AVCaptureDevice.TorchMode { 39 | switch self { 40 | case .on: 41 | return .on 42 | case .off: 43 | return .off 44 | } 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/Info.plist -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/ScanLine@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/ScanLine@2x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/ScanLine@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/ScanLine@3x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/ScanNet@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/ScanNet@2x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/ScanNet@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/ScanNet@3x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/flashOff@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/flashOff@2x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/flashOff@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/flashOff@3x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/flashOn@3x 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/flashOn@3x 2.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/flashOn@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/flashOn@3x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/icon_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/icon_back@2x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.bundle/icon_back@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slime3/SwiftScan/a2f098a3a47a93a6463d55ed09346a460630a27f/SwiftScanner/SwiftScanner.bundle/icon_back@3x.png -------------------------------------------------------------------------------- /SwiftScanner/SwiftScanner.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftScanner.h 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/29. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftScanner. 12 | FOUNDATION_EXPORT double SwiftScannerVersionNumber; 13 | 14 | //! Project version string for SwiftScanner. 15 | FOUNDATION_EXPORT const unsigned char SwiftScannerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SwiftScanner/Views/ScanView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScanView.swift 3 | // SwiftScanner 4 | // 5 | // Created by Jason on 2018/11/30. 6 | // Copyright © 2018 Jason. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class ScanView: UIView { 12 | 13 | /// 扫描动画图片 14 | lazy var scanAnimationImage = UIImage() 15 | 16 | /// 扫描样式 17 | public lazy var scanAnimationStyle = ScanAnimationStyle.default 18 | 19 | /// 边角位置,默认与边框线同中心点 20 | public lazy var cornerLocation = CornerLocation.default 21 | 22 | /// 边框线颜色,默认白色 23 | public lazy var borderColor = UIColor.white 24 | 25 | /// 边框线宽度,默认0.2 26 | public lazy var borderLineWidth:CGFloat = 0.2 27 | 28 | /// 边角颜色,默认红色 29 | public lazy var cornerColor = UIColor.red 30 | 31 | /// 边角宽度,默认2.0 32 | public lazy var cornerWidth:CGFloat = 2.0 33 | 34 | /// 扫描区周边颜色的 alpha 值,默认 0.6 35 | public lazy var backgroundAlpha:CGFloat = 0.6 36 | 37 | 38 | /// 扫描区的宽度跟屏幕宽度的比 39 | public lazy var scanBorderWidthRadio:CGFloat = 0.6 40 | 41 | /// 扫描区的宽度 42 | lazy var scanBorderWidth = scanBorderWidthRadio * screenWidth 43 | 44 | lazy var scanBorderHeight = scanBorderWidth 45 | 46 | /// 扫描区的x值 47 | lazy var scanBorderX = 0.5 * (1 - scanBorderWidthRadio) * screenWidth 48 | 49 | /// 扫描区的y值 50 | lazy var scanBorderY = 0.5 * (screenHeight - scanBorderWidth) 51 | 52 | lazy var contentView = UIView(frame: CGRect(x: scanBorderX, y: scanBorderY, width: scanBorderWidth, height:scanBorderHeight)) 53 | 54 | override public init(frame: CGRect) { 55 | 56 | super.init(frame: frame) 57 | 58 | backgroundColor = .clear 59 | 60 | } 61 | 62 | required init?(coder aDecoder: NSCoder) { 63 | fatalError("init(coder:) has not been implemented") 64 | } 65 | 66 | 67 | override public func draw(_ rect: CGRect) { 68 | 69 | super.draw(rect) 70 | 71 | drawScan(rect) 72 | 73 | var rect:CGRect? 74 | 75 | let imageView = UIImageView(image: scanAnimationImage.changeColor(cornerColor)) 76 | 77 | if scanAnimationStyle == .default { 78 | rect = CGRect(x: 0 , y: -(12 + 20), width: scanBorderWidth , height: 12) 79 | 80 | }else{ 81 | rect = CGRect(x: 0, y: -(scanBorderHeight + 20), width: scanBorderWidth, height:scanBorderHeight) 82 | } 83 | 84 | contentView.backgroundColor = .clear 85 | 86 | contentView.clipsToBounds = true 87 | 88 | addSubview(contentView) 89 | 90 | ScanAnimation.shared.startWith(rect!, contentView, imageView: imageView) 91 | 92 | setupTips() 93 | 94 | } 95 | 96 | } 97 | 98 | 99 | 100 | // MARK: - CustomMethod 101 | extension ScanView{ 102 | 103 | 104 | func setupTips() { 105 | 106 | let tipsLbl = UILabel.init() 107 | 108 | tipsLbl.text = "将二维码/条码放置在框内, 即开始扫描" 109 | 110 | tipsLbl.textColor = .white 111 | 112 | tipsLbl.textAlignment = .center 113 | 114 | tipsLbl.font = UIFont.systemFont(ofSize: 13) 115 | 116 | addSubview(tipsLbl) 117 | 118 | tipsLbl.translatesAutoresizingMaskIntoConstraints = false 119 | 120 | NSLayoutConstraint.activate([tipsLbl.centerXAnchor.constraint(equalTo: self.centerXAnchor),tipsLbl.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 20),tipsLbl.widthAnchor.constraint(equalToConstant: screenWidth),tipsLbl.heightAnchor.constraint(equalToConstant: 14)]) 121 | 122 | } 123 | 124 | 125 | func startAnimation() { 126 | 127 | ScanAnimation.shared.startAnimation() 128 | 129 | } 130 | 131 | func stopAnimation() { 132 | ScanAnimation.shared.stopAnimation() 133 | } 134 | 135 | 136 | /// 绘制扫码效果 137 | func drawScan(_ rect: CGRect) { 138 | 139 | /// 空白区域设置 140 | UIColor.black.withAlphaComponent(backgroundAlpha).setFill() 141 | 142 | UIRectFill(rect) 143 | 144 | let context = UIGraphicsGetCurrentContext() 145 | 146 | // 获取上下文,并设置混合模式 -> destinationOut 147 | context?.setBlendMode(.destinationOut) 148 | 149 | // 设置空白区 150 | let bezierPath = UIBezierPath(rect: CGRect(x: scanBorderX + 0.5 * borderLineWidth, y: scanBorderY + 0.5 * borderLineWidth, width: scanBorderWidth - borderLineWidth, height: scanBorderHeight - borderLineWidth)) 151 | 152 | bezierPath.fill() 153 | 154 | // 执行混合模式 155 | context?.setBlendMode(.normal) 156 | 157 | /// 边框设置 158 | let borderPath = UIBezierPath(rect: CGRect(x: scanBorderX, y: scanBorderY, width: scanBorderWidth, height: scanBorderHeight)) 159 | 160 | borderPath.lineCapStyle = .butt 161 | 162 | borderPath.lineWidth = borderLineWidth 163 | 164 | borderColor.set() 165 | 166 | borderPath.stroke() 167 | 168 | //角标长度 169 | let cornerLenght:CGFloat = 20 170 | 171 | let insideExcess = 0.5 * (cornerWidth - borderLineWidth) 172 | 173 | let outsideExcess = 0.5 * (cornerWidth + borderLineWidth) 174 | 175 | /// 左上角角标 176 | let leftTopPath = UIBezierPath() 177 | 178 | leftTopPath.lineWidth = cornerWidth 179 | 180 | cornerColor.set() 181 | 182 | if cornerLocation == .inside { 183 | 184 | leftTopPath.move(to: CGPoint(x: scanBorderX + insideExcess, y: scanBorderY + cornerLenght + insideExcess)) 185 | 186 | leftTopPath.addLine(to: CGPoint(x: scanBorderX + insideExcess, y: scanBorderY + insideExcess)) 187 | 188 | leftTopPath.addLine(to: CGPoint(x: scanBorderX + cornerLenght + insideExcess, y: scanBorderY + insideExcess)) 189 | 190 | }else if cornerLocation == .outside{ 191 | 192 | leftTopPath.move(to: CGPoint(x: scanBorderX - outsideExcess, y: scanBorderY + cornerLenght - outsideExcess)) 193 | 194 | leftTopPath.addLine(to: CGPoint(x: scanBorderX - outsideExcess, y: scanBorderY - outsideExcess)) 195 | 196 | leftTopPath.addLine(to: CGPoint(x: scanBorderX + cornerLenght - outsideExcess, y: scanBorderY - outsideExcess)) 197 | 198 | }else{ 199 | 200 | leftTopPath.move(to: CGPoint(x: scanBorderX, y: scanBorderY + cornerLenght)) 201 | 202 | leftTopPath.addLine(to: CGPoint(x: scanBorderX, y: scanBorderY)) 203 | 204 | leftTopPath.addLine(to: CGPoint(x: scanBorderX + cornerLenght, y: scanBorderY)) 205 | 206 | } 207 | 208 | leftTopPath.stroke() 209 | 210 | /// 左下角角标 211 | let leftBottomPath = UIBezierPath() 212 | 213 | leftBottomPath.lineWidth = cornerWidth 214 | 215 | cornerColor.set() 216 | 217 | if cornerLocation == .inside { 218 | 219 | leftBottomPath.move(to: CGPoint(x: scanBorderX + cornerLenght + insideExcess, y: scanBorderY + scanBorderHeight - insideExcess)) 220 | 221 | leftBottomPath.addLine(to: CGPoint(x: scanBorderX + insideExcess, y: scanBorderY + scanBorderHeight - insideExcess)) 222 | 223 | leftBottomPath.addLine(to: CGPoint(x: scanBorderX + insideExcess, y: scanBorderY + scanBorderHeight - cornerLenght - insideExcess)) 224 | 225 | }else if cornerLocation == .outside{ 226 | 227 | leftBottomPath.move(to: CGPoint(x: scanBorderX + cornerLenght - outsideExcess, y: scanBorderY + scanBorderHeight + outsideExcess)) 228 | 229 | leftBottomPath.addLine(to: CGPoint(x: scanBorderX - outsideExcess, y: scanBorderY + scanBorderHeight + outsideExcess)) 230 | 231 | leftBottomPath.addLine(to: CGPoint(x: scanBorderX - outsideExcess, y: scanBorderY + scanBorderHeight - cornerLenght + outsideExcess)) 232 | 233 | }else{ 234 | 235 | leftBottomPath.move(to: CGPoint(x: scanBorderX + cornerLenght, y: scanBorderY + scanBorderHeight)) 236 | 237 | leftBottomPath.addLine(to: CGPoint(x: scanBorderX, y: scanBorderY + scanBorderHeight)) 238 | 239 | leftBottomPath.addLine(to: CGPoint(x: scanBorderX, y: scanBorderY + scanBorderHeight - cornerLenght)) 240 | 241 | } 242 | 243 | leftBottomPath.stroke() 244 | 245 | /// 右上角小图标 246 | let rightTopPath = UIBezierPath() 247 | 248 | rightTopPath.lineWidth = cornerWidth 249 | 250 | cornerColor.set() 251 | 252 | if cornerLocation == .inside { 253 | 254 | rightTopPath.move(to: CGPoint(x: scanBorderX + scanBorderWidth - cornerLenght - insideExcess, y: scanBorderY + insideExcess)) 255 | 256 | rightTopPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth - insideExcess, y: scanBorderY + insideExcess)) 257 | 258 | rightTopPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth - insideExcess, y: scanBorderY + cornerLenght + insideExcess)) 259 | 260 | } else if cornerLocation == .outside { 261 | 262 | rightTopPath.move(to: CGPoint(x: scanBorderX + scanBorderWidth - cornerLenght + outsideExcess, y: scanBorderY - outsideExcess)) 263 | 264 | rightTopPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth + outsideExcess, y: scanBorderY - outsideExcess)) 265 | 266 | rightTopPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth + outsideExcess, y: scanBorderY + cornerLenght - outsideExcess)) 267 | 268 | } else { 269 | 270 | rightTopPath.move(to: CGPoint(x: scanBorderX + scanBorderWidth - cornerLenght, y: scanBorderY)) 271 | 272 | rightTopPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth, y: scanBorderY)) 273 | 274 | rightTopPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth, y: scanBorderY + cornerLenght)) 275 | 276 | } 277 | 278 | rightTopPath.stroke() 279 | 280 | /// 右下角小图标 281 | let rightBottomPath = UIBezierPath() 282 | 283 | rightBottomPath.lineWidth = cornerWidth 284 | 285 | cornerColor.set() 286 | 287 | if cornerLocation == .inside { 288 | 289 | rightBottomPath.move(to: CGPoint(x: scanBorderX + scanBorderWidth - insideExcess, y: scanBorderY + scanBorderHeight - cornerLenght - insideExcess)) 290 | 291 | rightBottomPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth - insideExcess, y: scanBorderY + scanBorderHeight - insideExcess)) 292 | 293 | rightBottomPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth - cornerLenght - insideExcess, y: scanBorderY + scanBorderHeight - insideExcess)) 294 | 295 | } else if cornerLocation == .outside { 296 | 297 | rightBottomPath.move(to: CGPoint(x: scanBorderX + scanBorderWidth + outsideExcess, y: scanBorderY + scanBorderHeight - cornerLenght + outsideExcess)) 298 | 299 | rightBottomPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth + outsideExcess, y: scanBorderY + scanBorderHeight + outsideExcess)) 300 | 301 | rightBottomPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth - cornerLenght + outsideExcess, y: scanBorderY + scanBorderHeight + outsideExcess)) 302 | 303 | } else { 304 | 305 | rightBottomPath.move(to: CGPoint(x: scanBorderX + scanBorderWidth, y: scanBorderY + scanBorderHeight - cornerLenght)) 306 | 307 | rightBottomPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth, y: scanBorderY + scanBorderHeight)) 308 | 309 | rightBottomPath.addLine(to: CGPoint(x: scanBorderX + scanBorderWidth - cornerLenght, y: scanBorderY + scanBorderHeight)) 310 | 311 | } 312 | 313 | rightBottomPath.stroke() 314 | 315 | 316 | } 317 | 318 | } 319 | --------------------------------------------------------------------------------