Files
digital-pilates/ios/digitalpilates/AppGroupUserDefaults.swift
richarjiang 35d6b74451 feat(widget): 增强Widget数据同步机制并优化UI设计
- 在useWaterData中统一处理数据变更后的Widget同步逻辑
- 新增数组类型数据存取方法支持更复杂数据结构
- 重构Widget UI为圆形进度条设计,提升视觉体验
- 修复数据同步时可能存在的竞态条件问题
- 优化错误处理,确保Widget同步失败不影响主功能
2025-09-11 10:38:54 +08:00

146 lines
4.3 KiB
Swift

//
// AppGroupUserDefaults.swift
// digitalpilates
//
// Native module for accessing App Group UserDefaults
// Allows sharing data between main app and widget
//
import Foundation
import React
@objc(AppGroupUserDefaults)
class AppGroupUserDefaults: NSObject, RCTBridgeModule {
static func moduleName() -> String! {
return "AppGroupUserDefaults"
}
static func requiresMainQueueSetup() -> Bool {
return false
}
// MARK: - String Methods
@objc
func setString(_ groupId: String, key: String, value: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
userDefaults.set(value, forKey: key)
userDefaults.synchronize()
DispatchQueue.main.async {
resolver(nil)
}
}
}
@objc
func getString(_ groupId: String, key: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
let value = userDefaults.string(forKey: key)
DispatchQueue.main.async {
resolver(value)
}
}
}
// MARK: - Number Methods
@objc
func setNumber(_ groupId: String, key: String, value: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
userDefaults.set(value, forKey: key)
userDefaults.synchronize()
DispatchQueue.main.async {
resolver(nil)
}
}
}
@objc
func getNumber(_ groupId: String, key: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
let value = userDefaults.object(forKey: key) as? NSNumber ?? NSNumber(value: 0)
DispatchQueue.main.async {
resolver(value)
}
}
}
// MARK: - Array Methods
@objc
func setArray(_ groupId: String, key: String, value: [Any], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
userDefaults.set(value, forKey: key)
userDefaults.synchronize()
DispatchQueue.main.async {
resolver(nil)
}
}
}
@objc
func getArray(_ groupId: String, key: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
let value = userDefaults.array(forKey: key)
DispatchQueue.main.async {
resolver(value)
}
}
}
// MARK: - Remove Key Method
@objc
func removeKey(_ groupId: String, key: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
DispatchQueue.global(qos: .background).async {
guard let userDefaults = UserDefaults(suiteName: groupId) else {
rejecter("ERROR", "Failed to create UserDefaults with suite name: \(groupId)", nil)
return
}
userDefaults.removeObject(forKey: key)
userDefaults.synchronize()
DispatchQueue.main.async {
resolver(nil)
}
}
}
}