├── 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 | 
2 | [](https://github.com/Carthage/Carthage)
3 | 
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 | 
116 | 
117 | 
118 | 
119 | 
120 | 
121 | 
122 | 
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 |
--------------------------------------------------------------------------------