forked from aerogear/aerogear-ios-cookbook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
QRcodeCaptureViewController.swift
147 lines (119 loc) · 6.32 KB
/
QRcodeCaptureViewController.swift
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import UIKit
import AVFoundation
import AeroGear_OTP
class QRcodeCaptureViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
// QRCode reader
var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
var otp: AGTotp?
// Added to support different barcodes
let supportedBarCodes = [AVMetadataObject.ObjectType.qr, AVMetadataObject.ObjectType.code128, AVMetadataObject.ObjectType.code39, AVMetadataObject.ObjectType.code93, AVMetadataObject.ObjectType.upce, AVMetadataObject.ObjectType.pdf417, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.aztec]
override func viewDidLoad() {
super.viewDidLoad()
do {
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
let input = try AVCaptureDeviceInput(device: captureDevice!)
// Initialize the captureSession object.
captureSession = AVCaptureSession()
// Set the input device on the capture session.
captureSession?.addInput(input as AVCaptureInput)
// Initialize the captureSession object.
captureSession = AVCaptureSession()
// Set the input device on the capture session.
captureSession?.addInput(input as AVCaptureInput)
// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)
// Set delegate and use the default dispatch queue to execute the call back
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
captureMetadataOutput.metadataObjectTypes = supportedBarCodes
// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
// Start video capture.
captureSession?.startRunning()
} catch let error as NSError {
// Handle any errors
print(error)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
fileprivate func parametersFromQueryString(_ queryString: String) -> [String: String] {
var parameters = [String: String]()
let queryPart = queryString.characters.split{$0 == "?"}
let query: String? = queryPart.count > 1 ? String(queryPart[1]) : nil
if let query = query {
let parameterScanner: Scanner = Scanner(string: query)
var name: NSString? = nil
var value: NSString? = nil
while (parameterScanner.isAtEnd != true) {
name = nil;
parameterScanner.scanUpTo("=", into: &name)
parameterScanner.scanString("=", into:nil)
value = nil
parameterScanner.scanUpTo("&", into:&value)
parameterScanner.scanString("&", into:nil)
print("name::\(String(describing: name)) and value::\(String(describing: value))")
if (name != nil && value != nil) {
parameters[name!.removingPercentEncoding!] = value!.removingPercentEncoding;
}
}
}
return parameters;
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
// Check if the metadataObjects array is not nil and it contains at least one object.
if metadataObjects == [] || metadataObjects.count == 0 {
return
}
// Get the metadata object.
let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
// Here we use filter method to check if the type of metadataObj is supported
// Instead of hardcoding the AVMetadataObjectTypeQRCode, we check if the type
// can be found in the array of supported bar codes.
if supportedBarCodes.filter({ $0 == metadataObj.type }).count > 0 {
if metadataObj.stringValue != nil {
// Capture is over
captureSession?.stopRunning()
let secret = self.parametersFromQueryString(metadataObj.stringValue!)["secret"]
if let secret = secret {
print("Secret found: \(secret)")
otp = AGTotp(secret: AGBase32.base32Decode(secret))
} else {
print("Secret not found.")
}
// go back to main screen
self.performSegue(withIdentifier: "displayOTP:", sender: self)
}
}
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
let viewController = segue.destination as! ViewController
viewController.otp = otp
}
}