大多数浏览器和
Developer App 均支持流媒体播放。
-
“专注”过滤器简介
探索如何基于当前由其他人启用的“专注”对 App 行为进行自定义。我们将向您介绍如何使用 App 意图来定义您 App 的“专注”过滤器,在系统中针对更改执行操作,并且以不同的方式呈现您的 App 视图。我们还将讨论您可以如何过滤通知和更新角标计数。为能更好地理解此讲座,我们建议您先观看 WWDC22 的“深入了解 App 意图”。
资源
相关视频
WWDC22
-
下载
♪ 柔和乐器演奏的嘻哈音乐 ♪ ♪ 大家好 我是 iOS 系统 体验团队的工程师 Teja 本次讲座 我们会来看看专注模式过滤器 我们在 iOS 15 macOS Monterey 和 watchOS 8 中引入了专注模式 用户可以通过 设置系统在一段时间内的行为 来帮助自己专注于当下最重要的事 要启用专注模式 只需进入控制中心 选择默认或是自定义的专注模式即可 当专注模式启用时 用户可以自定义通知行为 比如 在工作模式下 您也许会 只允许来自同事的通知 或者只允许来自某些与工作相关的 特定 App 的通知 每种专注模式的系统行为 都可以在设置中调整 iOS 16 和 macOS Ventura 引入了专注模式过滤器 来增强专注模式 首先 我会为您介绍专注模式过滤器 以及它的行为模式 其次 要如何在您的 App 中 定义专注模式过滤器 然后 我也介绍 专注模式的过滤器要怎么实现 最后 您的 App 可以怎样 把额外的上下文返回给系统 专注模式过滤器可以让用户 根据当前启用的 专注模式自定 App 的行为模式 一些系统 App 已经适配了专注模式过滤器 可以用做范例 日历 App 允许用户 根据启用的专注模式 设定默认显示的日历 通常状态下 我的日历是这样的 如您所见 在这里 个人和工作上的日程是混在一起的 我可以给日历 设置一个专注模式过滤器 让它在个人模式下 只显示我的个人日程 设置好专注模式过滤器后 我的日历就变成了这样 日历 App 会显示 这是经过专注模式过滤的 还提供了开关这个过滤器的选项 现在我终于不会在个人时间 被这些工作日程打扰了 Mail App 的收件箱 可以根据过滤器 在专注模式下只显示相关的邮箱 还可以过滤 Mail 通知 使其只突出显示相关的通知 也就是说我可以让 Mail 在工作模式下只推送 工作相关的邮件通知 这样个人邮件通知就不会打扰到我 为您的 App 加入专注模式过滤器的好处有很多 也许您的 App 管理着多个账户 一个账户会需要 关联一个专注模式 有大量数据的 App 也许需要为了专注模式 过滤内容 如果您想帮助用户 在专注状态下免受打扰 您可以通过减少标记 App 提醒以及通知的数量 来突出专注模式下最重要的信息 在外观上 也许您的 App 可以根据启用的专注模式 展示特定的主题或布局 从本质上讲 只要您的 App 可以根据不同情况 展示不同内容 您就可以利用专注模式过滤器 改善用户体验 我来说明一下 专注模式过滤器的运作方式 您的 App 定义了 用户可以根据专注模式自定哪些内容 这会通过 AppIntent 实现 系统会暴露出 可根据专注模式设置的部分 您的 AppIntent 定义的属性可通过 UI 设置 它会在专注模式设置中 作为过滤器显示出来 用户可以进入 专注模式设置 设置过滤器 来设定您的 App 的 运作方式 现在 让我来讲解 如何把专注模式过滤器 加入您的代码库中 定义专注模式过滤器分为几步 首先是启用 SetFocusFilterIntent 这会向系统表明您的 App 愿意根据专注模式提供自定设置 第二步是定义 App 的参数 即用户可以在您的 App 中 调节哪些设置 最后一步是设置显示内容 这样您的过滤器才会在系统设置中 显示正确的内容 用户才能明白自己设置了什么 用代码举例 首先您需要 import AppIntents 定义一个实施了 SetFocusFilterIntent 的 struct 这就是您的专注模式过滤器 设置标题和描述 让用户知道您的专注模式有什么效果 过滤器在设置中以网格状展示 在专注模式过滤器设置完成之前 这就是用户会看到的界面 这里就是您的 App 的图标 主要文本是 App 名 次要文本则与您在过滤器中 设置的标题对应 当用户点击配置您的过滤器时 会显示出同样的内容 这时 系统还会展示您提供的 描述字符串 以供参考 标题和描述字符串都是静态的 系统在安装您的 App 时 就读取了它们 定义您的专注模式过滤器时 您必须提供一系列修饰为参数的属性 用于指定用户可以自定的内容 指定参数时 必须为其命名 并确定数据类型 这些参数可以是标准数据类型 比如 Bool, string, float 等等 如果您希望设置某种 自定义的数据类型 您可以将其设为实体 这样您就可以 把它修饰为一个参数使用 要学习更多关于 实体和 App 意图的内容 请观看“详解 App 意图”讲座 定义专注模式过滤器时 您只需要指定 数据类型以及各参数名 应用于各专注模式的参数值 是由用户决定的 可以把参数标记为可选项 这样用户就不一定要设置它们 非可选项的参数必须有一个默认值 在代码中 指定一个参数 或可选参数的方法是:定义 您希望出现在过滤器中的变量类型 并将其修饰为一个参数 在这里 我创建了一个必选的 Bool 参数 代表我的专注模式 是否总是使用深色模式 我把它的默认值设置为否 我还创建了一个 可选的 string 参数 代表此专注模式下的用户状态 最后 我添加了一个可选的账户参数 这是我的 App 定义的一个实体 其包含了特定账户的信息 这三个参数都设置了标题 用于描述这些参数 会在设置中展示给用户 在专注模式设置中 用户设置您的 App 的 专注模式过滤器时 设置界面会以类似我刚才展示过的 网格的样子呈现 但这次 因为过滤器 已经设置好了 其内容会动态反映 之前设置的内容 这里仍然是您的 App 的图标 主要文本和次要文本 可以根据 FocusFilterIntent 中的 显示内容属性自定义 主要文本会显示出 设置好了的参数 比如选择账户 设置状态 等等 次要文本会显示出 设置好了的参数 比如工作账户或工作中 在我的代码中 我设置了 动态生成显示内容 因为账户和状态都是可选参数 它们只在用户设置之后 才会出现在动态主次文本中 由于 alwaysUseDarkMode 是一个必选参数 它会始终包含在主要和次要文本中 好了 现在您定义好了 专注模式过滤器 用户可以在专注模式设置中 为某个专注模式自定特定值了 但您的 App 怎么知道用户自定了什么呢? 您的 App 要如何适当更新自己? 它必须根据系统的变化采取行动 当专注模式发生了变化 系统认为 您的 App 有必要知道这个变化时 它会用 两种方式之一向您传达这个信息 如果 App 正在运行 而您已经部署了 FocusFilterIntent 它就会收到 perform 方法的调用 如果 App 没有运行 您可以部署 一个扩展 这样 如果您已经 在 FocusFilterIntent 中 部署了 perform 它就会在扩展中被调用 您的 App 和扩展 都可以调用 perform 所以并非每个 App 都需要扩展 一般来说 如果您的 App 只是 随着专注模式的改变更新界面外观 那只在 App 内 实现 perform 就足够了 如果您的 App 的 小组件、通知或标记 都需要随着专注模式改变 那您也许会需要部署一个扩展 基本上 如果您的 App 想要更新任何内部视图之外的东西 您就需要部署扩展了 在后面 我会用“您的 App”这个词 根据上下文不同 它可能说的是您的 App 也可能是您的扩展 要响应一个专注模式过滤器 请部署 perform 函数 访问设置中提供的 参数的填充值 依此更新您的 App 的外观与行为 当系统认为您的 App 需要响应专注模式的变化时 就会调用您的 perform 部署 当系统认为先前提供的值 不再有效时 也会调用 perform 这种情况下 您的过滤器参数 会被设置成默认值 当系统根据您的 App 的 过滤器调用 perform 时 所有参数会根据 设置中设定的值填满 要读取参数名的值 可以调用 self.“参数名” 这个示例中 在 perform 的最后 我让 App 根据我收到的数据更新 有时候 您也许会需要询问 当前的过滤器参数 在我的案例中 因为我的过滤器名叫 ExampleChatAppFocusFilter 我就要访问 ExampleChatAppFocusFilter.current
现在您的 App 可以根据专注模式过滤器行动了 接下来就是进一步提升用户体验 把您的 App 行为变化的额外上下文 返回给系统
通过提供额外上下文 您可以在 App 视图 之外影响其行为 比如 过滤通知信息 设定您的 App 的通知标记的数量 一个给系统提供信息的方法 是通过 AppContext 对象 这个对象可以作为 perform 函数结果的一部分返回 或者 您可以在专注模式过滤器中 随时返回 AppContext 并通过调用 invalidate 强制系统获取更新值 当有专注模式过滤器启用时 您的 App 也许有 额外的上下文 用来决定某个通知 是否应该打断用户 为了传递这个信息 您的 App 必须 在 AppContext 中 设置 filterPredicate 属性 这个“过滤器谓词”与一个 叫做 filterCriteria 的新字符串属性 共同工作在 UNNotification 上 如果通知的过滤器与过滤器谓词(Predicate) 不符合 该通知就会被静音 要在 FocusFilterIntent 中 设置过滤器谓词 请把它加入您的 App 上下文中 假如一台设备开启了个人专注模式 用户在设置中只选中了 个人账户 在这种情况下 我把过滤器谓词 设置成个人账户的标识符 如果收到的通知不是来自个人账户 它就不会打断用户 这里 当我设置这个通知时 我把 filterCriteria 设置成了工作账户的标识符 因为我知道这个通知 是要发送给工作账户的 这个通知应该会被静音 因为它的账户标识符与我刚刚设置的 谓词不符 它只和个人账户的标识符相符 这是一个本地通知的示例 但远程通知也可以通过 JSON 载荷 来设置过滤器 另一个给系统提供 额外上下文的方法是 更新您的 App 的标记数量 以反映当前启用的 专注模式下什么最重要 这样可以防止您的用户分心 在 UserNotifications 中 有一个新的 API 为此设计 在 UNUserNotificationCenter 上 您只需用一个代表新标记值的 无符号整数 调用 setBadgeCount 即可 现在 您已经学会如何提供上下文 以过滤通知 或是设置标记数量了 记住 这个功能的目标是为了 在用户需要专注时 展示最有用的信息 有时候 这需要尽量减少展示不相关的内容 以防止用户在启用专注模式时分心 接下来 请您思考一下 您的 App 的哪些部分 可以从专注模式过滤器中受益 确定哪些属性可以配置 设置好您的 App 和扩展来处理这些 然后更进一步 看看您是否需要提供额外上下文 这就是专注模式过滤器! 感谢您参加这次讲座 祝您愉快度过 接下来的 WWDC 时光 ♪
-
-
4:57 - Implementing SetFocusFilterIntent
// Implementing SetFocusFilterIntent import AppIntents struct ExampleChatAppFocusFilter: SetFocusFilterIntent { static var title: LocalizedStringResource = "Set account, status & look" static var description: LocalizedStringResource? = """ Select an account, set your status, and configure the look of Example Chat App. """ }
-
7:02 - Defining your Parameters & Entities
// Defining your Parameters & Entities import AppIntents struct ExampleChatAppFocusFilter: SetFocusFilterIntent { @Parameter(title: "Use Dark Mode", default: false) var alwaysUseDarkMode: Bool @Parameter(title: "Status Message") var status: String? @Parameter(title: "Selected Account") var account: AccountEntity? // ... }
-
8:43 - Display Representation
// Display Representation struct ExampleChatAppFocusFilter: SetFocusFilterIntent { // ... var localizedDarkModeString: String { return self.alwaysUseDarkMode ? "Dark" : "Dynamic" } var displayRepresentation: DisplayRepresentation { var titleList: [LocalizedStringResource] = [], subtitleList: [String] = [] if let account = self.account { titleList.append("Account") subtitleList.append(account.displayName) } if let status = self.status { titleList.append("Status") subtitleList.append(status) } titleList.append("Look") subtitleList.append(self.localizedDarkModeString) let title = LocalizedStringResource("Set \(titleList, format: .list(type: .and))") let subtitle = LocalizedStringResource("\(subtitleList.formatted())") return DisplayRepresentation(title: title, subtitle: subtitle) } // ... }
-
11:24 - Implementing Perform on your Focus filter
// Implementing Perform on your Focus filter import AppIntents struct ExampleChatAppFocusFilter: SetFocusFilterIntent { // ... func perform() async throws -> some IntentResult { let myData = AppData( alwaysUseDarkMode: self.alwaysUseDarkMode, status: self.status, account: self.account ) myModel.shared.updateAppWithData(myData) return .result() } // ... }
-
11:47 - Calling Current
// Calling Current import AppIntents func updateCurrentFilter() async throws { do { let currentFilter = try await ExampleChatAppFocusFilter.current let myData = AppData( myRequiredBoolValue: currentFilter.myRequiredBoolValue, myOptionalStringValue: currentFilter.myOptionalStringValue, myOptionalAppEnum: currentFilter.myOptionalAppEnum, myAppEntity: currentFilter.myAppEntity ) myModel.shared.updateAppWithData(myData) } catch let error { print("Error loading current filter: \(error.localizedDescription)") throw error } }
-
13:27 - Set a filterPredicate
// Set filterPredicate on an App context import AppIntents struct ExampleChatAppFocusFilter: SetFocusFilterIntent { var appContext: FocusFilterAppContext { let allowedAccountList = [account.identifier] let predicate = NSPredicate(format: "SELF IN %@", allowedAccountList) return FocusFilterAppContext(notificationFilterPredicate: predicate) } }
-
13:53 - Pass filterCriteria on UNNotificationContent
// Pass filterCriteria on UNNotificationContent let content = UNMutableNotificationContent() content.title = "Curt Rothert" content.subtitle = "Slide Feedback" content.body = "The run through today was great. I had few comments about slide 22 and 28." content.filterCriteria = "work-account-identifier"
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。