HealthKitHostApiImpl.swift 2.26 KB
import Foundation
import HealthKit

final class HealthKitHostApiImpl: HealthKitHostApi {
  private let service: HealthKitService

  init(service: HealthKitService = .shared) {
    self.service = service
  }

  func getHealthServerAuthUrl(completion: @escaping (Result<String, Error>) -> Void) {
    // Apple Health authorization is system-managed, not URL based.
    completion(.success(""))
  }

  func cancelHealthAppAuthorization() throws -> Bool {
    // iOS does not let apps revoke HealthKit permission programmatically.
    false
  }

  func checkHealthAppAuthorization(completion: @escaping (Result<HealthAuthorization, Error>) -> Void) {
    Task {
      let authorization: HealthAuthorization
      let requestStatus: HKAuthorizationRequestStatus?

      if !service.isHealthDataAvailable {
        requestStatus = nil
        authorization = HealthAuthorization(status: -1, hasData: false)
      } else {
        requestStatus = await service.authorizationRequestStatus()
        if requestStatus == .shouldRequest {
          authorization = HealthAuthorization(status: 0, hasData: false)
        } else {
          let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date())
            ?? Date(timeIntervalSinceNow: -30 * 24 * 60 * 60)
          let hasData = await service.hasAnyReadableData(startingAt: oneMonthAgo)
          authorization = HealthAuthorization(status: hasData ? 1 : 2, hasData: hasData)
        }
      }

      DebugLogger.debugLog(
        "checkHealthAppAuthorization result: requestStatus=\(String(describing: requestStatus)) status=\(authorization.status) hasData=\(authorization.hasData)"
      )
      completion(.success(authorization))
    }
  }

  func requestHealthClientAuthorization(completion: @escaping (Result<Bool, Error>) -> Void) {
    DebugLogger.debugLog("requestHealthClientAuthorization")
    service.requestAuthorization { [service] success, error in
      if let error {
        DebugLogger.debugLog("requestHealthClientAuthorization error: \(error)")
        completion(.failure(error))
        return
      }

      DebugLogger.debugLog("requestHealthClientAuthorization granted: \(success)")
      if success {
        service.restartBackgroundObserversAfterAuthorization()
      }
      completion(.success(success))
    }
  }
}