mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Background improvements
This commit is contained in:
parent
f2d01c4f8a
commit
5e367f191d
3 changed files with 116 additions and 39 deletions
|
|
@ -935,7 +935,14 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||
return .single(nil)
|
||||
}
|
||||
}
|
||||
let wakeupManager = SharedWakeupManager(beginBackgroundTask: { name, expiration in application.beginBackgroundTask(withName: name, expirationHandler: expiration) }, endBackgroundTask: { id in application.endBackgroundTask(id) }, backgroundTimeRemaining: { application.backgroundTimeRemaining }, acquireIdleExtension: {
|
||||
let wakeupManager = SharedWakeupManager(beginBackgroundTask: { name, expiration in
|
||||
let id = application.beginBackgroundTask(withName: name, expirationHandler: expiration)
|
||||
Logger.shared.log("App \(self.episodeId)", "Begin background task \(name): \(id)")
|
||||
return id
|
||||
}, endBackgroundTask: { id in
|
||||
print("App \(self.episodeId)", "End background task \(id)")
|
||||
application.endBackgroundTask(id)
|
||||
}, backgroundTimeRemaining: { application.backgroundTimeRemaining }, acquireIdleExtension: {
|
||||
return applicationBindings.pushIdleTimerExtension()
|
||||
}, activeAccounts: sharedContext.activeAccountContexts |> map { ($0.0?.account, $0.1.map { ($0.0, $0.1.account) }) }, liveLocationPolling: liveLocationPolling, watchTasks: watchTasks, inForeground: applicationBindings.applicationInForeground, hasActiveAudioSession: self.hasActiveAudioSession.get(), notificationManager: notificationManager, mediaManager: sharedContext.mediaManager, callManager: sharedContext.callManager, accountUserInterfaceInUse: { id in
|
||||
return sharedContext.accountUserInterfaceInUse(id)
|
||||
|
|
@ -1639,9 +1646,6 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||
extendNow = true
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
extendNow = false
|
||||
#endif
|
||||
sharedApplicationContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0, extendNow: extendNow)
|
||||
})
|
||||
|
||||
|
|
@ -1713,7 +1717,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||
}
|
||||
|
||||
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
||||
Logger.shared.log("App \(self.episodeId)", "register for notifications: didRegisterForRemoteNotificationsWithDeviceToken (deviceToken: \(deviceToken))")
|
||||
Logger.shared.log("App \(self.episodeId)", "register for notifications: didRegisterForRemoteNotificationsWithDeviceToken (deviceToken: \(hexString(deviceToken)))")
|
||||
self.notificationTokenPromise.set(.single(deviceToken))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,12 +175,17 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
private var spotlightDataContext: SpotlightDataContext?
|
||||
private var widgetDataContext: WidgetDataContext?
|
||||
|
||||
private weak var appDelegate: AppDelegate?
|
||||
|
||||
private var invalidatedApsToken: Data?
|
||||
|
||||
init(mainWindow: Window1?, sharedContainerPath: String, basePath: String, encryptionParameters: ValueBoxEncryptionParameters, accountManager: AccountManager<TelegramAccountManagerTypes>, appLockContext: AppLockContext, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, hasInAppPurchases: Bool, rootPath: String, legacyBasePath: String?, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, firebaseSecretStream: Signal<[String: String], NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void, displayUpgradeProgress: @escaping (Float?) -> Void = { _ in }, appDelegate: AppDelegate?) {
|
||||
assert(Queue.mainQueue().isCurrent())
|
||||
|
||||
precondition(!testHasInstance)
|
||||
testHasInstance = true
|
||||
|
||||
self.appDelegate = appDelegate
|
||||
self.mainWindow = mainWindow
|
||||
self.applicationBindings = applicationBindings
|
||||
self.sharedContainerPath = sharedContainerPath
|
||||
|
|
@ -902,10 +907,17 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
return true
|
||||
})
|
||||
|
||||
self.registeredNotificationTokensDisposable.set((combineLatest(queue: .mainQueue(), settings, self.activeAccountContexts)
|
||||
|> mapToSignal { settings, activeAccountsAndInfo -> Signal<Never, NoError> in
|
||||
let updatedApsToken = self.apsNotificationToken |> distinctUntilChanged(isEqual: { $0 == $1 })
|
||||
self.registeredNotificationTokensDisposable.set((combineLatest(
|
||||
queue: .mainQueue(),
|
||||
settings,
|
||||
self.activeAccountContexts,
|
||||
updatedApsToken
|
||||
)
|
||||
|> mapToSignal { settings, activeAccountsAndInfo, apsNotificationToken -> Signal<(Bool, Data?), NoError> in
|
||||
let (primary, activeAccounts, _) = activeAccountsAndInfo
|
||||
var applied: [Signal<Never, NoError>] = []
|
||||
var appliedApsList: [Signal<Bool?, NoError>] = []
|
||||
var appliedVoipList: [Signal<Never, NoError>] = []
|
||||
var activeProductionUserIds = activeAccounts.map({ $0.1 }).filter({ !$0.account.testingEnvironment }).map({ $0.account.peerId.id })
|
||||
var activeTestingUserIds = activeAccounts.map({ $0.1 }).filter({ $0.account.testingEnvironment }).map({ $0.account.peerId.id })
|
||||
|
||||
|
|
@ -928,18 +940,19 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
}
|
||||
|
||||
for (_, account, _) in activeAccounts {
|
||||
let appliedAps: Signal<Never, NoError>
|
||||
let appliedAps: Signal<Bool, NoError>
|
||||
let appliedVoip: Signal<Never, NoError>
|
||||
|
||||
if !activeProductionUserIds.contains(account.account.peerId.id) && !activeTestingUserIds.contains(account.account.peerId.id) {
|
||||
appliedAps = self.apsNotificationToken
|
||||
|> distinctUntilChanged(isEqual: { $0 == $1 })
|
||||
|> mapToSignal { token -> Signal<Never, NoError> in
|
||||
guard let token = token else {
|
||||
return .complete()
|
||||
if let apsNotificationToken {
|
||||
appliedAps = account.engine.accountData.unregisterNotificationToken(token: apsNotificationToken, type: .aps(encrypt: false), otherAccountUserIds: (account.account.testingEnvironment ? allTestingUserIds : allProductionUserIds).filter({ $0 != account.account.peerId.id }))
|
||||
|> map { _ -> Bool in
|
||||
}
|
||||
return account.engine.accountData.unregisterNotificationToken(token: token, type: .aps(encrypt: false), otherAccountUserIds: (account.account.testingEnvironment ? allTestingUserIds : allProductionUserIds).filter({ $0 != account.account.peerId.id }))
|
||||
|> then(.single(true))
|
||||
} else {
|
||||
appliedAps = .single(true)
|
||||
}
|
||||
|
||||
appliedVoip = self.voipNotificationToken
|
||||
|> distinctUntilChanged(isEqual: { $0 == $1 })
|
||||
|> mapToSignal { token -> Signal<Never, NoError> in
|
||||
|
|
@ -949,19 +962,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
return account.engine.accountData.unregisterNotificationToken(token: token, type: .voip, otherAccountUserIds: (account.account.testingEnvironment ? allTestingUserIds : allProductionUserIds).filter({ $0 != account.account.peerId.id }))
|
||||
}
|
||||
} else {
|
||||
appliedAps = self.apsNotificationToken
|
||||
|> distinctUntilChanged(isEqual: { $0 == $1 })
|
||||
|> mapToSignal { token -> Signal<Never, NoError> in
|
||||
guard let token = token else {
|
||||
return .complete()
|
||||
}
|
||||
let encrypt: Bool
|
||||
if #available(iOS 10.0, *) {
|
||||
encrypt = true
|
||||
} else {
|
||||
encrypt = false
|
||||
}
|
||||
return account.engine.accountData.registerNotificationToken(token: token, type: .aps(encrypt: encrypt), sandbox: sandbox, otherAccountUserIds: (account.account.testingEnvironment ? activeTestingUserIds : activeProductionUserIds).filter({ $0 != account.account.peerId.id }), excludeMutedChats: !settings.includeMuted)
|
||||
if let apsNotificationToken {
|
||||
appliedAps = account.engine.accountData.registerNotificationToken(token: apsNotificationToken, type: .aps(encrypt: true), sandbox: sandbox, otherAccountUserIds: (account.account.testingEnvironment ? activeTestingUserIds : activeProductionUserIds).filter({ $0 != account.account.peerId.id }), excludeMutedChats: !settings.includeMuted)
|
||||
} else {
|
||||
appliedAps = .single(true)
|
||||
}
|
||||
appliedVoip = self.voipNotificationToken
|
||||
|> distinctUntilChanged(isEqual: { $0 == $1 })
|
||||
|
|
@ -970,15 +974,47 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
return .complete()
|
||||
}
|
||||
return account.engine.accountData.registerNotificationToken(token: token, type: .voip, sandbox: sandbox, otherAccountUserIds: (account.account.testingEnvironment ? activeTestingUserIds : activeProductionUserIds).filter({ $0 != account.account.peerId.id }), excludeMutedChats: !settings.includeMuted)
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
||||
applied.append(appliedAps)
|
||||
applied.append(appliedVoip)
|
||||
appliedApsList.append(Signal<Bool?, NoError>.single(nil) |> then(appliedAps |> map(Optional.init)))
|
||||
appliedVoipList.append(appliedVoip)
|
||||
}
|
||||
return combineLatest(applied)
|
||||
|> ignoreValues
|
||||
}).start())
|
||||
|
||||
let allApsSuccess = combineLatest(appliedApsList)
|
||||
|> map { values -> Bool in
|
||||
return !values.contains(false)
|
||||
}
|
||||
|
||||
let allVoipSuccess = combineLatest(appliedVoipList)
|
||||
|
||||
return combineLatest(
|
||||
allApsSuccess,
|
||||
Signal<Void, NoError>.single(Void())
|
||||
|> then(
|
||||
allVoipSuccess
|
||||
|> map { _ -> Void in
|
||||
return Void()
|
||||
}
|
||||
)
|
||||
)
|
||||
|> map { allApsSuccess, _ -> (Bool, Data?) in
|
||||
return (allApsSuccess, apsNotificationToken)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] allApsSuccess, apsToken in
|
||||
guard let self, let appDelegate = self.appDelegate else {
|
||||
return
|
||||
}
|
||||
if !allApsSuccess {
|
||||
if self.invalidatedApsToken != apsToken {
|
||||
self.invalidatedApsToken = apsToken
|
||||
|
||||
appDelegate.requestNotificationTokenInvalidation()
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
public func beginNewAuth(testingEnvironment: Bool) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public final class SharedWakeupManager {
|
|||
private var inForeground: Bool = false
|
||||
private var hasActiveAudioSession: Bool = false
|
||||
private var activeExplicitExtensionTimer: SwiftSignalKit.Timer?
|
||||
private var activeExplicitExtensionTask: UIBackgroundTaskIdentifier?
|
||||
private var allowBackgroundTimeExtensionDeadline: Double?
|
||||
private var allowBackgroundTimeExtensionDeadlineTimer: SwiftSignalKit.Timer?
|
||||
private var isInBackgroundExtension: Bool = false
|
||||
|
|
@ -87,6 +88,10 @@ public final class SharedWakeupManager {
|
|||
if value {
|
||||
strongSelf.activeExplicitExtensionTimer?.invalidate()
|
||||
strongSelf.activeExplicitExtensionTimer = nil
|
||||
if let activeExplicitExtensionTask = strongSelf.activeExplicitExtensionTask {
|
||||
strongSelf.activeExplicitExtensionTask = nil
|
||||
strongSelf.endBackgroundTask(activeExplicitExtensionTask)
|
||||
}
|
||||
strongSelf.allowBackgroundTimeExtensionDeadlineTimer?.invalidate()
|
||||
strongSelf.allowBackgroundTimeExtensionDeadlineTimer = nil
|
||||
}
|
||||
|
|
@ -198,7 +203,7 @@ public final class SharedWakeupManager {
|
|||
|
||||
func allowBackgroundTimeExtension(timeout: Double, extendNow: Bool = false) {
|
||||
let shouldCheckTasks = self.allowBackgroundTimeExtensionDeadline == nil
|
||||
self.allowBackgroundTimeExtensionDeadline = CACurrentMediaTime() + timeout
|
||||
self.allowBackgroundTimeExtensionDeadline = CFAbsoluteTimeGetCurrent() + timeout
|
||||
|
||||
self.allowBackgroundTimeExtensionDeadlineTimer?.invalidate()
|
||||
self.allowBackgroundTimeExtensionDeadlineTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: false, completion: { [weak self] in
|
||||
|
|
@ -213,15 +218,35 @@ public final class SharedWakeupManager {
|
|||
|
||||
if extendNow {
|
||||
if self.activeExplicitExtensionTimer == nil {
|
||||
self.activeExplicitExtensionTimer = SwiftSignalKit.Timer(timeout: 20.0, repeat: false, completion: { [weak self] in
|
||||
let activeExplicitExtensionTimer = SwiftSignalKit.Timer(timeout: 20.0, repeat: false, completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.activeExplicitExtensionTimer?.invalidate()
|
||||
strongSelf.activeExplicitExtensionTimer = nil
|
||||
if let activeExplicitExtensionTask = strongSelf.activeExplicitExtensionTask {
|
||||
strongSelf.activeExplicitExtensionTask = nil
|
||||
strongSelf.endBackgroundTask(activeExplicitExtensionTask)
|
||||
}
|
||||
strongSelf.checkTasks()
|
||||
}, queue: .mainQueue())
|
||||
self.activeExplicitExtensionTimer?.start()
|
||||
self.activeExplicitExtensionTimer = activeExplicitExtensionTimer
|
||||
activeExplicitExtensionTimer.start()
|
||||
|
||||
self.activeExplicitExtensionTask = self.beginBackgroundTask("explicit-extension") { [weak self, weak activeExplicitExtensionTimer] in
|
||||
guard let self, let activeExplicitExtensionTimer else {
|
||||
return
|
||||
}
|
||||
if self.activeExplicitExtensionTimer === activeExplicitExtensionTimer {
|
||||
self.activeExplicitExtensionTimer?.invalidate()
|
||||
self.activeExplicitExtensionTimer = nil
|
||||
if let activeExplicitExtensionTask = self.activeExplicitExtensionTask {
|
||||
self.activeExplicitExtensionTask = nil
|
||||
self.endBackgroundTask(activeExplicitExtensionTask)
|
||||
}
|
||||
self.checkTasks()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if shouldCheckTasks || extendNow {
|
||||
|
|
@ -313,12 +338,12 @@ public final class SharedWakeupManager {
|
|||
hasTasksForBackgroundExtension = true
|
||||
}
|
||||
|
||||
let canBeginBackgroundExtensionTasks = self.allowBackgroundTimeExtensionDeadline.flatMap({ CACurrentMediaTime() < $0 }) ?? false
|
||||
let canBeginBackgroundExtensionTasks = self.allowBackgroundTimeExtensionDeadline.flatMap({ CFAbsoluteTimeGetCurrent() < $0 }) ?? false
|
||||
if hasTasksForBackgroundExtension {
|
||||
if canBeginBackgroundExtensionTasks {
|
||||
var endTaskId: UIBackgroundTaskIdentifier?
|
||||
|
||||
let currentTime = CACurrentMediaTime()
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
if let (taskId, startTime, timer) = self.currentTask {
|
||||
if startTime < currentTime + 1.0 {
|
||||
self.currentTask = nil
|
||||
|
|
@ -328,16 +353,28 @@ public final class SharedWakeupManager {
|
|||
}
|
||||
|
||||
if self.currentTask == nil {
|
||||
let handleExpiration:() -> Void = { [weak self] in
|
||||
var actualTaskId: UIBackgroundTaskIdentifier?
|
||||
let handleExpiration: () -> Void = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let actualTaskId {
|
||||
strongSelf.endBackgroundTask(actualTaskId)
|
||||
|
||||
if let (taskId, _, timer) = strongSelf.currentTask, taskId == actualTaskId {
|
||||
timer.invalidate()
|
||||
strongSelf.currentTask = nil
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.isInBackgroundExtension = false
|
||||
strongSelf.checkTasks()
|
||||
}
|
||||
if let taskId = self.beginBackgroundTask("background-wakeup", {
|
||||
handleExpiration()
|
||||
}) {
|
||||
actualTaskId = taskId
|
||||
let timer = SwiftSignalKit.Timer(timeout: min(30.0, max(0.0, self.backgroundTimeRemaining() - 5.0)), repeat: false, completion: {
|
||||
handleExpiration()
|
||||
}, queue: Queue.mainQueue())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue