iOS 小组件
基本知识
时间轴
小组件通过AppIntentTimelineProvider进行 UI 刷新
struct Provider: AppIntentTimelineProvider {func placeholder(in context: Context) -> SimpleEntry {// 添加占位的(选择添加的时候使用)// todo}func snapshot(for configuration: WidgetCfgIntent, in context: Context) async -> SimpleEntry {// 添加预览的时候会调用, 建议这里进行和timeline方法一样的数据处理。// todo}func timeline(for configuration: WidgetCfgIntent, in context: Context) async -> Timeline<SimpleEntry> {// 返回每个时间点的数据。var entries: [SimpleEntry] = []// 按需添加自己的时间片段// entries.append(entry)let nextTimeMin = 20let nextUpDate = Calendar.current.date(byAdding: .minute, value:nextTimeMin, to: .now) ?? Date(timeIntervalSince1970: Date().timeIntervalSince1970 + Double(nextTimeMin*60)) // 16-50分钟刷新一次, 不能设置时间太小,太小会被系统忽略return Timeline(entries: entries, policy: .after(nextUpDate))}// 推荐配置。func recommendations() -> [AppIntentRecommendation<WidgetCfgIntent>] {// todo}}
数据共享
与其他扩展一样,小组件可以通过Group 的UserDefault 共享数据。 还可以通过 SwiftData 共享数据。
交互
widgetURL:所有区域
Link: 不同元素
具有交互性的 Tog 或 Button(iOS 16):需要基于 AppIntent (与系统通用的 Intent 共用)参考https://developer.apple.com/documentation/widgetkit/adding-interactivity-to-widgets-and-live-activities
AppIntet 理解
Intent: 提供的一个小功能(通过入参、实现某个功能、返回什么结果),比如打开什么、记录什么
Entity:用来表示 App的内容,提供给 Intent 使用(对这个小功能的抽象数据)。
AppShortcut:用来包装 Intent,使之能被系统或者调用方发现。
APPIntent 如何返回数据
func perform() async throws -> some IntentResult & ReturnsValue<Int> {// 如果需要返回其他类型,在 Int 处替换。 let returnValue: Int = 1 //在这里添加你要执行的代码 return .result(value: returnValue) }
APPIntent 的参数通常用@Parameter标记, 支持基本常用值, 也可以继承AppEntity或AppEnum–枚举进行自定义类型。
实现了 AppIntent 的功能默认自动提供给快捷指令使用。注意多语言和相关测试
小组件更新
主 APP 内:通过WidgetCenter刷新
// 通过 kind 刷新某个类型小组件
WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.gamestatus")
// 刷新所有小组件
WidgetCenter.shared.reloadAllTimelines()
系统刷新:
- 通过时间轴刷新(15~50分钟一次,设置时间小了,系统也会忽略)
- 执行交互型 Intent 后会触发刷新
支持小组件类型
struct DemoWidget: Widget {var body: some WidgetConfiguration {// AppIntentConfiguration 为可以配置的小组件AppIntentConfiguration(kind: kind, intent: WidgetCfgIntent.self, provider: Provider()) { entry inSwiftUIWidgetEntryView(entry: entry).widgetBackground(Color.container) // 添加自定义背景色(扩展方法),注意小组件最底层始终有一个底色。 无法做到像 Apple Home 那样的半透明背景效果(据说是只有系统才能用的 API)}.configurationDisplayName("展示名字").description("描述").supportedFamilies(supportFamilies) // 支持小组件类型。.disableContentMarginsIfNeeded() // 忽略边距(扩展方法)}private var supportFamilies:[WidgetFamily] {return [.systemSmall, .systemMedium, .systemLarge]}private var kind: String {return "com.xxxx.Widget"}
}
小组件配置
通过继承WidgetConfigurationIntent 实现。探索 App Intents 的功能更新 – 小专栏
一组一组配置
相关接口:https://developer.apple.com/documentation/appintents/intentitemcollection
struct DeviceDefaultProvider:DynamicOptionsProvider
// 注意这里需要返回 IntentItemCollection, 即分组显示
func results() async throws -> IntentItemCollection<DeviceEntity> {
// return ItemCollection(promptLabel: "----collection") {
// ItemSection("title1", subtitle: "subtitle1", image: DisplayRepresentation.Image(named: "pic_xxxx")) {
// DeviceEntity(deviceID: "111", name: "device111")
// DeviceEntity(deviceID: "112", name: "device112")
// }
// ItemSection("title2", subtitle: "subtitle2", image: DisplayRepresentation.Image(named: "pic_em0xxxx")) {
// DeviceEntity(deviceID: "211", name: "device211")
// DeviceEntity(deviceID: "212", name: "device212")
// }
// }
}
效果图
小组件扩展
import WidgetKit
import SwiftUIextension View {/// 统一设置备件@ViewBuilderfunc widgetBackground(_ backgroundView: some View) -> some View {if Bundle.main.bundlePath.hasSuffix(".appex"){ // 小组件才生效if #available(iOS 17.0, *) {containerBackground(for: .widget) {backgroundView}} else {background(backgroundView)}} else {background(backgroundView)}}
}extension WidgetConfiguration {func disableContentMarginsIfNeeded() -> some WidgetConfiguration {if #available(iOSApplicationExtension 17.0, *) {// 禁用边距return self.contentMarginsDisabled()} else {return self}}
}
小组件刷新失败
entities 查询返回数据空
背景:我在主 APP 修改了小组件显示数据源, 同时调用了WidgetCenter.shared.reloadAllTimelines刷新,但是回到小组件,数据依然没有变化,通过调试,控制台打印如下:
Error getting AppIntent from LNAction: AppIntent has missing parameter value for 'xxxx'. You may need to set a default value in the initializer of your @Parameter, or using the default method on your Query.
No AppIntent in timeline(for:with:)
上面这种情况属于 APP 内主动刷新失效, 但是系统的时间轴刷新有效。
通过反复测试发现,在桌面小组件自定义配置后才发生。
我的配置参数是基于 AppEntity 实现的自定义类型。
发现每次在调用 EntityQuery 的entities(for)方法,内部返回空数组,都会打印上面的错误。
struct DeviceEntityQuery: EntityQuery, Sendable {// 通过 ID 查询的会调用, (比如通过配置匹配,提供数据源等)func entities(for identifiers: [DeviceEntity.ID]) async throws -> [DeviceEntity] {//具体逻辑:通过 ID 过滤数据。 如果没匹配到,就返回空。}
}
APP主动刷新小组件 -> 通过自定义配置在 EntityQuery 方法中查询 -> 查询到,触发刷新小组件的生命周期方法,(没查询,比如返回空数组,则不会刷新小组件生命周期方法)
结论:在entities(for)的返回结果时,不要返回空数组,否则可能无法刷新。
解决方法:如果没有匹配到,不返回空数组,构建对应的 Entity 返回。
其他问题
widgetURL配置
现象:通过 WidgtURL装饰器配置的 URL 跳转异常。
原因:我在最底层配置得了 WidgetURL, 在子视图也配置了 Widget,导致跳转异常. 根据官网文档解释,如果有多层View 使用了 WidgetURL, 状态和跳转将是不可预料的(在 iOS18.0上,多数情况下都响应最底层的 WidgetURL)
解决方案:通过 Link 或者 Button(AppIntent 交互)处理连接。
Link(destination: URL(string: "xxxxx" ) {
// your view
}
Summery 怎么多语言化
使用新的多语言文件 xcstrings
使用占位模式
Get the daylight duration on ${date} in ${location}
使用示例
Summary("Switch \(\.$device) \(\.$isOn)")// 可选, table: "Localizable1")
注意:变量名要一致
Next
将 App 控制扩展到系统级别: 将功能扩展到系统控制,通过类型小组件 AppIntent 的方式。
资料参考
Apple 官方指导:https://developer.apple.com/cn/documentation/widgetkit/
iOS 小组件系列教程:https://juejin.cn/post/7297513663435210771?searchId=2024082914404396F94C65488FE5528F7E
WidgetExamples – github
SwiftUI 控件 Demo – github
SwiftUI 细节学习参考 --肘子的记事本: 各种SwiftUI 控件、布局理解。
相关文章:
iOS 小组件
基本知识 时间轴 小组件通过AppIntentTimelineProvider进行 UI 刷新 struct Provider: AppIntentTimelineProvider {func placeholder(in context: Context) -> SimpleEntry {// 添加占位的(选择添加的时候使用)// todo}func snapshot(for configu…...
【2.使用VBA自动填充Excel工作表】
目录 前言什么是VBA如何使用Excel中的VBA简单基础入门控制台输出信息定义过程(功能)定义变量常用的数据类型Set循环For To 我的需求开发过程效果演示文件情况测试填充源文件测试填充目标文件 全部完整的代码sheet1中的代码,对应A公司工作表Us…...
算法记录——链表
2.链表 2.1判断是否是回文链表 1.方法一:利用栈反转链表 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode…...
EasyExcel实现百万数据批量导出
当数据量比较大时,例如数据量达到百万级,传统的一次读取到内存中在写入excel文件的方法便不再适用了,可能会导致内存溢出;而且一次性将数据写入一张sheet工作表也不太好。 但我们可以选择数据分片的方式批量写入多个工作表。 测试…...
兆易GD32E508的SHRTIM配置 主从定时器 产生2对相位可调互补PWM 带死区
如有技术问题及技术需求请加作者微信! GD32E5系列MCU是基于Arm Cortex-M33处理器的32位通用微控制器。Cortex-M33处理器基于Armv8架构,处理器主频最高可达180MHz,支持强大的可扩展指令集,包括通用数据处理I/O控制任务、增强的数据处理位域操作、DSP和浮点运算器(FPU)。 GD…...
数据归组工具
利用C#将数据 [ {"name":"A","fzh":1}, {"name":"A","fzh":2}, {"name":"A","fzh":3}, {"name":"B","fzh":4}, {"name":"B",&…...
JavaScript 中的闭包的形成及使用场景
JavaScript 中的闭包 闭包(Closure) 是 JavaScript 中一个非常重要且独特的概念,它指的是 函数能够记住并访问其词法作用域内的变量,即使这个函数在其词法作用域之外执行。 通俗地说,闭包是 一个函数可以“记住”它在…...
后端返回内容有换行标识,前端如何识别换行
<br/>的话 用 v-html \n 可以用css样式 white-space: pre-wrap 后端返回结果 前端...
服务器被挂马,导致网站首页被更改怎么解决
当服务器被挂马并导致网站首页被篡改时,说明服务器或网站的安全性遭到破坏。为了修复并防止未来的攻击,你可以按照以下步骤进行操作: 1. 立即下线网站 目的:防止恶意软件进一步传播,保护用户数据和防止攻击者继续对网…...
Android 利用OSMdroid开发GIS
1、地址 Github地址:https://gitee.com/mirrors/osmdroid Git地址: GitCode - 全球开发者的开源社区,开源代码托管平台 Git下载包地址:Releases osmdroid/osmdroid GitHub 新建项目 osmdroid在线: (1)…...
一文上手skywalking【上】
一、skywalking预览 1.1 skywalking 概述 Apache SkyWalking, 适用于分布式系统的应用程序性能监控工具,专为微服务、云原生和基于容器的 (Kubernetes) 架构而设计。官方地址: https://skywalking.apache.org/ 适用于分布式系统的应用程…...
【JavaScript】JQuery基础知识及应用
一、JQuery的导入方法 https://editor.csdn.net/md/?articleId132214798 二、JQuery介绍 JQuery(JQ):JS的一个类库(方法库:包含了大量的、有助于项目开发的属性和方法) 第一代版本1.xx.xx: 1.11.3 兼容所有浏览器的࿰…...
初始爬虫9
1.元素定位后的操作 “find_element“仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法”。下面列出了两个方法: 获取文本 element.text 通过定位获取的标签对象的 text 属性,获取文本内容 获取属性…...
从细胞到临床:表观组学分析技术在精准医疗中的角色
中国科学院等科研院所的顶尖人才发起,专注于多组学、互作组、生物医学等领域的研究与服务。在Nature等国际知名期刊发表多篇论文,提供实验整体打包、免费SCI论文润色等四大优势服务。在表观组学分析技术方面,提供DAP-seq、ATAC-seq、H3K4me3 …...
带你0到1之QT编程:二十、QT与MySQL喜结连理,构建数据库应用开发
此为QT编程的第二十谈!关注我,带你快速学习QT编程的学习路线! 每一篇的技术点都是很很重要!很重要!很重要!但不冗余! 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点! …...
梯度下降法及其性能评估
梯度下降法 梯度下降法是一种一阶迭代优化算法,用于寻找函数的局部最小值。在机器学习中,它通常用来最小化损失函数(也称为成本函数或误差函数),以提高模型对数据的拟合程度。梯度下降法的基本思想是沿着目标函数当前…...
906. 超级回文数
1. 题目 906. 超级回文数 2. 解题思路 题目意思很简单,在给定范围中找到所有满足,它本身是回文,且它的平方也是回文的数字个数。 这题需要注意题目给定的范围,后面很有用: 因为回文范围是有限的,那么我…...
代码随想录算法训练营||二叉树
前/中/后序遍历 递归方式 参考文章 题目 思路:其实递归方式的前中后序遍历的方式都差不多,区别是在父节点的遍历时间。 前序代码 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result new…...
线上报名小程序怎么做
在这个数字化、智能化的时代,信息技术的发展正以前所未有的速度改变着我们的生活。无论是学习、工作还是娱乐,互联网都成为了我们不可或缺的一部分。而在线上报名这一领域,小程序的出现更是为广大用户带来了前所未有的便捷与高效。今天&#…...
【测试岗】手撕代码 - 零钱兑换
322. 零钱兑换 题目描述 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
