自定义颜色导致Live Activities无法显示问题求助
问题根源
你使用的Color Codable扩展没有适配从Assets目录加载的自定义颜色。原扩展仅支持系统预定义颜色(如.red)和基于RGB/HSL数值初始化的颜色,但对于Color("YourCustomColor")这类依赖资源名称的颜色,编码解码过程中会丢失关键的资源标识信息,导致解码后的Color对象无效,最终触发Live Activity渲染失败,所以锁屏上完全看不到活动内容。
修复方案
修改Color的Codable扩展,增加对资源名称类型Color的支持。核心思路是在编码时识别资源颜色并存储其名称,解码时根据存储的信息还原对应的颜色:
extension Color: Codable { private enum CodingKeys: String, CodingKey { case resourceName case rgbComponents case systemColorName } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 优先尝试解码资源名称对应的颜色 if let resourceName = try container.decodeIfPresent(String.self, forKey: .resourceName) { self.init(resourceName) } // 其次解码RGB数值颜色 else if let rgb = try container.decodeIfPresent((Double, Double, Double, Double).self, forKey: .rgbComponents) { self.init(red: rgb.0, green: rgb.1, blue: rgb.2, opacity: rgb.3) } // 最后处理系统预定义颜色 else if let systemName = try container.decodeIfPresent(String.self, forKey: .systemColorName) { switch systemName { case "red": self = .red case "blue": self = .blue case "green": self = .green case "yellow": self = .yellow case "orange": self = .orange // 根据你的需求添加更多系统颜色 default: self = .clear } } else { throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "无法解析该类型的Color")) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) // 尝试识别资源颜色(通过解析description,注意:该方式依赖Apple的格式实现,若后续格式变更需调整) let colorDescription = self.description if colorDescription.contains("NamedColor") { let nameComponents = colorDescription.components(separatedBy: "\"") guard nameComponents.count >= 2 else { // 无法提取名称时 fallback 到RGB编码 try encodeAsRGB(to: &container) return } try container.encode(nameComponents[1], forKey: .resourceName) return } // 识别系统颜色 switch self { case .red: try container.encode("red", forKey: .systemColorName) case .blue: try container.encode("blue", forKey: .systemColorName) case .green: try container.encode("green", forKey: .systemColorName) case .yellow: try container.encode("yellow", forKey: .systemColorName) case .orange: try container.encode("orange", forKey: .systemColorName) // 按需添加更多系统颜色 default: // 其他情况按RGB编码 try encodeAsRGB(to: &container) } } // 辅助方法:将Color转为RGB组件编码 private func encodeAsRGB(to container: inout KeyedEncodingContainer<CodingKeys>) throws { #if os(iOS) || os(tvOS) || os(watchOS) let uiColor = UIColor(self) var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) try container.encode((Double(red), Double(green), Double(blue), Double(alpha)), forKey: .rgbComponents) #elseif os(macOS) let nsColor = NSColor(self) guard let rgbColor = nsColor.usingColorSpace(.sRGB) else { throw EncodingError.invalidValue(self, .init(codingPath: container.codingPath, debugDescription: "无法转换为sRGB颜色空间")) } try container.encode((rgbColor.redComponent, rgbColor.greenComponent, rgbColor.blueComponent, rgbColor.alphaComponent), forKey: .rgbComponents) #endif } }
更稳定的替代方案
上面通过解析description识别资源颜色的方式存在一定风险(Apple可能修改描述格式)。如果需要更稳定的实现,可以自定义一个CodableColor结构体来封装不同类型的颜色:
enum CodableColor: Codable, Hashable { case resource(name: String) case rgb(red: Double, green: Double, blue: Double, opacity: Double) case system(name: String) // 转换为SwiftUI Color var color: Color { switch self { case .resource(let name): return Color(name) case .rgb(let red, let green, let blue, let opacity): return Color(red: red, green: green, blue: blue, opacity: opacity) case .system(let name): switch name { case "red": return .red case "blue": return .blue case "green": return .green default: return .clear } } } } // 在ContentState中使用CodableColor替代Color struct ContentState: Codable, Hashable { var elapsedTime: Int var remainingTime: Int var meetingDuration: Double var mainColor: CodableColor } // 在视图中使用时转换为Color .background(context.state.mainColor.color)
注意事项
- 确保自定义颜色资源在WidgetExtension目标的资源目录中也存在,否则Live Activity无法加载该颜色。
- Live Activity的
ContentState必须完全可安全编码解码,任何无效的对象都会导致Activity无法渲染。
内容的提问来源于stack exchange,提问作者LucasC
相关产品推荐
相关产品推荐

