|
|
|
@ -17,7 +17,7 @@ public enum PushRegistrationError: Error {
|
|
|
|
|
/**
|
|
|
|
|
* Singleton used to integrate with push notification services - registration and routing received remote notifications.
|
|
|
|
|
*/
|
|
|
|
|
@objc public class PushRegistrationManager: NSObject {
|
|
|
|
|
@objc public class PushRegistrationManager: NSObject, PKPushRegistryDelegate {
|
|
|
|
|
|
|
|
|
|
// MARK: - Dependencies
|
|
|
|
|
|
|
|
|
@ -44,21 +44,25 @@ public enum PushRegistrationError: Error {
|
|
|
|
|
private var vanillaTokenResolver: Resolver<Data>?
|
|
|
|
|
|
|
|
|
|
private var voipRegistry: PKPushRegistry?
|
|
|
|
|
private var voipTokenPromise: Promise<Data>?
|
|
|
|
|
private var voipTokenResolver: Resolver<Data>?
|
|
|
|
|
private var voipTokenPromise: Promise<Data?>?
|
|
|
|
|
private var voipTokenResolver: Resolver<Data?>?
|
|
|
|
|
|
|
|
|
|
// MARK: Public interface
|
|
|
|
|
|
|
|
|
|
public func requestPushTokens() -> Promise<(pushToken: String, voipToken: String)> {
|
|
|
|
|
return firstly {
|
|
|
|
|
self.registerUserNotificationSettings()
|
|
|
|
|
}.then { () -> Promise<(pushToken: String, voipToken: String)> in
|
|
|
|
|
Logger.info("")
|
|
|
|
|
|
|
|
|
|
return firstly { () -> Promise<Void> in
|
|
|
|
|
return self.registerUserNotificationSettings()
|
|
|
|
|
}.then { (_) -> Promise<(pushToken: String, voipToken: String)> in
|
|
|
|
|
guard !Platform.isSimulator else {
|
|
|
|
|
throw PushRegistrationError.pushNotSupported(description: "Push not supported on simulators")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self.registerForVanillaPushToken().map { vanillaPushToken -> (pushToken: String, voipToken: String) in
|
|
|
|
|
return (pushToken: vanillaPushToken, voipToken: "")
|
|
|
|
|
return self.registerForVanillaPushToken().then { vanillaPushToken -> Promise<(pushToken: String, voipToken: String)> in
|
|
|
|
|
self.registerForVoipPushToken().map { voipPushToken in
|
|
|
|
|
(pushToken: vanillaPushToken, voipToken: voipPushToken ?? "")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -168,6 +172,68 @@ public enum PushRegistrationError: Error {
|
|
|
|
|
self.vanillaTokenPromise = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func createVoipRegistryIfNecessary() {
|
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
|
|
|
|
|
|
guard voipRegistry == nil else { return }
|
|
|
|
|
let voipRegistry = PKPushRegistry(queue: nil)
|
|
|
|
|
self.voipRegistry = voipRegistry
|
|
|
|
|
voipRegistry.desiredPushTypes = [.voIP]
|
|
|
|
|
voipRegistry.delegate = self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func registerForVoipPushToken() -> Promise<String?> {
|
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
|
|
|
|
|
|
guard self.voipTokenPromise == nil else {
|
|
|
|
|
let promise = self.voipTokenPromise!
|
|
|
|
|
return promise.map { $0?.hexEncodedString }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No pending voip token yet. Create a new promise
|
|
|
|
|
let (promise, resolver) = Promise<Data?>.pending()
|
|
|
|
|
self.voipTokenPromise = promise
|
|
|
|
|
self.voipTokenResolver = resolver
|
|
|
|
|
|
|
|
|
|
// We don't create the voip registry in init, because it immediately requests the voip token,
|
|
|
|
|
// potentially before we're ready to handle it.
|
|
|
|
|
createVoipRegistryIfNecessary()
|
|
|
|
|
|
|
|
|
|
guard let voipRegistry = self.voipRegistry else {
|
|
|
|
|
owsFailDebug("failed to initialize voipRegistry")
|
|
|
|
|
resolver.reject(PushRegistrationError.assertionError(description: "failed to initialize voipRegistry"))
|
|
|
|
|
return promise.map { _ in
|
|
|
|
|
// coerce expected type of returned promise - we don't really care about the value,
|
|
|
|
|
// since this promise has been rejected. In practice this shouldn't happen
|
|
|
|
|
String()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we've already completed registering for a voip token, resolve it immediately,
|
|
|
|
|
// rather than waiting for the delegate method to be called.
|
|
|
|
|
if let voipTokenData = voipRegistry.pushToken(for: .voIP) {
|
|
|
|
|
Logger.info("using pre-registered voIP token")
|
|
|
|
|
resolver.fulfill(voipTokenData)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return promise.map { (voipTokenData: Data?) -> String? in
|
|
|
|
|
Logger.info("successfully registered for voip push notifications")
|
|
|
|
|
return voipTokenData?.hexEncodedString
|
|
|
|
|
}.ensure {
|
|
|
|
|
self.voipTokenPromise = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: PKPushRegistryDelegate
|
|
|
|
|
public func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
|
|
|
|
|
Logger.info("")
|
|
|
|
|
owsAssertDebug(type == .voIP)
|
|
|
|
|
owsAssertDebug(pushCredentials.type == .voIP)
|
|
|
|
|
guard let voipTokenResolver = voipTokenResolver else { return }
|
|
|
|
|
|
|
|
|
|
voipTokenResolver.fulfill(pushCredentials.token)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We transmit pushToken data as hex encoded string to the server
|
|
|
|
|