You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xcode 16.4无法识别iOS HealthKit的HKWorkoutPlan、HKWorkoutComposition等API的问题求助

Xcode 16.4无法识别iOS HealthKit的HKWorkoutPlan、HKWorkoutComposition等API的问题求助

各位好,我最近在开发一个需要和HealthKit交互的iOS应用,遇到了一个很头疼的问题:使用Xcode 16.4(版本号16F6)编译代码时,编译器一直报找不到HealthKit相关API的错误,具体报错如下:

  • Cannot find 'HKWorkoutPlan' in scope
  • Cannot find 'HKWorkoutComposition' in scope
  • Cannot find type 'HKWorkoutGoal' in scope

我的部署目标是iOS 17,代码里也给用到这些API的方法加上了@available(iOS 17.0, *)的注解,按道理这些API在iOS 17及以上版本是原生支持的,但Xcode就是识别不到它们。

下面是我的HealthKitManager.swift完整代码,报错的部分集中在saveWorkoutPlan方法里:

//
//  HealthKitManager.swift
//  AppHere
//
import Foundation
import HealthKit

class HealthKitManager {
    // MARK: - Properties
    // Create a singleton instance so the whole app can share it.
    static let shared = HealthKitManager()
    let healthStore = HKHealthStore()
    
    // Private init to enforce the singleton pattern.
    private init() {}
    
    // MARK: - Authorization
    func requestAuthorization(completion: @escaping (Bool, Error?) -> Void) {
        // First, gotta make sure HealthKit is actually available on this device.
        guard HKHealthStore.isHealthDataAvailable() else {
            completion(false, HealthKitError.notAvailableOnDevice)
            return
        }
        
        // These are the data types I'll be writing to HealthKit.
        let typesToShare: Set = [
            HKObjectType.workoutType()
        ]
        
        // I don't need to read any data right now, but I'm requesting permission anyway
        // so I don't have to ask the user again later if I add read features.
        let typesToRead: Set = [
            HKObjectType.workoutType()
        ]
        
        // Now, actually ask the user for permission.
        healthStore.requestAuthorization(toShare: typesToShare, read: typesToRead) { success, error in
            // This completion can come back on a background thread, so I need to make
            // sure I dispatch to the main queue before calling the completion handler.
            DispatchQueue.main.async {
                completion(success, error)
            }
        }
    }
    
    // MARK: - Workout Plan Management
    // Even though my deployment target is iOS 17, using @available makes the code's
    // requirements clearer and prevents accidental use if the target ever changes.
    @available(iOS 17.0, *)
    func saveWorkoutPlan(_ workout: StructuredWorkout, completion: @escaping (Bool, Error?) -> Void) {
        do {
            // Set up the basic configuration for this workout.
            let workoutConfiguration = HKWorkoutConfiguration()
            workoutConfiguration.activityType = workout.discipline
            workoutConfiguration.locationType = .outdoor // Assuming outdoor for now.
            
            var finalBlocks: [HKWorkoutComposition.Block] = []
            var blockBuffer: [HKWorkoutComposition.Block] = []
            
            for step in workout.steps {
                if step.type == .repeatStep {
                    // If this is a repeat step, I need to wrap everything in the buffer
                    // into a repeating block.
                    guard !blockBuffer.isEmpty, let repeatCount = step.repeatCount else {
                        continue
                    }
                    
                    // Create a composition from the buffered steps that need to be repeated.
                    let repeatComposition = try HKWorkoutComposition(blocks: blockBuffer)
                    let repeatBlock = try HKWorkoutComposition.Block(composition: repeatComposition, repetitions: repeatCount)
                    finalBlocks.append(repeatBlock)
                    
                    // Clear out the buffer so it's ready for the next set of steps.
                    blockBuffer.removeAll()
                } else {
                    // For a regular step, just create a single block and add it to the buffer.
                    let goal = workoutGoal(for: step)
                    let block = try HKWorkoutComposition.Block(activity: workoutConfiguration, goal: goal)
                    blockBuffer.append(block)
                }
            }
            
            // After the loop, I need to add any steps left in the buffer that weren't
            // part of a final repeat block.
            if !blockBuffer.isEmpty {
                finalBlocks.append(contentsOf: blockBuffer)
            }
            
            // Build the final composition from all the blocks I've created.
            let composition = try HKWorkoutComposition(blocks: finalBlocks)
            let plan = HKWorkoutPlan(name: workout.name, composition: composition, date: workout.date)
            
            healthStore.save(plan) { success, error in
                if success {
                    print("✅ Successfully saved workout plan: \(workout.name)")
                }
                
                // Make sure to call the completion handler on the main thread.
                DispatchQueue.main.async {
                    completion(success, error)
                }
            }
        } catch {
            // Catch any errors that happen during the block/composition creation.
            print(" Failed to build workout plan composition: \(error.localizedDescription)")
            completion(false, error)
        }
    }
    
    // Helper function to turn my WorkoutStep into a HealthKit goal.
    @available(iOS 17.0, *)
    private func workoutGoal(for step: WorkoutStep) -> HKWorkoutGoal {
        switch step.target {
        case .open:
            return .init(duration: step.duration)
        case .power(let low, let high):
            let lowPower = HKQuantity(unit: .watt(), doubleValue: low)
            let highPower = HKQuantity(unit: .watt(), doubleValue: high)
            return .init(powerRangeFrom: lowPower, to: highPower, for: step.duration)
        case .pace(let low, let high):
            // Important: HealthKit expects speed (m/s), not pace (min/mile).
            // I'm handling the conversion before this function is ever called.
            let lowSpeed = HKQuantity(unit: .meter().unitDivided(by: .second()), doubleValue: low)
            let highSpeed = HKQuantity(unit: .meter().unitDivided(by: .second()), doubleValue: high)
            return .init(speedRangeFrom: lowSpeed, to: highSpeed, for: step.duration)
        case .heartRate(let low, let high):
            let bpmUnit = HKUnit.count().unitDivided(by: .minute())
            let lowHR = HKQuantity(unit: bpmUnit, doubleValue: low)
            let highHR = HKQuantity(unit: bpmUnit, doubleValue: high)
            return .init(heartRateRangeFrom: lowHR, to: highHR, for: step.duration)
        }
    }
}

// 自定义错误枚举,用于HealthKit相关错误处理
enum HealthKitError: Error {
    case notAvailableOnDevice
}

我已经尝试过这些方案,但都没能解决问题:

  • 确认项目的部署目标确实是iOS 17.0,没有设置成更低版本
  • 代码里已经正确导入了HealthKit框架
  • 清理了Xcode的构建缓存(Cmd+Shift+K),还手动删除了Derived Data文件夹
  • 重启过Xcode和电脑,但报错依然存在

有没有朋友遇到过类似的问题?或者知道怎么让Xcode正确识别这些HealthKit API?麻烦给我点思路,非常感谢!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 10:48:03