|
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