-
Notifications
You must be signed in to change notification settings - Fork 1
/
ViewController.swift
189 lines (170 loc) · 7.93 KB
/
ViewController.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
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
//
// ViewController.swift
// PhoneNumberCapture
//
// Created by David G. Young on 4/30/18.
// Copyright © 2018 David G. Young. All rights reserved.
//
import UIKit
import MessageUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate {
@IBOutlet weak var button: UIButton!
@IBOutlet weak var label: UILabel!
@IBOutlet weak var spinner: UIActivityIndicatorView!
var composeVC = MFMessageComposeViewController()
let AWSQueryEndpointURL = /* TODO: Paste your AWS Query Endpoint URL here */
let AwsPhoneNumber = /* TODO: Paste your AWS Phone number here */
var smsVerificationStartTime: Date?
var deviceUuid: String {
get {
if let val = UserDefaults.standard.string(forKey: "deviceUuid") {
return val
}
let val = UUID().uuidString
self.deviceUuid = val
return val
}
set {
UserDefaults.standard.set(newValue, forKey: "deviceUuid")
}
}
var phoneNumber: String? {
get {
return UserDefaults.standard.string(forKey: "phoneNumber")
}
set {
return UserDefaults.standard.set(newValue, forKey: "phoneNumber")
}
}
let dateFormatter = DateFormatter()
override func viewDidLoad() {
super.viewDidLoad()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
updateView()
}
func updateView() {
if phoneNumber != nil {
label.text = "Phone Number: \(phoneNumber!)"
button.setTitle("Reset Phone Number", for: .normal)
spinner.isHidden = true
}
else if smsVerificationStartTime == nil {
label.text = "Phone number not verified"
button.setTitle("Verify Phone Number", for: .normal)
spinner.isHidden = true
}
else {
label.text = "Verifying phone number..."
button.setTitle("Cancel Verification", for: .normal)
spinner.isHidden = false
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func buttonTapped(_ sender: Any) {
if smsVerificationStartTime != nil {
smsVerificationStartTime = nil
updateView()
}
else if (phoneNumber == nil) {
capturePhoneNumber()
}
else {
clearPhoneNumber()
updateView()
}
}
func clearPhoneNumber() {
UserDefaults.standard.set(nil, forKey: "phoneNumber")
}
func capturePhoneNumber() {
if !MFMessageComposeViewController.canSendText() {
let alert = UIAlertController(title: "Cannot send SMS", message: "SMS messaging is unavailable on this device. You may not use a Simulator, an iPod Touch, or a Phone without cell service.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: {(alert: UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}
else {
let alert = UIAlertController(title: "Prepare to send message", message: "A message dialog will be presented to register your device id and phone number with our servers. Please ensure you have cell connectivty, and tap OK. When the messaging window appears, please do not alter the message or the destination phone number otherwise registration will fail. ", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: {(alert: UIAlertAction!) in
self.composeVC.messageComposeDelegate = self
// Configure the fields of the interface.
self.composeVC.recipients = [self.AWSPhoneNumber]
self.composeVC.body = "device_uuid:\(self.deviceUuid)"
self.composeVC.disableUserAttachments()
// Present the view controller modally.
self.present(self.composeVC, animated: true, completion: nil)
// Set up a new one to use next time, as these are slow to
// get ready
self.composeVC = MFMessageComposeViewController()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default, handler: { (alert: UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
controller.dismiss(animated: true, completion: nil)
smsVerificationStartTime = Date()
updateView()
verifySmsAfterDelay()
}
func verifySmsAfterDelay() {
guard let smsVerificationStartTime = smsVerificationStartTime else {
return
}
// If 30 secs has passed since we started verification, give up.
if Date().timeIntervalSince(smsVerificationStartTime) > 60.0 {
self.smsVerificationStartTime = nil
DispatchQueue.main.async {
self.updateView()
let alert = UIAlertController(title: "Timeout Verifying Phone Number", message: "Please check your network connectivity and try again", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: {(alert: UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}
return
}
// execute the following code in one second
NSLog("Waiting one second before checking SMS verification")
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 1.0) {
NSLog("Checking SMS verification")
DeviceApi(server: self.AWSQueryEndpointURL).query(deviceUuid: self.deviceUuid, completionHandler: { (resultDict, error) in
guard resultDict != nil, error == nil, let deviceDict = resultDict!["device"] as? [String:String] else {
let errorMessage = resultDict?["errorMessage"] as? String ?? error
NSLog("error calling device service: \(errorMessage ?? "no error")")
self.verifySmsAfterDelay()
return
}
NSLog("Result: \(resultDict!)" )
self.phoneNumber = deviceDict["phone_number"]
let validationTime = self.dateFormatter.date(from: deviceDict["sns_publish_time"] ?? "")
guard let validationTimeNotNil = validationTime, validationTimeNotNil > smsVerificationStartTime else {
if validationTime == nil {
NSLog("SNS publish time could not be parsed: \(deviceDict["sns_publish_time"] ?? "nil")")
}
else {
NSLog("phone number was verified only prior to this verification operation (\(validationTime!) <= \(smsVerificationStartTime))")
}
self.verifySmsAfterDelay()
return
}
self.phoneNumber = deviceDict["origination_number"]
if (self.phoneNumber == nil) {
self.verifySmsAfterDelay()
}
else {
// We have a new phone number and its verification time was after we started this sms verification
// this means we are done!
self.smsVerificationStartTime = nil
DispatchQueue.main.async {
self.updateView()
}
}
})
}
}
}