当前位置: 首页 > news >正文

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文件&#xff0c;可以进行多个小组件的调试 TestWidget2文件是主要操作&#xff0c;小组件使用swiftUI布局&#xff0c;使用 AppIntent进行事件处理&#xff…...

LVTTL(Low Voltage Transistor-Transistor Logic)电平详解

一、LVTTL电平的定义与核心特性 LVTTL&#xff08;低压晶体管-晶体管逻辑&#xff09;是传统TTL&#xff08;5V&#xff09;的低电压版本&#xff0c;工作电压通常为3.3V&#xff0c;旨在降低功耗并适配现代低电压集成电路&#xff0c;同时保持与TTL的逻辑兼容性。其核心特点如…...

element tree树形结构默认展开全部

背景&#xff1a; el-tree树形结构&#xff0c;默认展开全部&#xff0c;使用属性default-expand-all【是否默认展开所有节点】&#xff1b;默认展开一级&#xff0c;设置default-expanded-keys【默认展开的节点的 key 的数组】属性值为数组。 因为我这里的数据第一级是四川【省…...

统计登录系统10秒内连续登录失败超过3次的用户

为防止暴力破解用户账号的行为&#xff0c;在输入账号和密码时一般都会限制用户尝试密码输出错误的次数&#xff0c;如果用户多次输错密码后&#xff0c;将在一段时间内锁定账号&#xff0c;常见的有银行类APP、个税App等应用&#xff0c;如下是用户账号密码输入错误的提示图&a…...

音视频软件工程师面试题

一、基础知识 编解码相关 H.264 和 H.265(HEVC)的主要区别是什么?视频编解码的基本流程是什么?关键技术有哪些?音频编解码(如 AAC、MP3、Opus)的区别和应用场景?什么是 B 帧、P 帧、I 帧?它们的作用是什么? 流媒体协议RTMP、HTTP-FLV、HLS、WebRTC 的区别和应用场景…...

架构师面试(十四):注册中心设计

问题 大家或多或少都接触过【注册中心】&#xff0c;对注册中心的基本功能&#xff0c;如&#xff1a;服务注册、服务发现、健康检查和变更通知 &#xff0c;肯定是耳熟能详的&#xff1b;那么大家对注册中心的架构设计是否了解呢&#xff1f; 如果让你负责设计一个分布式的注…...

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将元素固定在,距离屏幕边缘的某个比例,以及保持元素自身比例

在不同分辨率的屏幕下&#xff0c;UI元素按照自身像素大小&#xff0c;会发生位置与比例的变化&#xff0c;本文仅利用锚点&#xff08;Anchors&#xff09;使用&#xff0c;来实现UI元素&#xff0c;固定在某个比例距离的屏幕边缘。 首先&#xff0c;将元素的锚点设置为中心&…...

nextjs15简要介绍以及配置eslint和prettier

目录 一、Next.js 何时使用服务器端渲染&#xff08;SSR&#xff09;&#xff1f;何时使用静态生成&#xff08;SSG&#xff09;&#xff1f; 1、服务器端渲染&#xff08;SSR - getServerSideProps&#xff09; 2、 静态生成&#xff08;SSG - getStaticProps&#xff09; …...

存储过程和自定义函数在银行信贷业务中的应用(oracle)

数据校验和清洗 例如&#xff0c;检查客户的年龄是否在合理范围内&#xff0c;贷款金额是否符合规定的上下限等。 对于不符合规则的数据&#xff0c;可以进行清洗和修正。比如&#xff0c;将空值替换为默认值&#xff0c;或者对错误的数据进行纠正。 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 中&#xff0c;之所以对“容器为空”和“计算位置为空”采取不同的处理方式&#xff0c;主要是因为 并发场景下的性能优化和并发安全保证。我们可以分开来看这两种情况&#xff1a; 1. 容器为空时&#xff0c;使用 volatile CAS 初始化 原因…...

如何让powershell的界面变成全屏显示?

刚打开powershell&#xff0c;原来的样子&#xff1a; 全屏&#xff1a;可以按一下键盘上的alt enter 键&#xff0c;效果&#xff1a;...

语音识别踩坑记录

本来想在原来的语音识别的基础上增加本地扩展本地词典&#xff0c; 采用的语音识别是Vosk识别器&#xff0c;模型是 vosk-model-small-cn-0.22 // 初始化Vosk识别器 if (recognizer null) {using (Model model new Model(modelPath)){string grammar "{""…...

图片查看器:用PyQt5实现本地图片预览工具

通过python代码&#xff0c;基于PyQt5实现本地图片预览查看工具。 我们对窗口进行了圆角设计&#xff0c;图片的翻页按钮半透明处理&#xff0c;当鼠标移动至按钮上的动画效果&#xff0c;当选择某一张图片&#xff0c;进行左右翻页则轮播同目录所有支持的图片格式。 import …...

Deepin通过二进制方式升级部署高版本 Docker

一、背景&#xff1a; 在Deepin系统中通过二进制方式升级部署高版本 Docker&#xff0c;下面将详细介绍二进制方式升级部署高版本 Docker 的具体步骤。 二、操作步骤 1.根据需求下载二进制文件&#xff0c;下载地址如下&#xff1a; https://mirrors.tuna.tsinghua.e…...

车架号VIN查询 API 接口用JAVA如何调用?

以下是车架号VIN查询 API 接口用JAVA如何调用的示例代码&#xff1a; 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 的正则实现

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

Python数据分析之数据可视化

Python 数据分析重点知识点 本系列不同其他的知识点讲解&#xff0c;力求通过例子让新同学学习用法&#xff0c;帮助老同学快速回忆知识点 可视化系列&#xff1a; Python基础数据分析工具数据处理与分析数据可视化机器学习基础 四、数据可视化 图表类型与选择 根据数据特…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...