我正在开发一个带有小部件的新 iOS 应用程序。用 SwiftUI 编写。
我的大部分代码在 Widget 目标和 App 目标之间共享,但我想在两个目标之间进行一些小的样式更改。
有没有办法检查代码是在小部件中还是在应用程序中执行?
我正在尝试了解 Apple 的Widget background network requests文档。
要处理网络请求的结果,请对小部件的配置使用 onBackgroundURLSessionEvents(matching:_:) 修饰符,然后执行以下操作:
- 存储对
completion参数的引用。在处理完所有网络事件后调用完成处理程序。- 使用该
identifier参数查找URLSession您在发起后台请求时使用的对象。如果您的小部件扩展已终止,请使用标识符重新创建URLSession.
关于第一个要点,completion这里指的是什么参数?它是func的completion参数onBackgroundURLSessionEvents(matching:_:)还是可能是IntentTimelineProvider's的完成处理程序getTimeline(for:in:completion:)?如果是前者,是否意味着在有多个事件时存储多个完成处理程序?调用该完成处理程序的目的是什么?
对于第二个要点,您如何使用identifier重新创建URLSession? 在getTimeline(for:in:completion:)重新创建会话时,您是否应该将配置保存到磁盘以供稍后访问?
要在网络请求完成后刷新小部件的时间线,请从委托的 urlSessionDidFinishEvents 实现中调用WidgetCenter方法。
在这一部分,他们似乎指的是调用方法WidgetCenter.shared.reloadTimelines(ofKind:)。但是,这不会触发小部件的所有实例的刷新吗?还是系统知道只刷新调用它的那个?
我想使用自定义颜色为我的小部件创建渐变颜色。而且我只使用两种颜色时出现问题,结果没有应用一种颜色,而是背景变成绿色!
struct WeatherWidgetMediumView: View {
var gradient: LinearGradient {
LinearGradient(
gradient: Gradient(
colors:
[
Color(red: 96.0/255.0, green: 171.0/255.0, blue: 239.0/255.0),
Color(red: 163.0/255.0, green: 230.0/255.0, blue: 244.0/255.0)
]),
startPoint: .top,
endPoint: .bottom)
}
var body: some View {
GeometryReader { geo in
HStack(alignment: .center) {
Divider().background(Color.black).padding(.vertical, 16.0).opacity(0.1)
}
}
.background(gradient)
}
}
Run Code Online (Sandbox Code Playgroud)
但是如果我再添加一种颜色,它看起来很棒。
struct WeatherWidgetMediumView: View {
let weather: Weather
var gradient: LinearGradient {
LinearGradient(
gradient: Gradient(
colors:
[
Color(red: 96.0/255.0, green: 171.0/255.0, blue: 239.0/255.0),
Color(red: 96.0/255.0, green: 171.0/255.0, blue: 239.0/255.0), …Run Code Online (Sandbox Code Playgroud) 我找不到在 Widget 中实现某种 ProgressBar 的解决方案。我明白了,例如,如果类型为 .timer,则应该更改 Text 组件。我看到默认的小部件时钟,带有漂亮的移动箭头动画。但是我可以在小部件中实现自定义动画吗?
我正在编写一个 HomeKit 应用程序,它可以成功显示应用程序内支持的配件的实时数据。我可以读取单个值 ( HMCharacteristic.readValue) 或使用通知来保持更新 ( HMCharacteristic.enableNotification)。
现在我想实现在用户主屏幕上显示这些数据的小部件。这包括四个步骤:
HMHomeManager并使用户能够选择其中一个以显示在小部件上。IntentTimelineProvider的getTimeline函数内部,我可以再次使用HMHomeManager来检索我想要在小部件上显示的附件(基于存储在 的参数 - 意图中的附件的 UUID getTimeline)configuration。getTimeline功能内,我可以选择显示附件小部件所需的服务和特征HMHomeManager。到目前为止,一切正常。
HMCharacteristic.readValue,回调包含一个错误,说明错误域=HMErrorDomain 代码=80“缺少 API 权利。”
Widget 的 Info.plist 包含“隐私 - HomeKit 使用说明”字段,并且 Target 具有 HomeKit 功能。
经过一番研究,我得出了以下理论:显然整个 WidgetKit API 在后台运行我的代码。而且 HomeKit 似乎不允许从后台上下文进行访问。好吧,它确实允许访问 Homes/Services/Characteristics,但它不允许读取或写入 Characteristics(我想确保应用程序开发人员使用 HomeKit 自动化,并且不要尝试实现由某些后台进程控制的自定义自动化他们的应用程序在 iPhone 上运行)。
我的(简化的)getTimeline代码:
func getTimeline(for configuration: SelectAccessoryIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> …Run Code Online (Sandbox Code Playgroud) 我正在HealthKit我的小部件中使用数据。如果手机被锁定,则无法获取HealthKit数据,除非手机解锁。但是,即使手机被锁定,我的小部件时间线也会尝试更新。
是否有可能以某种方式返回空完成,因此它将保持当前小部件数据不变?
这是我的代码:
struct Provider: IntentTimelineProvider {
private let healthKitService = HealthKitService()
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let refreshDate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
healthKitService.getHeartRate() { data, error in
//Create an empty entry
var entry = SimpleEntry(date: currentDate, configuration: ConfigurationIntent(), data: nil)
//If no errors, set data
if(error == nil) {
entry.data = data
} else {
print(error) //this runs when a …Run Code Online (Sandbox Code Playgroud) 我需要创建无限数量的小部件,具有相同的布局,但具有不同的行为和内容。
当用户添加许多相同类型的小部件时,它们kind将是相同的。我需要其他东西来识别小部件,以便设置彼此不同的行为。他们有身份证吗?
我们如何将锁屏小部件添加到现有的小部件包中并仍然支持 iOS 15?:thinking_face: 例如,这不会编译
struct SecondExtraBundle: WidgetBundle {
@WidgetBundleBuilder
var body: some Widget {
DailyHeartRatesWidget()
if #available(iOSApplicationExtension 16.0, *) {
LockScreenRecoveryScoreWidget()//Requires iOS 16?
} else {
// Fallback on earlier versions
}
}
}
Run Code Online (Sandbox Code Playgroud) 我们正在将ClockKit复杂功能迁移到WidgetKit手表应用程序 (watchOS 9+) 中。\n迁移进展顺利,UI 部分工作正常。然而,我们遇到了小部件在手表应用程序请求时没有更新的问题。\n我相信我们错过了一些非常简单和基本的东西,但到目前为止还找不到确切的东西。非常欢迎建议和提示!\xe2\x80\x8d\xe2\x99\x82\xef\xb8\x8f
我们的实施细节:
\nWatchConnectivity使用WCSession.default.transferCurrentComplicationUserInfo(_:). 根据文档,此方法应用于传输与复杂功能相关的数据,因为即使手表应用程序位于后台或根本未打开,它也会唤醒手表应用程序。UserDefaults与托管 WidgetKit 复杂功能的 Watch Widget 扩展共享的位置App Group。WidgetCenter.shared.reloadAllTimelines()。根据文档,它重新加载属于包含应用程序的所有已配置小部件的时间线,因此这似乎是重新加载 WidgetKit 复杂性的适当方法。UserDefaults,并使用它来为要渲染的 widget 视图提供更新的数据snapshot。我们相信我们的实现逻辑是正确的,但由于某种原因它不起作用。打开手表应用程序时,小部件有时会更新,但并非总是如此。强制更新小部件的最明确方法是切换到不同的表盘,这确认小部件时间线提供程序可以访问正确更新的数据。
\nPS我们知道小部件的每日重新加载预算,因此我们很少使用小部件重新加载触发器。无论如何,根据文档,在调试模式下重新加载预算无效,但即使在调试模式下小部件也不会重新加载。
\n最低可重现示例应用程序:\n https://github.com/SergejLogis/wkcomplications
\n谢谢你!
\n我试图找出为什么我的小部件没有重新加载。我想entries从内部打印数组func getTimeline到控制台。
但是打印语句不会出现在控制台中。
如何让打印语句出现在控制台中?