From 993b284c754b8bd7eec45d5a6c4cb219f751aa7b Mon Sep 17 00:00:00 2001 From: Bug Magnet Date: Thu, 24 Oct 2024 09:38:08 +0200 Subject: [PATCH] Fix building for Xcode 15 and 16 --- ios/MullvadVPN.xcodeproj/project.pbxproj | 8 +-- .../AddressCacheTracker.swift | 8 +-- ios/MullvadVPN/AppDelegate.swift | 26 ++++++-- .../RelayCacheTracker/RelayCacheTracker.swift | 8 +-- .../StorePaymentManager.swift | 4 +- .../BackgroundTaskProvider.swift | 64 +++++++++++++++++++ .../SendTunnelProviderMessageOperation.swift | 52 +-------------- .../TunnelManager/Tunnel+Messaging.swift | 22 ++++++- ios/MullvadVPN/TunnelManager/Tunnel.swift | 8 +-- .../TunnelManager/TunnelInteractor.swift | 2 +- .../TunnelManager/TunnelManager.swift | 40 ++++++------ .../TunnelManager/TunnelStore.swift | 4 +- .../UIApplication+Extensions.swift | 34 ---------- .../MullvadVPN/TunnelManager/MockTunnel.swift | 4 +- .../TunnelManager/MockTunnelInteractor.swift | 2 +- .../TunnelManager/TunnelManagerTests.swift | 8 +-- .../TunnelManager/TunnelStore+Stubs.swift | 8 +-- .../TunnelManager/UIApplication+Stubs.swift | 2 +- ios/Operations/BackgroundObserver.swift | 4 +- ios/Operations/ResultOperation.swift | 2 +- 20 files changed, 162 insertions(+), 148 deletions(-) create mode 100644 ios/MullvadVPN/TunnelManager/BackgroundTaskProvider.swift delete mode 100644 ios/MullvadVPN/TunnelManager/UIApplication+Extensions.swift diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 7fe94e8467cf..99c369c428d7 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -846,7 +846,7 @@ A9D9A4D42C36E1EA004088DD /* mullvad_rust_runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D9A4D32C36E1EA004088DD /* mullvad_rust_runtime.h */; settings = {ATTRIBUTES = (Private, ); }; }; A9DF789B2B7D1DF10094E4AD /* mullvad-api.h in Headers */ = {isa = PBXBuildFile; fileRef = 01EF6F2D2B6A51B100125696 /* mullvad-api.h */; settings = {ATTRIBUTES = (Private, ); }; }; A9DF789D2B7D1E8B0094E4AD /* LoggedInWithTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */; }; - A9E031782ACB09930095D843 /* UIApplication+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031762ACB08950095D843 /* UIApplication+Extensions.swift */; }; + A9E031782ACB09930095D843 /* BackgroundTaskProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031762ACB08950095D843 /* BackgroundTaskProvider.swift */; }; A9E0317A2ACB0AE70095D843 /* UIApplication+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */; }; A9E0317F2ACC331C0095D843 /* TunnelStatusBlockObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E0317D2ACC32920095D843 /* TunnelStatusBlockObserver.swift */; }; A9E034642ABB302000E59A5A /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E034632ABB302000E59A5A /* UIEdgeInsets+Extensions.swift */; }; @@ -2070,7 +2070,7 @@ A9D96B192A8247C100A5C673 /* MigrationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationManager.swift; sourceTree = ""; }; A9D9A4C02C36D53C004088DD /* MullvadRustRuntimeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadRustRuntimeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A9D9A4D32C36E1EA004088DD /* mullvad_rust_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mullvad_rust_runtime.h; path = include/mullvad_rust_runtime.h; sourceTree = ""; }; - A9E031762ACB08950095D843 /* UIApplication+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extensions.swift"; sourceTree = ""; }; + A9E031762ACB08950095D843 /* BackgroundTaskProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundTaskProvider.swift; sourceTree = ""; }; A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Stubs.swift"; sourceTree = ""; }; A9E0317D2ACC32920095D843 /* TunnelStatusBlockObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelStatusBlockObserver.swift; sourceTree = ""; }; A9E034632ABB302000E59A5A /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIEdgeInsets+Extensions.swift"; sourceTree = ""; }; @@ -2686,7 +2686,7 @@ 44BB5F962BE527F4002520EB /* TunnelState+UI.swift */, A9E0317D2ACC32920095D843 /* TunnelStatusBlockObserver.swift */, 5803B4B12940A48700C23744 /* TunnelStore.swift */, - A9E031762ACB08950095D843 /* UIApplication+Extensions.swift */, + A9E031762ACB08950095D843 /* BackgroundTaskProvider.swift */, 5842102F282D8A3C00F24E46 /* UpdateAccountDataOperation.swift */, 58421031282E42B000F24E46 /* UpdateDeviceDataOperation.swift */, A9F360332AAB626300F53531 /* VPNConnectionProtocol.swift */, @@ -6041,7 +6041,7 @@ 58D2240A294C90210029F5F8 /* IPAddress+Codable.swift in Sources */, 58E45A5729F12C5100281ECF /* Result+Extensions.swift in Sources */, A90C48672C36BC2600DCB94C /* EphemeralPeerReceiver.swift in Sources */, - A9E031782ACB09930095D843 /* UIApplication+Extensions.swift in Sources */, + A9E031782ACB09930095D843 /* BackgroundTaskProvider.swift in Sources */, 58D2240B294C90210029F5F8 /* Cancellable.swift in Sources */, 58D2240C294C90210029F5F8 /* WrappingError.swift in Sources */, A9A8A8EB2A262AB30086D569 /* FileCache.swift in Sources */, diff --git a/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift b/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift index 048d63d0b0ae..00d8b2fe1365 100644 --- a/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift +++ b/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift @@ -21,7 +21,7 @@ final class AddressCacheTracker { /// Logger. private let logger = Logger(label: "AddressCache.Tracker") - private let application: UIApplication + private let backgroundTaskProvider: BackgroundTaskProviding /// REST API proxy. private let apiProxy: APIQuerying @@ -45,8 +45,8 @@ final class AddressCacheTracker { private let nslock = NSLock() /// Designated initializer - init(application: UIApplication, apiProxy: APIQuerying, store: REST.AddressCache) { - self.application = application + init(backgroundTaskProvider: BackgroundTaskProviding, apiProxy: APIQuerying, store: REST.AddressCache) { + self.backgroundTaskProvider = backgroundTaskProvider self.apiProxy = apiProxy self.store = store } @@ -103,7 +103,7 @@ final class AddressCacheTracker { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Update endpoints", cancelUponExpiration: true ) diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 6314dc62ac74..2f78e904760a 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -83,20 +83,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD let tunnelSettingsListener = TunnelSettingsListener() let tunnelSettingsUpdater = SettingsUpdater(listener: tunnelSettingsListener) + let backgroundTaskProvider = BackgroundTaskProvider( + backgroundTimeRemaining: application.backgroundTimeRemaining, + application: application + ) + relayCacheTracker = RelayCacheTracker( relayCache: ipOverrideWrapper, - application: application, + backgroundTaskProvider: backgroundTaskProvider, apiProxy: apiProxy ) - addressCacheTracker = AddressCacheTracker(application: application, apiProxy: apiProxy, store: addressCache) + addressCacheTracker = AddressCacheTracker( + backgroundTaskProvider: backgroundTaskProvider, + apiProxy: apiProxy, + store: addressCache + ) - tunnelStore = TunnelStore(application: application) + tunnelStore = TunnelStore(application: backgroundTaskProvider) let relaySelector = RelaySelectorWrapper( relayCache: ipOverrideWrapper ) - tunnelManager = createTunnelManager(application: application, relaySelector: relaySelector) + tunnelManager = createTunnelManager( + backgroundTaskProvider: backgroundTaskProvider, + relaySelector: relaySelector + ) settingsObserver = TunnelBlockObserver(didUpdateTunnelSettings: { _, settings in tunnelSettingsListener.onNewSettings?(settings) @@ -104,7 +116,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD tunnelManager.addObserver(settingsObserver) storePaymentManager = StorePaymentManager( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, queue: .default(), apiProxy: apiProxy, accountsProxy: accountsProxy, @@ -155,11 +167,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } private func createTunnelManager( - application: UIApplication, + backgroundTaskProvider: BackgroundTaskProviding, relaySelector: RelaySelectorProtocol ) -> TunnelManager { return TunnelManager( - application: application, + backgroundTaskProvider: backgroundTaskProvider, tunnelStore: tunnelStore, relayCacheTracker: relayCacheTracker, accountsProxy: accountsProxy, diff --git a/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift b/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift index e8731b526827..8b00f9f26a95 100644 --- a/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift +++ b/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift @@ -34,7 +34,7 @@ final class RelayCacheTracker: RelayCacheTrackerProtocol { /// Relay cache. private let cache: RelayCacheProtocol - private let application: UIApplication + private let backgroundTaskProvider: BackgroundTaskProviding /// Lock used for synchronization. private let relayCacheLock = NSLock() @@ -57,8 +57,8 @@ final class RelayCacheTracker: RelayCacheTrackerProtocol { /// Memory cache. private var cachedRelays: CachedRelays? - init(relayCache: RelayCacheProtocol, application: UIApplication, apiProxy: APIQuerying) { - self.application = application + init(relayCache: RelayCacheProtocol, backgroundTaskProvider: BackgroundTaskProviding, apiProxy: APIQuerying) { + self.backgroundTaskProvider = backgroundTaskProvider self.apiProxy = apiProxy cache = relayCache @@ -181,7 +181,7 @@ final class RelayCacheTracker: RelayCacheTrackerProtocol { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Update relays", cancelUponExpiration: true ) diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift index dc2025df1e3d..8086e4216194 100644 --- a/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift @@ -30,7 +30,7 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver { return queue }() - private let backgroundTaskProvider: BackgroundTaskProvider + private let backgroundTaskProvider: BackgroundTaskProviding private let paymentQueue: SKPaymentQueue private let apiProxy: APIQuerying private let accountsProxy: RESTAccountHandling @@ -57,7 +57,7 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver { /// - accountsProxy: the object implementing `RESTAccountHandling`. /// - transactionLog: an instance of transaction log. Typically ``StoreTransactionLog/default``. init( - backgroundTaskProvider: BackgroundTaskProvider, + backgroundTaskProvider: BackgroundTaskProviding, queue: SKPaymentQueue, apiProxy: APIQuerying, accountsProxy: RESTAccountHandling, diff --git a/ios/MullvadVPN/TunnelManager/BackgroundTaskProvider.swift b/ios/MullvadVPN/TunnelManager/BackgroundTaskProvider.swift new file mode 100644 index 000000000000..de826634e8a3 --- /dev/null +++ b/ios/MullvadVPN/TunnelManager/BackgroundTaskProvider.swift @@ -0,0 +1,64 @@ +// +// BackgroundTaskProvider.swift +// MullvadVPN +// +// Created by Marco Nikic on 2023-10-02. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +#if canImport(UIKit) + +import Foundation +import UIKit + +@available(iOSApplicationExtension, unavailable) +public protocol BackgroundTaskProviding { + var backgroundTimeRemaining: TimeInterval { get } + #if compiler(>=6) + nonisolated + func beginBackgroundTask( + withName taskName: String?, + expirationHandler handler: (@MainActor @Sendable () -> Void)? + ) -> UIBackgroundTaskIdentifier + #else + func beginBackgroundTask( + withName taskName: String?, + expirationHandler handler: (() -> Void)? + ) -> UIBackgroundTaskIdentifier + #endif + + func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) +} + +@available(iOSApplicationExtension, unavailable) +public class BackgroundTaskProvider: BackgroundTaskProviding { + public var backgroundTimeRemaining: TimeInterval + weak var application: UIApplication! + + public init(backgroundTimeRemaining: TimeInterval, application: UIApplication) { + self.backgroundTimeRemaining = backgroundTimeRemaining + self.application = application + } + + #if compiler(>=6) + nonisolated + public func beginBackgroundTask( + withName taskName: String?, + expirationHandler handler: (@MainActor @Sendable () -> Void)? + ) -> UIBackgroundTaskIdentifier { + application.beginBackgroundTask(withName: taskName, expirationHandler: handler) + } + #else + public func beginBackgroundTask( + withName taskName: String?, + expirationHandler handler: (() -> Void)? + ) -> UIBackgroundTaskIdentifier { + application.beginBackgroundTask(withName: taskName, expirationHandler: handler) + } + #endif + + public func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) { + application.endBackgroundTask(identifier) + } +} +#endif diff --git a/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift b/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift index 04c574640ca6..47b8562f7fbd 100644 --- a/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift +++ b/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift @@ -23,7 +23,7 @@ private let defaultTimeout: Duration = .seconds(5) final class SendTunnelProviderMessageOperation: ResultOperation { typealias DecoderHandler = (Data?) throws -> Output - private let backgroundTaskProvider: BackgroundTaskProvider + private let backgroundTaskProvider: BackgroundTaskProviding private let tunnel: any TunnelProtocol private let message: TunnelProviderMessage private let timeout: Duration @@ -38,7 +38,7 @@ final class SendTunnelProviderMessageOperation: ResultOperation init( dispatchQueue: DispatchQueue, - backgroundTaskProvider: BackgroundTaskProvider, + backgroundTaskProvider: BackgroundTaskProviding, tunnel: any TunnelProtocol, message: TunnelProviderMessage, timeout: Duration? = nil, @@ -215,54 +215,6 @@ final class SendTunnelProviderMessageOperation: ResultOperation } } -extension SendTunnelProviderMessageOperation where Output: Codable { - convenience init( - dispatchQueue: DispatchQueue, - backgroundTaskProvider: BackgroundTaskProvider, - tunnel: any TunnelProtocol, - message: TunnelProviderMessage, - timeout: Duration? = nil, - completionHandler: @escaping CompletionHandler - ) { - self.init( - dispatchQueue: dispatchQueue, - backgroundTaskProvider: backgroundTaskProvider, - tunnel: tunnel, - message: message, - timeout: timeout, - decoderHandler: { data in - if let data { - return try TunnelProviderReply(messageData: data).value - } else { - throw EmptyTunnelProviderResponseError() - } - }, - completionHandler: completionHandler - ) - } -} - -extension SendTunnelProviderMessageOperation where Output == Void { - convenience init( - dispatchQueue: DispatchQueue, - backgroundTaskProvider: BackgroundTaskProvider, - tunnel: any TunnelProtocol, - message: TunnelProviderMessage, - timeout: Duration? = nil, - completionHandler: CompletionHandler? - ) { - self.init( - dispatchQueue: dispatchQueue, - backgroundTaskProvider: backgroundTaskProvider, - tunnel: tunnel, - message: message, - timeout: timeout, - decoderHandler: { _ in () }, - completionHandler: completionHandler - ) - } -} - enum SendTunnelProviderMessageError: LocalizedError, WrappingError { /// Tunnel process is either down or about to go down. case tunnelDown(NEVPNStatus) diff --git a/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift b/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift index 5f1d731d8968..280420d08684 100644 --- a/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift +++ b/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift @@ -32,6 +32,7 @@ extension TunnelProtocol { backgroundTaskProvider: backgroundTaskProvider, tunnel: self, message: .reconnectTunnel(nextRelays), + decoderHandler: { _ in () }, completionHandler: completionHandler ) @@ -44,16 +45,24 @@ extension TunnelProtocol { func getTunnelStatus( completionHandler: @escaping (Result) -> Void ) -> Cancellable { + let decoderHandler: (Data?) throws -> ObservedState = { data in + if let data { + return try TunnelProviderReply(messageData: data).value + } else { + throw EmptyTunnelProviderResponseError() + } + } + let operation = SendTunnelProviderMessageOperation( dispatchQueue: dispatchQueue, backgroundTaskProvider: backgroundTaskProvider, tunnel: self, message: .getTunnelStatus, + decoderHandler: decoderHandler, completionHandler: completionHandler ) operationQueue.addOperation(operation) - return operation } @@ -62,12 +71,21 @@ extension TunnelProtocol { _ proxyRequest: ProxyURLRequest, completionHandler: @escaping (Result) -> Void ) -> Cancellable { + let decoderHandler: (Data?) throws -> ProxyURLResponse = { data in + if let data { + return try TunnelProviderReply(messageData: data).value + } else { + throw EmptyTunnelProviderResponseError() + } + } + let operation = SendTunnelProviderMessageOperation( dispatchQueue: dispatchQueue, backgroundTaskProvider: backgroundTaskProvider, tunnel: self, message: .sendURLRequest(proxyRequest), timeout: proxyRequestTimeout, + decoderHandler: decoderHandler, completionHandler: completionHandler ) @@ -79,6 +97,7 @@ extension TunnelProtocol { backgroundTaskProvider: backgroundTaskProvider, tunnel: self, message: .cancelURLRequest(proxyRequest.id), + decoderHandler: decoderHandler, completionHandler: nil ) @@ -99,6 +118,7 @@ extension TunnelProtocol { backgroundTaskProvider: backgroundTaskProvider, tunnel: self, message: .privateKeyRotation, + decoderHandler: { _ in () }, completionHandler: completionHandler ) diff --git a/ios/MullvadVPN/TunnelManager/Tunnel.swift b/ios/MullvadVPN/TunnelManager/Tunnel.swift index 0b767e80d345..9489998ef68b 100644 --- a/ios/MullvadVPN/TunnelManager/Tunnel.swift +++ b/ios/MullvadVPN/TunnelManager/Tunnel.swift @@ -26,9 +26,9 @@ protocol TunnelProtocol: AnyObject { var status: NEVPNStatus { get } var isOnDemandEnabled: Bool { get set } var startDate: Date? { get } - var backgroundTaskProvider: BackgroundTaskProvider { get } + var backgroundTaskProvider: BackgroundTaskProviding { get } - init(tunnelProvider: TunnelManagerProtocol, backgroundTaskProvider: BackgroundTaskProvider) + init(tunnelProvider: TunnelManagerProtocol, backgroundTaskProvider: BackgroundTaskProviding) func addObserver(_ observer: any TunnelStatusObserver) func removeObserver(_ observer: any TunnelStatusObserver) @@ -53,7 +53,7 @@ final class Tunnel: TunnelProtocol, Equatable { /// Unique identifier assigned to instance at the time of creation. let identifier = UUID() - var backgroundTaskProvider: any BackgroundTaskProvider + var backgroundTaskProvider: BackgroundTaskProviding #if DEBUG /// System VPN configuration identifier. @@ -117,7 +117,7 @@ final class Tunnel: TunnelProtocol, Equatable { private var _startDate: Date? internal let tunnelProvider: TunnelProviderManagerType - init(tunnelProvider: TunnelProviderManagerType, backgroundTaskProvider: BackgroundTaskProvider) { + init(tunnelProvider: TunnelProviderManagerType, backgroundTaskProvider: BackgroundTaskProviding) { self.tunnelProvider = tunnelProvider self.backgroundTaskProvider = backgroundTaskProvider diff --git a/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift b/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift index 39587cb688e8..cb268ef33038 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift @@ -16,7 +16,7 @@ protocol TunnelInteractor { // MARK: - Tunnel manipulation var tunnel: (any TunnelProtocol)? { get } - var backgroundTaskProvider: any BackgroundTaskProvider { get } + var backgroundTaskProvider: BackgroundTaskProviding { get } func getPersistentTunnels() -> [any TunnelProtocol] func createNewTunnel() -> any TunnelProtocol diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 758be0bcb615..4703fe3cda85 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -42,7 +42,7 @@ final class TunnelManager: StorePaymentObserver { // MARK: - Internal variables - let application: BackgroundTaskProvider + let backgroundTaskProvider: BackgroundTaskProviding fileprivate let tunnelStore: any TunnelStoreProtocol private let relayCacheTracker: RelayCacheTrackerProtocol private let accountsProxy: RESTAccountHandling @@ -81,7 +81,7 @@ final class TunnelManager: StorePaymentObserver { // MARK: - Initialization init( - application: BackgroundTaskProvider, + backgroundTaskProvider: BackgroundTaskProviding, tunnelStore: any TunnelStoreProtocol, relayCacheTracker: RelayCacheTrackerProtocol, accountsProxy: RESTAccountHandling, @@ -90,7 +90,7 @@ final class TunnelManager: StorePaymentObserver { accessTokenManager: RESTAccessTokenManagement, relaySelector: RelaySelectorProtocol ) { - self.application = application + self.backgroundTaskProvider = backgroundTaskProvider self.tunnelStore = tunnelStore self.relayCacheTracker = relayCacheTracker self.accountsProxy = accountsProxy @@ -103,9 +103,9 @@ final class TunnelManager: StorePaymentObserver { NotificationCenter.default.addObserver( self, - selector: #selector(applicationDidBecomeActive(_:)), + selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, - object: application + object: nil ) } @@ -204,7 +204,7 @@ final class TunnelManager: StorePaymentObserver { loadTunnelOperation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Load tunnel configuration", cancelUponExpiration: false ) @@ -244,7 +244,7 @@ final class TunnelManager: StorePaymentObserver { ) operation.addObserver(BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Start tunnel", cancelUponExpiration: true )) @@ -279,7 +279,7 @@ final class TunnelManager: StorePaymentObserver { } operation.addObserver(BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Stop tunnel", cancelUponExpiration: true )) @@ -315,7 +315,7 @@ final class TunnelManager: StorePaymentObserver { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Reconnect tunnel", cancelUponExpiration: true ) @@ -355,7 +355,7 @@ final class TunnelManager: StorePaymentObserver { } operation.addObserver(BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: action.taskName, cancelUponExpiration: true )) @@ -408,7 +408,7 @@ final class TunnelManager: StorePaymentObserver { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Update account data", cancelUponExpiration: true ) @@ -437,7 +437,7 @@ final class TunnelManager: StorePaymentObserver { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Redeem voucher", cancelUponExpiration: true ) @@ -467,7 +467,7 @@ final class TunnelManager: StorePaymentObserver { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Update device data", cancelUponExpiration: true ) @@ -503,7 +503,7 @@ final class TunnelManager: StorePaymentObserver { operation.addObserver( BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Rotate private key", cancelUponExpiration: true ) @@ -779,7 +779,7 @@ final class TunnelManager: StorePaymentObserver { // MARK: - Private methods - @objc private func applicationDidBecomeActive(_ notification: Notification) { + @objc private func applicationDidBecomeActive() { #if DEBUG logger.debug("Refresh device state and tunnel status due to application becoming active.") #endif @@ -898,7 +898,7 @@ final class TunnelManager: StorePaymentObserver { operation.addCondition(MutuallyExclusive(category: OperationCategory.deviceStateUpdate.category)) operation.addObserver(BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: "Refresh device state", cancelUponExpiration: true )) @@ -958,7 +958,7 @@ final class TunnelManager: StorePaymentObserver { } operation.addObserver(BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: taskName, cancelUponExpiration: false )) @@ -994,7 +994,7 @@ final class TunnelManager: StorePaymentObserver { } operation.addObserver(BackgroundObserver( - backgroundTaskProvider: application, + backgroundTaskProvider: backgroundTaskProvider, name: taskName, cancelUponExpiration: false )) @@ -1204,8 +1204,8 @@ private struct TunnelInteractorProxy: TunnelInteractor { tunnelManager.tunnel } - var backgroundTaskProvider: any BackgroundTaskProvider { - tunnelManager.application + var backgroundTaskProvider: BackgroundTaskProviding { + tunnelManager.backgroundTaskProvider } func getPersistentTunnels() -> [any TunnelProtocol] { diff --git a/ios/MullvadVPN/TunnelManager/TunnelStore.swift b/ios/MullvadVPN/TunnelManager/TunnelStore.swift index 705a1f0ab28b..fa1fb0f3d712 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelStore.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelStore.swift @@ -23,7 +23,7 @@ final class TunnelStore: TunnelStoreProtocol, TunnelStatusObserver { typealias TunnelType = Tunnel private let logger = Logger(label: "TunnelStore") private let lock = NSLock() - private let application: BackgroundTaskProvider + private let application: BackgroundTaskProviding /// Persistent tunnels registered with the system. private var persistentTunnels: [TunnelType] = [] @@ -31,7 +31,7 @@ final class TunnelStore: TunnelStoreProtocol, TunnelStatusObserver { /// Newly created tunnels, stored as collection of weak boxes. private var newTunnels: [WeakBox] = [] - init(application: BackgroundTaskProvider) { + init(application: BackgroundTaskProviding) { self.application = application NotificationCenter.default.addObserver( self, diff --git a/ios/MullvadVPN/TunnelManager/UIApplication+Extensions.swift b/ios/MullvadVPN/TunnelManager/UIApplication+Extensions.swift deleted file mode 100644 index ed06c325aa5b..000000000000 --- a/ios/MullvadVPN/TunnelManager/UIApplication+Extensions.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// UIApplication+Extensions.swift -// MullvadVPN -// -// Created by Marco Nikic on 2023-10-02. -// Copyright © 2023 Mullvad VPN AB. All rights reserved. -// - -#if canImport(UIKit) - -import Foundation -import UIKit - -public protocol BackgroundTaskProvider { - var backgroundTimeRemaining: TimeInterval { get } - func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) - - #if compiler(>=6) - nonisolated - func beginBackgroundTask( - withName taskName: String?, - expirationHandler handler: (@MainActor @Sendable () -> Void)? - ) -> UIBackgroundTaskIdentifier - #else - func beginBackgroundTask( - withName taskName: String?, - expirationHandler handler: (() -> Void)? - ) -> UIBackgroundTaskIdentifier - #endif -} - -extension UIApplication: BackgroundTaskProvider {} - -#endif diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnel.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnel.swift index 302e4ca2f755..6edd2059cc3e 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnel.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnel.swift @@ -19,9 +19,9 @@ class MockTunnel: TunnelProtocol { var startDate: Date? - var backgroundTaskProvider: any BackgroundTaskProvider + var backgroundTaskProvider: BackgroundTaskProviding - required init(tunnelProvider: TunnelManagerProtocol, backgroundTaskProvider: BackgroundTaskProvider) { + required init(tunnelProvider: TunnelManagerProtocol, backgroundTaskProvider: BackgroundTaskProviding) { status = .disconnected isOnDemandEnabled = false startDate = nil diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift index 6f8999b19cd2..552607a279f5 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift @@ -23,7 +23,7 @@ class MockTunnelInteractor: TunnelInteractor { var tunnel: (any TunnelProtocol)? - var backgroundTaskProvider: any BackgroundTaskProvider { + var backgroundTaskProvider: BackgroundTaskProviding { UIApplicationStub() } diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift index d4bf276f152c..19c59a3f051d 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift @@ -18,7 +18,7 @@ class TunnelManagerTests: XCTestCase { static let store = InMemorySettingsStore() private var tunnelObserver: TunnelObserver! - var application: UIApplicationStub! + var application: BackgroundTaskProviding! var relayCacheTracker: RelayCacheTrackerStub! var accountProxy: AccountsProxyStub! var accessTokenManager: AccessTokenManagerStub! @@ -87,7 +87,7 @@ class TunnelManagerTests: XCTestCase { accountProxy.createAccountResult = .success(REST.NewAccountData.mockValue()) let tunnelManager = TunnelManager( - application: application, + backgroundTaskProvider: application, tunnelStore: TunnelStoreStub(backgroundTaskProvider: application), relayCacheTracker: relayCacheTracker, accountsProxy: accountProxy, @@ -105,7 +105,7 @@ class TunnelManagerTests: XCTestCase { accountProxy.createAccountResult = .success(REST.NewAccountData.mockValue()) let tunnelManager = TunnelManager( - application: application, + backgroundTaskProvider: application, tunnelStore: TunnelStoreStub(backgroundTaskProvider: application), relayCacheTracker: relayCacheTracker, accountsProxy: accountProxy, @@ -135,7 +135,7 @@ class TunnelManagerTests: XCTestCase { } let tunnelManager = TunnelManager( - application: application, + backgroundTaskProvider: application, tunnelStore: TunnelStore(application: application), relayCacheTracker: relayCacheTracker, accountsProxy: accountProxy, diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelStore+Stubs.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelStore+Stubs.swift index cc89fd776b43..f8946271514c 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelStore+Stubs.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelStore+Stubs.swift @@ -12,7 +12,7 @@ import NetworkExtension struct TunnelStoreStub: TunnelStoreProtocol { typealias TunnelType = TunnelStub - let backgroundTaskProvider: any BackgroundTaskProvider + let backgroundTaskProvider: any BackgroundTaskProviding func getPersistentTunnels() -> [TunnelType] { [] } @@ -35,13 +35,13 @@ final class TunnelStub: TunnelProtocol, Equatable { convenience init( tunnelProvider: SimulatorTunnelProviderManager, - backgroundTaskProvider: any BackgroundTaskProvider + backgroundTaskProvider: any BackgroundTaskProviding ) { self.init(backgroundTaskProvider: backgroundTaskProvider, status: .invalid, isOnDemandEnabled: false) } init( - backgroundTaskProvider: any BackgroundTaskProvider, + backgroundTaskProvider: any BackgroundTaskProviding, status: NEVPNStatus, isOnDemandEnabled: Bool, startDate: Date? = nil @@ -56,7 +56,7 @@ final class TunnelStub: TunnelProtocol, Equatable { func removeObserver(_ observer: TunnelStatusObserver) {} - var backgroundTaskProvider: any BackgroundTaskProvider + var backgroundTaskProvider: any BackgroundTaskProviding var status: NEVPNStatus diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/UIApplication+Stubs.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/UIApplication+Stubs.swift index a220578bb610..57240864382c 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/UIApplication+Stubs.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/UIApplication+Stubs.swift @@ -11,7 +11,7 @@ import UIKit @testable import MullvadTypes -struct UIApplicationStub: BackgroundTaskProvider { +struct UIApplicationStub: BackgroundTaskProviding { var backgroundTimeRemaining: TimeInterval { .infinity } func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) {} diff --git a/ios/Operations/BackgroundObserver.swift b/ios/Operations/BackgroundObserver.swift index 2b9181a0737c..5165780a15c9 100644 --- a/ios/Operations/BackgroundObserver.swift +++ b/ios/Operations/BackgroundObserver.swift @@ -14,12 +14,12 @@ import UIKit @available(iOSApplicationExtension, unavailable) public final class BackgroundObserver: OperationObserver { public let name: String - public let backgroundTaskProvider: BackgroundTaskProvider + public let backgroundTaskProvider: BackgroundTaskProviding public let cancelUponExpiration: Bool private var taskIdentifier: UIBackgroundTaskIdentifier? - public init(backgroundTaskProvider: BackgroundTaskProvider, name: String, cancelUponExpiration: Bool) { + public init(backgroundTaskProvider: BackgroundTaskProviding, name: String, cancelUponExpiration: Bool) { self.backgroundTaskProvider = backgroundTaskProvider self.name = name self.cancelUponExpiration = cancelUponExpiration diff --git a/ios/Operations/ResultOperation.swift b/ios/Operations/ResultOperation.swift index d555b4a9bc74..e377ecf9f520 100644 --- a/ios/Operations/ResultOperation.swift +++ b/ios/Operations/ResultOperation.swift @@ -9,7 +9,7 @@ import Foundation /// Base class for operations producing result. -open class ResultOperation: AsyncOperation, OutputOperation { +open class ResultOperation: AsyncOperation, OutputOperation, @unchecked Sendable { public typealias CompletionHandler = (Result) -> Void private let nslock = NSLock()