mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
Attempt to simplify the background app refresh flows and always clean up the task while at the same time make sure the task is always cleaned up (#930)
This commit is contained in:
@@ -27,6 +27,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
/// Common background task to resume long-running tasks in the background.
|
/// Common background task to resume long-running tasks in the background.
|
||||||
/// When this task expiring, we'll try to suspend the state machine by `suspend` event.
|
/// When this task expiring, we'll try to suspend the state machine by `suspend` event.
|
||||||
private var backgroundTask: BackgroundTaskProtocol?
|
private var backgroundTask: BackgroundTaskProtocol?
|
||||||
|
|
||||||
|
/// Task used while processing background app refreshes
|
||||||
|
private var backgroundAppRefreshTask: BGAppRefreshTask?
|
||||||
|
|
||||||
private var isSuspended = false
|
private var isSuspended = false
|
||||||
|
|
||||||
private var userSession: UserSessionProtocol? {
|
private var userSession: UserSessionProtocol? {
|
||||||
@@ -500,14 +504,20 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
|
|
||||||
private func stopSync() {
|
private func stopSync() {
|
||||||
userSession?.clientProxy.stopSync()
|
userSession?.clientProxy.stopSync()
|
||||||
|
|
||||||
|
backgroundAppRefreshTask?.setTaskCompleted(success: true)
|
||||||
|
backgroundAppRefreshTask = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startSync() {
|
private func startSync() {
|
||||||
// We don't fatal error here because background app refreshes might be scheduled before the session is setup
|
guard let userSession else {
|
||||||
guard let userSession else { return }
|
fatalError("User session not setup")
|
||||||
|
}
|
||||||
|
|
||||||
userSession.clientProxy.startSync()
|
userSession.clientProxy.startSync()
|
||||||
|
|
||||||
|
installBackgroundAppRefreshMonitor()
|
||||||
|
|
||||||
let identifier = "StaleDataIndicator"
|
let identifier = "StaleDataIndicator"
|
||||||
|
|
||||||
ServiceLocator.shared.userIndicatorController.submitIndicator(.init(id: identifier, type: .toast, title: L10n.commonLoading, persistent: true))
|
ServiceLocator.shared.userIndicatorController.submitIndicator(.init(id: identifier, type: .toast, title: L10n.commonLoading, persistent: true))
|
||||||
@@ -542,13 +552,15 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
backgroundTask = backgroundTaskService.startBackgroundTask(withName: "SuspendApp: \(UUID().uuidString)") { [weak self] in
|
backgroundTask = backgroundTaskService.startBackgroundTask(withName: "SuspendApp: \(UUID().uuidString)") { [weak self] in
|
||||||
guard let self else {
|
guard let self else { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
userSession?.clientProxy.stopSync {
|
userSession?.clientProxy.stopSync {
|
||||||
// No need to weakify self, this is a non escaping closure
|
// No need to weakify self, this is a non escaping closure
|
||||||
self.backgroundTask?.stop()
|
self.backgroundTask?.stop()
|
||||||
self.backgroundTask = nil
|
self.backgroundTask = nil
|
||||||
|
|
||||||
|
self.backgroundAppRefreshTask?.setTaskCompleted(success: true)
|
||||||
|
self.backgroundAppRefreshTask = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,20 +617,35 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
private func handleBackgroundAppRefresh(_ task: BGAppRefreshTask) {
|
private func handleBackgroundAppRefresh(_ task: BGAppRefreshTask) {
|
||||||
MXLog.info("Started background app refresh")
|
MXLog.info("Started background app refresh")
|
||||||
|
|
||||||
|
backgroundAppRefreshTask = task
|
||||||
|
|
||||||
// This is important for the app to keep refreshing in the background
|
// This is important for the app to keep refreshing in the background
|
||||||
scheduleBackgroundAppRefresh()
|
scheduleBackgroundAppRefresh()
|
||||||
|
|
||||||
task.expirationHandler = { [weak self] in
|
task.expirationHandler = { [weak self] in
|
||||||
MXLog.info("Background app refresh task expired")
|
MXLog.info("Background app refresh task expired")
|
||||||
self?.stopSync()
|
self?.stopSync()
|
||||||
task.setTaskCompleted(success: true)
|
}
|
||||||
|
|
||||||
|
guard let userSession, !userSession.clientProxy.isSyncing else {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
startSync()
|
startSync()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func installBackgroundAppRefreshMonitor() {
|
||||||
|
guard let userSession else {
|
||||||
|
fatalError("User session not setup")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard backgroundAppRefreshTask != nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Be a good citizen, run for a max of 10 SS responses or 10 seconds
|
// Be a good citizen, run for a max of 10 SS responses or 10 seconds
|
||||||
// An SS request will time out after 30 seconds if no new data is available
|
// An SS request will time out after 30 seconds if no new data is available
|
||||||
backgroundRefreshSyncObserver = userSession?.clientProxy
|
backgroundRefreshSyncObserver = userSession.clientProxy
|
||||||
.callbacks
|
.callbacks
|
||||||
.filter(\.isSyncUpdate)
|
.filter(\.isSyncUpdate)
|
||||||
.collect(.byTimeOrCount(DispatchQueue.main, .seconds(10), 10))
|
.collect(.byTimeOrCount(DispatchQueue.main, .seconds(10), 10))
|
||||||
@@ -626,7 +653,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
MXLog.info("Background app refresh finished")
|
MXLog.info("Background app refresh finished")
|
||||||
self?.backgroundRefreshSyncObserver?.cancel()
|
self?.backgroundRefreshSyncObserver?.cancel()
|
||||||
self?.stopSync()
|
self?.stopSync()
|
||||||
task.setTaskCompleted(success: true)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user