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

如何在iOS17以下版本使用disfavoredLocations并复用Widget body?

兼容iOS15/16的Widget待机位置适配方案

要实现「iOS17+支持.systemSmall用于待机位置但隐藏主屏幕入口,同时兼容旧版本并复用Widget配置」的需求,核心是把基础Widget配置抽离复用,并通过版本标记让系统自动加载对应Widget,避免WidgetBundle的条件分支类型问题。具体步骤如下:

1. 抽离可复用的基础配置

把原Widget的核心配置(比如StaticConfiguration、通用修饰符)抽成独立函数,让新旧版本的Widget都能调用,避免重复代码:

private func baseWidgetConfiguration() -> some WidgetConfiguration {
    StaticConfiguration(kind: "MyWidget", provider: MyWidgetProvider()) { entry in
        MyWidgetEntryView(entry: entry)
    }
    .configurationDisplayName("我的Widget")
    .description("自定义Widget描述")
    // 保留你原有的其他修饰符(比如.xxx)
}

2. 定义旧版本专用Widget(iOS15/16)

这部分完全保留原有逻辑,只支持.systemLarge:

// 仅在iOS15-16加载
@available(iOS, introduced: 15.0, deprecated: 17.0)
struct MyWidget: Widget {
    var body: some WidgetConfiguration {
        baseWidgetConfiguration()
            .supportedFamilies([.systemLarge])
    }
}

3. 定义iOS17+专用Widget

在这个版本里添加.systemSmall支持,并设置disfavoredLocations隐藏主屏幕入口:

// 仅在iOS17及以上加载
@available(iOS 17.0, *)
struct MyWidgetiOS17: Widget {
    var body: some WidgetConfiguration {
        baseWidgetConfiguration()
            .supportedFamilies([.systemLarge, .systemSmall])
            .disfavoredLocations([.homeScreen], for: [.systemSmall])
    }
}

4. 配置WidgetBundle

直接把两个Widget都加入Bundle,系统会根据设备iOS版本自动筛选加载:

@main
struct WidgetsBundle: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        MyWidget()
        MyWidgetiOS17()
    }
}

为什么之前的方案失败?

你之前用if #available在WidgetBundle的body里做分支,会导致旧版本iOS的类型推断错误——WidgetBundle的body需要明确的Widget类型集合,而条件分支会让编译器无法确定返回类型。通过给Widget本身添加@available标记,让系统自动处理版本筛选,就能绕过这个问题。

内容的提问来源于stack exchange,提问作者Robert Dresler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:35:26