Initial skeleton for Universal Link handling.

This commit is contained in:
Doug
2023-09-05 17:21:53 +01:00
committed by Stefan Ceriu
parent 1a12c729de
commit b9279ce709
5 changed files with 37 additions and 15 deletions
@@ -24,6 +24,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
private let stateMachine: AppCoordinatorStateMachine private let stateMachine: AppCoordinatorStateMachine
private let navigationRootCoordinator: NavigationRootCoordinator private let navigationRootCoordinator: NavigationRootCoordinator
private let userSessionStore: UserSessionStoreProtocol private let userSessionStore: UserSessionStoreProtocol
private let appSettings: AppSettings
/// Common background task to continue long-running tasks in the background. /// Common background task to continue long-running tasks in the background.
private var backgroundTask: BackgroundTaskProtocol? private var backgroundTask: BackgroundTaskProtocol?
@@ -71,6 +72,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
AppSettings.reset() AppSettings.reset()
} }
self.appSettings = appSettings
navigationRootCoordinator = NavigationRootCoordinator() navigationRootCoordinator = NavigationRootCoordinator()
Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator, appSettings: appSettings) Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator, appSettings: appSettings)
@@ -88,7 +91,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
userSessionStore = UserSessionStore(backgroundTaskService: backgroundTaskService) userSessionStore = UserSessionStore(backgroundTaskService: backgroundTaskService)
notificationManager = NotificationManager(notificationCenter: UNUserNotificationCenter.current(), notificationManager = NotificationManager(notificationCenter: UNUserNotificationCenter.current(),
appSettings: ServiceLocator.shared.settings) appSettings: appSettings)
notificationManager.delegate = self notificationManager.delegate = self
notificationManager.start() notificationManager.start()
@@ -96,13 +99,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
fatalError("The app's version number **must** use semver for migration purposes.") fatalError("The app's version number **must** use semver for migration purposes.")
} }
if let previousVersion = ServiceLocator.shared.settings.lastVersionLaunched.flatMap(Version.init) { if let previousVersion = appSettings.lastVersionLaunched.flatMap(Version.init) {
performMigrationsIfNecessary(from: previousVersion, to: currentVersion) performMigrationsIfNecessary(from: previousVersion, to: currentVersion)
} else { } else {
// The app has been deleted since the previous run. Reset everything. // The app has been deleted since the previous run. Reset everything.
wipeUserData(includingSettings: true) wipeUserData(includingSettings: true)
} }
ServiceLocator.shared.settings.lastVersionLaunched = currentVersion.description appSettings.lastVersionLaunched = currentVersion.description
setupStateMachine() setupStateMachine()
@@ -132,6 +135,15 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
) )
} }
func handleUniversalLink(_ url: URL) {
// Parse into an AppRoute to redirect these in a type safe way.
// Until we have an OIDC callback AppRoute, handle it manually.
if url.absoluteString.starts(with: appSettings.oidcRedirectURL.absoluteString) {
MXLog.error("OIDC callback through Universal Links not implemented.")
}
}
// MARK: - AuthenticationCoordinatorDelegate // MARK: - AuthenticationCoordinatorDelegate
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didLoginWithSession userSession: UserSessionProtocol) { func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didLoginWithSession userSession: UserSessionProtocol) {
@@ -207,13 +219,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController(rootCoordinator: navigationRootCoordinator)) ServiceLocator.shared.register(userIndicatorController: UserIndicatorController(rootCoordinator: navigationRootCoordinator))
ServiceLocator.shared.register(appSettings: appSettings) ServiceLocator.shared.register(appSettings: appSettings)
ServiceLocator.shared.register(networkMonitor: NetworkMonitor()) ServiceLocator.shared.register(networkMonitor: NetworkMonitor())
ServiceLocator.shared.register(bugReportService: BugReportService(withBaseURL: ServiceLocator.shared.settings.bugReportServiceBaseURL, ServiceLocator.shared.register(bugReportService: BugReportService(withBaseURL: appSettings.bugReportServiceBaseURL,
sentryURL: ServiceLocator.shared.settings.bugReportSentryURL, sentryURL: appSettings.bugReportSentryURL,
applicationId: ServiceLocator.shared.settings.bugReportApplicationId, applicationId: appSettings.bugReportApplicationId,
sdkGitSHA: sdkGitSha(), sdkGitSHA: sdkGitSha(),
maxUploadSize: ServiceLocator.shared.settings.bugReportMaxUploadSize)) maxUploadSize: appSettings.bugReportMaxUploadSize))
ServiceLocator.shared.register(analytics: AnalyticsService(client: PostHogAnalyticsClient(), ServiceLocator.shared.register(analytics: AnalyticsService(client: PostHogAnalyticsClient(),
appSettings: ServiceLocator.shared.settings, appSettings: appSettings,
bugReportService: ServiceLocator.shared.bugReportService)) bugReportService: ServiceLocator.shared.bugReportService))
} }
@@ -231,7 +243,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
if oldVersion < Version(1, 1, 7) { if oldVersion < Version(1, 1, 7) {
MXLog.info("Migrating to v1.1.0, marking accounts as migrated.") MXLog.info("Migrating to v1.1.0, marking accounts as migrated.")
for userID in userSessionStore.userIDs { for userID in userSessionStore.userIDs {
ServiceLocator.shared.settings.migratedAccounts[userID] = true appSettings.migratedAccounts[userID] = true
} }
} }
} }
@@ -300,10 +312,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
private func startAuthentication() { private func startAuthentication() {
let authenticationNavigationStackCoordinator = NavigationStackCoordinator() let authenticationNavigationStackCoordinator = NavigationStackCoordinator()
let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: ServiceLocator.shared.settings) let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: appSettings)
authenticationCoordinator = AuthenticationCoordinator(authenticationService: authenticationService, authenticationCoordinator = AuthenticationCoordinator(authenticationService: authenticationService,
navigationStackCoordinator: authenticationNavigationStackCoordinator, navigationStackCoordinator: authenticationNavigationStackCoordinator,
appSettings: ServiceLocator.shared.settings, appSettings: appSettings,
analytics: ServiceLocator.shared.analytics, analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
authenticationCoordinator?.delegate = self authenticationCoordinator?.delegate = self
@@ -329,7 +341,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
userDisplayName: displayName, userDisplayName: displayName,
deviceID: userSession.deviceID) deviceID: userSession.deviceID)
let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: ServiceLocator.shared.settings) let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: appSettings)
_ = await authenticationService.configure(for: userSession.homeserver) _ = await authenticationService.configure(for: userSession.homeserver)
let parameters = SoftLogoutScreenCoordinatorParameters(authenticationService: authenticationService, let parameters = SoftLogoutScreenCoordinatorParameters(authenticationService: authenticationService,
@@ -361,7 +373,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
navigationSplitCoordinator: navigationSplitCoordinator, navigationSplitCoordinator: navigationSplitCoordinator,
bugReportService: ServiceLocator.shared.bugReportService, bugReportService: ServiceLocator.shared.bugReportService,
roomTimelineControllerFactory: RoomTimelineControllerFactory(), roomTimelineControllerFactory: RoomTimelineControllerFactory(),
appSettings: ServiceLocator.shared.settings, appSettings: appSettings,
analytics: ServiceLocator.shared.analytics) analytics: ServiceLocator.shared.analytics)
userSessionFlowCoordinator.callback = { [weak self] action in userSessionFlowCoordinator.callback = { [weak self] action in
@@ -668,7 +680,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
// MARK: Background app refresh // MARK: Background app refresh
private func registerBackgroundAppRefresh() { private func registerBackgroundAppRefresh() {
let result = BGTaskScheduler.shared.register(forTaskWithIdentifier: ServiceLocator.shared.settings.backgroundAppRefreshTaskIdentifier, using: .main) { [weak self] task in let result = BGTaskScheduler.shared.register(forTaskWithIdentifier: appSettings.backgroundAppRefreshTaskIdentifier, using: .main) { [weak self] task in
guard let task = task as? BGAppRefreshTask else { guard let task = task as? BGAppRefreshTask else {
MXLog.error("Invalid background app refresh configuration") MXLog.error("Invalid background app refresh configuration")
return return
@@ -681,7 +693,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
} }
private func scheduleBackgroundAppRefresh() { private func scheduleBackgroundAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: ServiceLocator.shared.settings.backgroundAppRefreshTaskIdentifier) let request = BGAppRefreshTaskRequest(identifier: appSettings.backgroundAppRefreshTaskIdentifier)
// We have other background tasks that keep the app alive // We have other background tasks that keep the app alive
request.earliestBeginDate = Date(timeIntervalSinceNow: 30) request.earliestBeginDate = Date(timeIntervalSinceNow: 30)
@@ -18,4 +18,5 @@ import Foundation
protocol AppCoordinatorProtocol: CoordinatorProtocol { protocol AppCoordinatorProtocol: CoordinatorProtocol {
var notificationManager: NotificationManagerProtocol { get } var notificationManager: NotificationManagerProtocol { get }
func handleUniversalLink(_ url: URL)
} }
@@ -35,6 +35,7 @@ struct Application: App {
WindowGroup { WindowGroup {
appCoordinator.toPresentable() appCoordinator.toPresentable()
.statusBarHidden(shouldHideStatusBar) .statusBarHidden(shouldHideStatusBar)
.onOpenURL { appCoordinator.handleUniversalLink($0) }
.introspect(.window, on: .iOS(.v16)) { window in .introspect(.window, on: .iOS(.v16)) { window in
// Workaround for SwiftUI not consistently applying the tint colour to Alerts/Confirmation Dialogs. // Workaround for SwiftUI not consistently applying the tint colour to Alerts/Confirmation Dialogs.
window.tintColor = .compound.textActionPrimary window.tintColor = .compound.textActionPrimary
@@ -60,6 +60,10 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
func toPresentable() -> AnyView { func toPresentable() -> AnyView {
navigationRootCoordinator.toPresentable() navigationRootCoordinator.toPresentable()
} }
func handleUniversalLink(_ url: URL) {
fatalError("Not implemented.")
}
} }
@MainActor @MainActor
@@ -36,4 +36,8 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol {
func toPresentable() -> AnyView { func toPresentable() -> AnyView {
AnyView(ProgressView("Running Unit Tests")) AnyView(ProgressView("Running Unit Tests"))
} }
func handleUniversalLink(_ url: URL) {
fatalError("Not implemented.")
}
} }