|
56 | 56 | /// Only tests should access this property.
|
57 | 57 | var immediateCallbackForTestFaking: (() -> Bool)?
|
58 | 58 |
|
59 |
| - /// All pending callbacks while a check is being performed. |
60 |
| - private var pendingCallbacks: [(Bool) -> Void]? |
| 59 | + private let condition: AuthCondition |
61 | 60 |
|
62 | 61 | /// Initializes the instance.
|
63 | 62 | /// - Parameter application: The application.
|
|
69 | 68 | self.application = application
|
70 | 69 | self.appCredentialManager = appCredentialManager
|
71 | 70 | timeout = kProbingTimeout
|
| 71 | + condition = AuthCondition() |
72 | 72 | }
|
73 | 73 |
|
74 |
| - /// Checks whether or not remote notifications are being forwarded to this class. |
75 |
| - /// - Parameter callback: The block to be called either immediately or in future once a result |
76 |
| - /// is available. |
77 |
| - func checkNotificationForwardingInternal(withCallback callback: @escaping (Bool) -> Void) { |
78 |
| - if pendingCallbacks != nil { |
79 |
| - pendingCallbacks?.append(callback) |
80 |
| - return |
| 74 | + private actor PendingCount { |
| 75 | + private var count = 0 |
| 76 | + func increment() -> Int { |
| 77 | + count = count + 1 |
| 78 | + return count |
81 | 79 | }
|
| 80 | + } |
| 81 | + |
| 82 | + private let pendingCount = PendingCount() |
| 83 | + |
| 84 | + /// Checks whether or not remote notifications are being forwarded to this class. |
| 85 | + func checkNotificationForwarding() async -> Bool { |
82 | 86 | if let getValueFunc = immediateCallbackForTestFaking {
|
83 |
| - callback(getValueFunc()) |
84 |
| - return |
| 87 | + return getValueFunc() |
85 | 88 | }
|
86 | 89 | if hasCheckedNotificationForwarding {
|
87 |
| - callback(isNotificationBeingForwarded) |
88 |
| - return |
| 90 | + return isNotificationBeingForwarded |
89 | 91 | }
|
90 |
| - hasCheckedNotificationForwarding = true |
91 |
| - pendingCallbacks = [callback] |
92 |
| - |
93 |
| - DispatchQueue.main.async { |
94 |
| - let proberNotification = [self.kNotificationDataKey: [self.kNotificationProberKey: |
95 |
| - "This fake notification should be forwarded to Firebase Auth."]] |
96 |
| - if let delegate = self.application.delegate, |
97 |
| - delegate |
98 |
| - .responds(to: #selector(UIApplicationDelegate |
99 |
| - .application(_:didReceiveRemoteNotification:fetchCompletionHandler:))) { |
100 |
| - delegate.application?(self.application, |
101 |
| - didReceiveRemoteNotification: proberNotification) { _ in |
| 92 | + if await pendingCount.increment() == 1 { |
| 93 | + DispatchQueue.main.async { |
| 94 | + let proberNotification = [self.kNotificationDataKey: [self.kNotificationProberKey: |
| 95 | + "This fake notification should be forwarded to Firebase Auth."]] |
| 96 | + if let delegate = self.application.delegate, |
| 97 | + delegate |
| 98 | + .responds(to: #selector(UIApplicationDelegate |
| 99 | + .application(_:didReceiveRemoteNotification:fetchCompletionHandler:))) { |
| 100 | + delegate.application?(self.application, |
| 101 | + didReceiveRemoteNotification: proberNotification) { _ in |
| 102 | + } |
| 103 | + } else { |
| 104 | + AuthLog.logWarning( |
| 105 | + code: "I-AUT000015", |
| 106 | + message: "The UIApplicationDelegate must handle " + |
| 107 | + "remote notification for phone number authentication to work." |
| 108 | + ) |
| 109 | + } |
| 110 | + kAuthGlobalWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(self.timeout))) { |
| 111 | + self.condition.signal() |
102 | 112 | }
|
103 |
| - } else { |
104 |
| - AuthLog.logWarning( |
105 |
| - code: "I-AUT000015", |
106 |
| - message: "The UIApplicationDelegate must handle " + |
107 |
| - "remote notification for phone number authentication to work." |
108 |
| - ) |
109 |
| - } |
110 |
| - kAuthGlobalWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(self.timeout))) { |
111 |
| - self.callback() |
112 |
| - } |
113 |
| - } |
114 |
| - } |
115 |
| - |
116 |
| - func checkNotificationForwarding() async -> Bool { |
117 |
| - return await withUnsafeContinuation { continuation in |
118 |
| - checkNotificationForwardingInternal { value in |
119 |
| - continuation.resume(returning: value) |
120 | 113 | }
|
121 | 114 | }
|
| 115 | + await condition.wait() |
| 116 | + hasCheckedNotificationForwarding = true |
| 117 | + return isNotificationBeingForwarded |
122 | 118 | }
|
123 | 119 |
|
124 | 120 | /// Attempts to handle the remote notification.
|
|
140 | 136 | return false
|
141 | 137 | }
|
142 | 138 | if dictionary[kNotificationProberKey] != nil {
|
143 |
| - if pendingCallbacks == nil { |
| 139 | + if hasCheckedNotificationForwarding { |
144 | 140 | // The prober notification probably comes from another instance, so pass it along.
|
145 | 141 | return false
|
146 | 142 | }
|
147 | 143 | isNotificationBeingForwarded = true
|
148 |
| - callback() |
| 144 | + condition.signal() |
149 | 145 | return true
|
150 | 146 | }
|
151 | 147 | guard let receipt = dictionary[kNotificationReceiptKey] as? String,
|
|
154 | 150 | }
|
155 | 151 | return appCredentialManager.canFinishVerification(withReceipt: receipt, secret: secret)
|
156 | 152 | }
|
157 |
| - |
158 |
| - // MARK: Internal methods |
159 |
| - |
160 |
| - private func callback() { |
161 |
| - guard let pendingCallbacks else { |
162 |
| - return |
163 |
| - } |
164 |
| - self.pendingCallbacks = nil |
165 |
| - for callback in pendingCallbacks { |
166 |
| - callback(isNotificationBeingForwarded) |
167 |
| - } |
168 |
| - } |
169 | 153 | }
|
170 | 154 | #endif
|
0 commit comments