Centralize dependency wiring with Session/Context/Network/UI/Runtime bundles, unify leaf ViewControllers on appServices, and add a test initializer with AppServicesTests. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
6.0 KiB
Swift
165 lines
6.0 KiB
Swift
//
|
||
// AppServices.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/6/26.
|
||
//
|
||
|
||
import Foundation
|
||
|
||
@MainActor
|
||
/// 全局依赖容器,集中提供 ViewModel 与 ViewController 所需的 API 和上下文。
|
||
final class AppServices {
|
||
static let shared = AppServices()
|
||
|
||
let session: SessionBundle
|
||
let context: AppContextBundle
|
||
let network: NetworkBundle
|
||
let ui: UIFeedbackBundle
|
||
let runtime: AppRuntimeBundle
|
||
let appRouter = AppRouter()
|
||
|
||
private let tokenStore: SessionTokenStore
|
||
private let snapshotStore: AccountSnapshotStore
|
||
|
||
// MARK: - 扁平访问(兼容现有调用方)
|
||
|
||
var appSession: AppSession { session.appSession }
|
||
var accountContext: AccountContext { context.accountContext }
|
||
var permissionContext: PermissionContext { context.permissionContext }
|
||
var scenicSpotContext: ScenicSpotContext { context.scenicSpotContext }
|
||
var toastCenter: ToastCenter { ui.toastCenter }
|
||
var globalLoading: GlobalLoadingCenter { ui.globalLoading }
|
||
var scenicQueueRuntime: ScenicQueueRuntime { runtime.scenicQueueRuntime }
|
||
|
||
var apiClient: APIClient { network.apiClient }
|
||
var authAPI: AuthAPI { network.authAPI }
|
||
var profileAPI: ProfileAPI { network.profileAPI }
|
||
var uploadAPI: UploadAPI { network.uploadAPI }
|
||
var ossUploadService: OSSUploadService { network.ossUploadService }
|
||
var accountContextAPI: AccountContextAPI { network.accountContextAPI }
|
||
var ordersAPI: OrdersAPI { network.ordersAPI }
|
||
var statisticsAPI: StatisticsAPI { network.statisticsAPI }
|
||
var paymentAPI: PaymentAPI { network.paymentAPI }
|
||
var walletAPI: WalletAPI { network.walletAPI }
|
||
var pushAPI: PushAPI { network.pushAPI }
|
||
var scenicPermissionAPI: ScenicPermissionAPI { network.scenicPermissionAPI }
|
||
var scenicSettlementAPI: ScenicSettlementAPI { network.scenicSettlementAPI }
|
||
var messageCenterAPI: MessageCenterAPI { network.messageCenterAPI }
|
||
var scenicQueueAPI: ScenicQueueAPI { network.scenicQueueAPI }
|
||
var liveAPI: LiveAPI { network.liveAPI }
|
||
var operatingAreaAPI: OperatingAreaAPI { network.operatingAreaAPI }
|
||
var pilotCertificationAPI: PilotCertificationAPI { network.pilotCertificationAPI }
|
||
var taskAPI: TaskAPI { network.taskAPI }
|
||
var projectAPI: ProjectAPI { network.projectAPI }
|
||
var scheduleAPI: ScheduleAPI { network.scheduleAPI }
|
||
var inviteAPI: InviteAPI { network.inviteAPI }
|
||
var assetsAPI: AssetsAPI { network.assetsAPI }
|
||
var punchPointAPI: PunchPointAPI { network.punchPointAPI }
|
||
var locationReportAPI: LocationReportAPI { network.locationReportAPI }
|
||
|
||
var authSessionCoordinator: AuthSessionCoordinator { session.authSessionCoordinator }
|
||
var sessionBootstrapper: SessionBootstrapper { session.sessionBootstrapper }
|
||
|
||
/// 当前景区 ID。
|
||
var currentScenicId: Int? {
|
||
accountContext.currentScenic?.id
|
||
}
|
||
|
||
/// 当前用户 staffId,用于钱包等接口。
|
||
var staffId: Int? {
|
||
Int(accountContext.profile?.userId ?? "")
|
||
}
|
||
|
||
/// 当前用户 ID 字符串。
|
||
var userId: String? {
|
||
accountContext.profile?.userId
|
||
}
|
||
|
||
/// 生产环境默认初始化。
|
||
private init() {
|
||
let tokenStore = SessionTokenStore()
|
||
let snapshotStore = AccountSnapshotStore()
|
||
let preferencesStore = AppPreferencesStore()
|
||
let apiClient = APIClient()
|
||
|
||
self.tokenStore = tokenStore
|
||
self.snapshotStore = snapshotStore
|
||
context = AppContextBundle(
|
||
accountContext: AccountContext(),
|
||
permissionContext: PermissionContext(),
|
||
scenicSpotContext: ScenicSpotContext()
|
||
)
|
||
network = NetworkBundle(apiClient: apiClient)
|
||
ui = UIFeedbackBundle(
|
||
toastCenter: ToastCenter(),
|
||
globalLoading: GlobalLoadingCenter()
|
||
)
|
||
runtime = AppRuntimeBundle(scenicQueueRuntime: ScenicQueueRuntime())
|
||
session = SessionBundle(
|
||
appSession: AppSession(),
|
||
authSessionCoordinator: AuthSessionCoordinator(
|
||
tokenStore: tokenStore,
|
||
snapshotStore: snapshotStore,
|
||
preferencesStore: preferencesStore
|
||
),
|
||
sessionBootstrapper: SessionBootstrapper(
|
||
tokenStore: tokenStore,
|
||
snapshotStore: snapshotStore
|
||
)
|
||
)
|
||
bindAuthTokenProvider()
|
||
}
|
||
|
||
/// 测试专用初始化,允许注入 mock `APIClient` 与存储替身。
|
||
init(
|
||
apiClient: APIClient,
|
||
tokenStore: SessionTokenStore = SessionTokenStore(),
|
||
snapshotStore: AccountSnapshotStore = AccountSnapshotStore(),
|
||
preferencesStore: AppPreferencesStore = AppPreferencesStore()
|
||
) {
|
||
self.tokenStore = tokenStore
|
||
self.snapshotStore = snapshotStore
|
||
context = AppContextBundle(
|
||
accountContext: AccountContext(),
|
||
permissionContext: PermissionContext(),
|
||
scenicSpotContext: ScenicSpotContext()
|
||
)
|
||
network = NetworkBundle(apiClient: apiClient)
|
||
ui = UIFeedbackBundle(
|
||
toastCenter: ToastCenter(),
|
||
globalLoading: GlobalLoadingCenter()
|
||
)
|
||
runtime = AppRuntimeBundle(scenicQueueRuntime: ScenicQueueRuntime())
|
||
session = SessionBundle(
|
||
appSession: AppSession(),
|
||
authSessionCoordinator: AuthSessionCoordinator(
|
||
tokenStore: tokenStore,
|
||
snapshotStore: snapshotStore,
|
||
preferencesStore: preferencesStore
|
||
),
|
||
sessionBootstrapper: SessionBootstrapper(
|
||
tokenStore: tokenStore,
|
||
snapshotStore: snapshotStore
|
||
)
|
||
)
|
||
bindAuthTokenProvider()
|
||
}
|
||
|
||
/// 绑定推送与 UIKit 导航。
|
||
func configurePushNotifications() {
|
||
PushNotificationManager.shared.configure(
|
||
api: pushAPI,
|
||
session: appSession,
|
||
router: appRouter
|
||
)
|
||
}
|
||
|
||
/// 将 `APIClient` 与当前 `AppSession` token 关联。
|
||
private func bindAuthTokenProvider() {
|
||
apiClient.bindAuthTokenProvider { [unowned self] in
|
||
appSession.token
|
||
}
|
||
}
|
||
}
|