ios 小组件和数据共享
创建主工程就不必讲了
1 创建小组件
创建子工程 [new Target ] 选择 [ Widger Extension]

小组件入口是WidgetBundle文件,可以进行多个小组件的调试

TestWidget2文件是主要操作,小组件使用swiftUI布局,使用 AppIntent进行事件处理,TestDataUserDefalut 用的userdefault 和主程序数据同步,下面详细讲解
//
// TestWidget2.swift
// TestSwift6Demo
//
// Created by ITHPNB04296 on 11/3/25.
//import WidgetKit
import SwiftUI
import AppIntentsstruct TestWidget2:Widget{let kind:String = "TestWidget2"var body: some WidgetConfiguration{StaticConfiguration(kind: kind, provider: MyWidget2Provider()) {entry inTestWidget2View(entry: entry ,ganmeStatus: entry.state).containerBackground(for: ContainerBackgroundPlacement.widget) {//背景色Color.yellow}}.configurationDisplayName("TestWidget2").description("show Testwidget2").supportedFamilies([.systemMedium])}}struct TestWidget2View:View {var entry: MyWidget2Provider.Entry(\.widgetFamily) var family:WidgetFamilyvar ganmeStatus:Test2State
// var selectedCharacter:CharacterDetailvar body: some View {VStack{Text("\(ganmeStatus.date.description)")Button("\(ganmeStatus.state)") {print("点击按钮1 直接就跳转到主APP了")}if entry.running{createRunningView()}else{createStaticView()}}}func createRunningView()->some View{//点击一次更新了一次return VStack{Button("点击按钮2", intent: Test2Intent())//该Text 无法设置停止时间
// Text(entry.date, style: Text.DateStyle.timer)
// .font(Font.system(size: 15.0))
// .fontWeight(.bold)
// .multilineTextAlignment(.center)
// .contentTransition(.numericText(countsDown: entry.state.duration > 0))//新Text样式,可以设置停止时间Text(timerInterval: entry.daterange,pauseTime: entry.pauseTime,countsDown: entry.countsDown,showsHours: entry.showsHours)}}func createStaticView()->some View{return VStack{Button("点击按钮2", intent: Test2Intent())Text(entry.date, style: Text.DateStyle.date).font(Font.system(size: 15.0)).fontWeight(.bold).multilineTextAlignment(.center)//过渡动画 countsDown 参数用来控制是否向下滚动.contentTransition(.numericText(countsDown: entry.state.duration > 0))}}
}//添加按钮点击事件行为
struct Test2Intent:AppIntent{static var title: LocalizedStringResource = "XXX"//点击事件函数是异步的可以做一些耗时操作,比如网络请求等func perform() async throws -> some IntentResult {//也可以通过App group 和主程序共享数据//点击事件更新let isrunning = TestDataUserDefalut().get()TestDataUserDefalut().set(!isrunning)return .result()}
}struct Test2State{var state:Stringvar date:Date{return Date()}var duration:Int = 10}struct MyWidget2Entry:TimelineEntry{var date: Date//默认区间是0var daterange:ClosedRange<Date> = Date()...Date()//默认没有开启var running:Bool {//添加状态控制return TestDataUserDefalut().get()}/// The relevance of a widget’s content to the user.var relevance: TimelineEntryRelevance?//添加适配新的TimerText//停止时间var pauseTime: Date = Date()//倒计时var countsDown = falsevar showsHours = true//携带其他额外数据var state:Test2State
}struct MyWidget2Provider: TimelineProvider{//没有数据时候占位,仅初始化时候调用一次,数据没加载上来时候,添加占位数据func placeholder(in context: Context) -> MyWidget2Entry {return MyWidget2Entry(date: Date(), state: Test2State(state: "init"))}//生成预览照,给系统组件库使用func getSnapshot(in context: Context, completion: (MyWidget2Entry) -> Void) {let date = Date()let entry:MyWidget2Entryprint("getSnapshot")entry = MyWidget2Entry(date: date, state: Test2State(state:"perview"))completion(entry)}//实时更新时间线,每次点击按钮时候调用两次 ? 调用两次没理解func getTimeline(in context: Context, completion: (Timeline<MyWidget2Entry>) -> Void) {let date = Date()let endtime:Date = Calendar.current.date(byAdding: .minute, value: 10, to: date)!let entry = MyWidget2Entry(date: date, daterange: date...endtime,countsDown: true, state: Test2State(state:"start"))//下一次更新时候let nextUpdateDate = Calendar.current.date(byAdding: .second, value: 1, to: date)!//时间线,\/*atend -当时间线中的所有条目都已显示完毕后,才会重新加载时间线。固定时间点加载,比如天气never - 不会自动刷新小组件内容,只有主app主动去刷新数据after(Date) - 指定一个未来的日期和时间*/let timeline = Timeline(entries: [entry], policy: TimelineReloadPolicy.after(nextUpdateDate))print("时间线方法1更新了 ")completion(timeline)}}//更新共享数据
struct TestDataUserDefalut{func get()->Bool{let sharedDefaults = UserDefaults(suiteName: "group.testwidget1.demo")let isrunning = sharedDefaults?.value(forKey: "sharedRunning") as? Bool ?? falsereturn isrunning}func set(_ state:Bool){let sharedDefaults = UserDefaults(suiteName: "group.testwidget1.demo")sharedDefaults?.set(state, forKey: "sharedRunning")sharedDefaults?.synchronize()}
}
小组件和主工程进行数据同步,也就是进程间通信
配置 App Groups
1. 打开 Xcode,选择你的主 App 目标(Target)。
2. 在 Signing & Capabilities 中,点击 + Capability。
3. 搜索 App Groups 并添加。
4. 创建一个新的 App Group(如 group.com.yourcompany.shared)。
5. 在 Widget Extension / App Clips 目标中重复上述步骤,选择相同的 App Group。
我的demo使用plist文件也就是userdefault 同步数据当然也可以使用数据库同步数据,我看同事使用SwiftData(ios 17之后才能使用)同步数据 swiftData官方文档 ,我选择的appgroup 名字是 “group.testwidget1.demo”,这个不是包名,TestWidget2 里面的 TestDataUserDefalut 就是小程序同步数据代码,下面看一下主程序App同步代码,添加包括刷新通知等,讲解比较详细
class ViewController: UIViewController {lazy var stateLab:UILabel = {let size = UIScreen.main.bounds.sizelet labwidth = 100.0let labheight = 50.0let lab = UILabel(frame: CGRectMake((size.width - labwidth) / 2.0, (size.height - labheight) / 2.0, labwidth, labheight))view.addSubview(lab)lab.backgroundColor = UIColor.greenlab.font = UIFont.systemFont(ofSize: 28)lab.textColor = UIColor.redlab.textAlignment = .centerreturn lab}()func updateState(_ state:Bool){DispatchQueue.main.async {self.stateLab.text = state ? "打开" : "关闭"}}func addTest(){/*配置 App Groups1. 打开 Xcode,选择你的主 App 目标(Target)。2. 在 Signing & Capabilities 中,点击 + Capability。3. 搜索 App Groups 并添加。4. 创建一个新的 App Group(如 group.com.yourcompany.shared)。5. 在 Widget Extension / App Clips 目标中重复上述步骤,选择相同的 App Group。*/let appGroup = "group.testwidget1.demo"let sharedDefaults = UserDefaults(suiteName: appGroup)let isrunning = sharedDefaults?.value(forKey: "sharedRunning") as? Bool ?? falseupdateState(isrunning)}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {super.touchesBegan(touches, with: event)let sharedDefaults = UserDefaults(suiteName: "group.testwidget1.demo")let isrunning = sharedDefaults?.value(forKey: "sharedRunning") as? Bool ?? falsesharedDefaults?.set(!isrunning, forKey: "sharedRunning")print("\(!isrunning)")updateState(!isrunning)//通知小组件刷新notifiUpdateWidget()}func notifiUpdateWidget(){//通知小组件刷新,刷新所有小组件WidgetCenter.shared.reloadAllTimelines()//刷新指定的小组件,小组件那边注册的kind
// WidgetCenter.shared.reloadTimelines(ofKind: "TestWidget1")//获取配置去刷新小组件
// WidgetCenter.shared.getCurrentConfigurations { result in
// guard case .success(let success) = result else {
// return
// }
//
if let widget = success.first(
where:{ widget in
let intent = widget.configuration as ConfigurationAppIntent
return intent?.character == ""
}
){
WidgetCenter.shared.reloadTimelines(ofKind: widget.kind)
}
// }}override func viewDidLoad() {super.viewDidLoad()addTest()}}
苹果官方小组件文档
苹果官方swiftUI文档
相关文章:
ios 小组件和数据共享
创建主工程就不必讲了 1 创建小组件 创建子工程 [new Target ] 选择 [ Widger Extension] 小组件入口是WidgetBundle文件,可以进行多个小组件的调试 TestWidget2文件是主要操作,小组件使用swiftUI布局,使用 AppIntent进行事件处理ÿ…...
LVTTL(Low Voltage Transistor-Transistor Logic)电平详解
一、LVTTL电平的定义与核心特性 LVTTL(低压晶体管-晶体管逻辑)是传统TTL(5V)的低电压版本,工作电压通常为3.3V,旨在降低功耗并适配现代低电压集成电路,同时保持与TTL的逻辑兼容性。其核心特点如…...
element tree树形结构默认展开全部
背景: el-tree树形结构,默认展开全部,使用属性default-expand-all【是否默认展开所有节点】;默认展开一级,设置default-expanded-keys【默认展开的节点的 key 的数组】属性值为数组。 因为我这里的数据第一级是四川【省…...
统计登录系统10秒内连续登录失败超过3次的用户
为防止暴力破解用户账号的行为,在输入账号和密码时一般都会限制用户尝试密码输出错误的次数,如果用户多次输错密码后,将在一段时间内锁定账号,常见的有银行类APP、个税App等应用,如下是用户账号密码输入错误的提示图&a…...
音视频软件工程师面试题
一、基础知识 编解码相关 H.264 和 H.265(HEVC)的主要区别是什么?视频编解码的基本流程是什么?关键技术有哪些?音频编解码(如 AAC、MP3、Opus)的区别和应用场景?什么是 B 帧、P 帧、I 帧?它们的作用是什么? 流媒体协议RTMP、HTTP-FLV、HLS、WebRTC 的区别和应用场景…...
架构师面试(十四):注册中心设计
问题 大家或多或少都接触过【注册中心】,对注册中心的基本功能,如:服务注册、服务发现、健康检查和变更通知 ,肯定是耳熟能详的;那么大家对注册中心的架构设计是否了解呢? 如果让你负责设计一个分布式的注…...
ctf-web: php原生类利用 -- GHCTF Popppppp
源代码 <?php error_reporting(0); class CherryBlossom { public $fruit1; public $fruit2; public function __construct($a) {$this->fruit1 $a; } function __destruct() { echo $this->fruit1; } public function __toString() { $newFunc …...
「Unity3D」UGUI将元素固定在,距离屏幕边缘的某个比例,以及保持元素自身比例
在不同分辨率的屏幕下,UI元素按照自身像素大小,会发生位置与比例的变化,本文仅利用锚点(Anchors)使用,来实现UI元素,固定在某个比例距离的屏幕边缘。 首先,将元素的锚点设置为中心&…...
nextjs15简要介绍以及配置eslint和prettier
目录 一、Next.js 何时使用服务器端渲染(SSR)?何时使用静态生成(SSG)? 1、服务器端渲染(SSR - getServerSideProps) 2、 静态生成(SSG - getStaticProps) …...
存储过程和自定义函数在银行信贷业务中的应用(oracle)
数据校验和清洗 例如,检查客户的年龄是否在合理范围内,贷款金额是否符合规定的上下限等。 对于不符合规则的数据,可以进行清洗和修正。比如,将空值替换为默认值,或者对错误的数据进行纠正。 CREATE OR REPLACE PROC…...
基于Ollama平台部署的Qwen大模型实现聊天机器人
文章目录 基于Ollama平台部署的Qwen大模型实现聊天机器人1 概述2 技术栈2.1 开发技术2.2 环境 3 技术架构4 实现步骤4.1 环境搭建4.1.1 WSL配置及Ubuntu安装4.1.2 Ollama安装及模型部署 4.2 模块安装4.2.1 安装Streamlit 1.42.24.2.2 安装requests 2.32.34.2.3 安装ollama 0.4.…...
在 JDK 1.8 的 ConcurrentHashMap 中,为什么存在两种插入方式?
在 JDK 1.8 的 ConcurrentHashMap 中,之所以对“容器为空”和“计算位置为空”采取不同的处理方式,主要是因为 并发场景下的性能优化和并发安全保证。我们可以分开来看这两种情况: 1. 容器为空时,使用 volatile CAS 初始化 原因…...
如何让powershell的界面变成全屏显示?
刚打开powershell,原来的样子: 全屏:可以按一下键盘上的alt enter 键,效果:...
语音识别踩坑记录
本来想在原来的语音识别的基础上增加本地扩展本地词典, 采用的语音识别是Vosk识别器,模型是 vosk-model-small-cn-0.22 // 初始化Vosk识别器 if (recognizer null) {using (Model model new Model(modelPath)){string grammar "{""…...
图片查看器:用PyQt5实现本地图片预览工具
通过python代码,基于PyQt5实现本地图片预览查看工具。 我们对窗口进行了圆角设计,图片的翻页按钮半透明处理,当鼠标移动至按钮上的动画效果,当选择某一张图片,进行左右翻页则轮播同目录所有支持的图片格式。 import …...
Deepin通过二进制方式升级部署高版本 Docker
一、背景: 在Deepin系统中通过二进制方式升级部署高版本 Docker,下面将详细介绍二进制方式升级部署高版本 Docker 的具体步骤。 二、操作步骤 1.根据需求下载二进制文件,下载地址如下: https://mirrors.tuna.tsinghua.e…...
车架号VIN查询 API 接口用JAVA如何调用?
以下是车架号VIN查询 API 接口用JAVA如何调用的示例代码: package com.shuxun.data.impl.demo;import com.shuxun.common.core.util.HttpUtil; import org.apache.commons.codec.digest.DigestUtils;import java.util.HashMap; import java.util.Map;public class …...
Vulnhub 靶机 VulnOSv2 write up opendocman cms 32075 sql注入 账号密码 ssh连接 37292.c 脏牛提权
Vulnhub 靶机 VulnOSv2 write up opendocman cms 32075 sql注入 账号密码 ssh连接 37292.c 脏牛提权 一、信息收集 1、首先拿到靶场先扫一下ip arp-scan -l 3、 2、指纹扫描 nmap -sS -sV 192.168.66.178nmap -p- -sV -A 192.168.66.253 PORT STATE SERVICE VERSION 22…...
爬虫的精准识别:基于 User-Agent 的正则实现
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
Python数据分析之数据可视化
Python 数据分析重点知识点 本系列不同其他的知识点讲解,力求通过例子让新同学学习用法,帮助老同学快速回忆知识点 可视化系列: Python基础数据分析工具数据处理与分析数据可视化机器学习基础 四、数据可视化 图表类型与选择 根据数据特…...
5分钟快速上手:智能象棋AI助手的完整使用教程
5分钟快速上手:智能象棋AI助手的完整使用教程 【免费下载链接】VinXiangQi Xiangqi syncing tool based on Yolov5 / 基于Yolov5的中国象棋连线工具 项目地址: https://gitcode.com/gh_mirrors/vi/VinXiangQi Vin象棋是一款基于YOLOv5深度学习的开源免费中国…...
从HIP4082到IR2184:直流电机H桥驱动芯片怎么选?一份给硬件工程师的对比清单(含成本、功耗、设计复杂度)
从HIP4082到IR2184:直流电机H桥驱动芯片的工程选型指南 在小型机器人、电动工具或自动化设备的开发中,电机驱动电路的设计往往是硬件工程师面临的核心挑战之一。面对市场上琳琅满目的驱动芯片,如何在性能、成本和可靠性之间找到最佳平衡点&am…...
如何通过HS2-HF Patch解锁《Honey Select 2》的完整创作潜力:从新手到专家的终极指南
如何通过HS2-HF Patch解锁《Honey Select 2》的完整创作潜力:从新手到专家的终极指南 【免费下载链接】HS2-HF_Patch Automatically translate, uncensor and update HoneySelect2! 项目地址: https://gitcode.com/gh_mirrors/hs/HS2-HF_Patch 还在为《Honey…...
AI工具搭建自动化视频生成NVENC
最近在折腾视频生成这块,发现AI工具搭配NVENC(NVIDIA的硬件编码器)做自动化视频生成,其实是个挺有意思的组合。很多人以为写个脚本调用FFmpeg就能搞定,但真正要把NVENC用透,背后的门道还是挺多的。不如从几…...
告别杂乱地图标注!Arcgis中标注位置与多边形中心点提取的‘黄金搭档’技巧
告别杂乱地图标注!Arcgis中标注位置与多边形中心点提取的‘黄金搭档’技巧 当你在制作行政区划图或设施分布图时,是否曾被密密麻麻的标注搞得焦头烂额?标注重叠、位置不当、中心点偏移——这些问题不仅影响地图美观,更会降低信息的…...
深入解析:parseInt 到底有几个参数?
🔢 深入解析:parseInt 到底有几个参数? 🤔 parseInt 的签名 parseInt 函数接收 两个 参数: parseInt(string, radix)string (必填):要被解析的值。如果参数不是字符串,会先转换为字符串。rad…...
宇树GO2机器人ROS2控制:从零到自主导航的完整指南
宇树GO2机器人ROS2控制:从零到自主导航的完整指南 【免费下载链接】go2_ros2_sdk Unofficial ROS2 SDK support for Unitree GO2 AIR/PRO/EDU 项目地址: https://gitcode.com/gh_mirrors/go/go2_ros2_sdk Unitree GO2 ROS2 SDK是一个专门为宇树科技GO2系列机…...
MyBatis 二级缓存脏读真实原因
很多同学熟悉 MyBatis 一级缓存、二级缓存基础用法,但多表联查、跨Mapper更新场景下的缓存脏读漏洞,90%的人都会踩坑。 本文结合完整实战案例,用大白话拆解:脏读如何产生、一级缓存二级缓存双重隐患、Namespace隔离缺陷࿰…...
FCPX调色进阶:不靠插件,用内置工具实现电影感人物突出效果
FCPX调色进阶:不靠插件,用内置工具实现电影感人物突出效果 在影视创作中,人物主体的突出不仅是技术操作,更是视觉叙事的核心语言。Final Cut Pro X(FCPX)作为专业级剪辑软件,其内置调色工具往往…...
联想IdeaPad 310S老本升级记:手把手教你加内存、换固态、装Win10+Ubuntu双系统
联想IdeaPad 310S性能重生指南:从硬件升级到双系统实战 每次打开这台2016年购入的联想IdeaPad 310S,风扇的嘶吼和系统卡顿都让人抓狂。作为一款定位入门级的笔记本,它搭载的i3-6006U处理器和4GB内存早已跟不上现代应用的需求。但直接换新机又…...
