Drop App Groups, share via keychain access group only

Apple's ASC API doesn't expose App Group registration cleanly, and the
keychain access group on its own (`$(AppIdentifierPrefix)<bundleId>`)
already gives the share extension and container app a shared store for
the base URL + token. The repo cache moves to per-process UserDefaults —
the extension fetches/caches it on first share if empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude
2026-04-26 23:20:36 -05:00
parent 74e03c4e10
commit 0a835f6be0
4 changed files with 9 additions and 19 deletions
-4
View File
@@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.treytartt.GiteaIssue</string>
</array>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.treytartt.GiteaIssue</string> <string>$(AppIdentifierPrefix)com.treytartt.GiteaIssue</string>
@@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.treytartt.GiteaIssue</string>
</array>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.treytartt.GiteaIssue</string> <string>$(AppIdentifierPrefix)com.treytartt.GiteaIssue</string>
+6 -6
View File
@@ -9,7 +9,7 @@ enum RepoCache {
static var repos: [GiteaRepo] { static var repos: [GiteaRepo] {
get { get {
guard let data = AppSettings.sharedDefaults.data(forKey: listKey) else { return [] } guard let data = AppSettings.localDefaults.data(forKey: listKey) else { return [] }
let decoder = JSONDecoder() let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601 decoder.dateDecodingStrategy = .iso8601
return (try? decoder.decode([GiteaRepo].self, from: data)) ?? [] return (try? decoder.decode([GiteaRepo].self, from: data)) ?? []
@@ -18,14 +18,14 @@ enum RepoCache {
let encoder = JSONEncoder() let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601 encoder.dateEncodingStrategy = .iso8601
if let data = try? encoder.encode(newValue) { if let data = try? encoder.encode(newValue) {
AppSettings.sharedDefaults.set(data, forKey: listKey) AppSettings.localDefaults.set(data, forKey: listKey)
AppSettings.sharedDefaults.set(Date(), forKey: listFetchedKey) AppSettings.localDefaults.set(Date(), forKey: listFetchedKey)
} }
} }
} }
static var fetchedAt: Date? { static var fetchedAt: Date? {
AppSettings.sharedDefaults.object(forKey: listFetchedKey) as? Date AppSettings.localDefaults.object(forKey: listFetchedKey) as? Date
} }
static var isStale: Bool { static var isStale: Bool {
@@ -34,13 +34,13 @@ enum RepoCache {
} }
static var recentFullNames: [String] { static var recentFullNames: [String] {
AppSettings.sharedDefaults.stringArray(forKey: recentsKey) ?? [] AppSettings.localDefaults.stringArray(forKey: recentsKey) ?? []
} }
static func touch(_ fullName: String) { static func touch(_ fullName: String) {
var current = recentFullNames.filter { $0 != fullName } var current = recentFullNames.filter { $0 != fullName }
current.insert(fullName, at: 0) current.insert(fullName, at: 0)
if current.count > recentsCap { current = Array(current.prefix(recentsCap)) } if current.count > recentsCap { current = Array(current.prefix(recentsCap)) }
AppSettings.sharedDefaults.set(current, forKey: recentsKey) AppSettings.localDefaults.set(current, forKey: recentsKey)
} }
} }
+3 -5
View File
@@ -1,8 +1,6 @@
import Foundation import Foundation
enum AppSettings { enum AppSettings {
static let appGroup = "group.com.treytartt.GiteaIssue"
private static let baseURLKey = "gitea.baseURL" private static let baseURLKey = "gitea.baseURL"
private static let tokenKey = "gitea.token" private static let tokenKey = "gitea.token"
@@ -20,7 +18,7 @@ enum AppSettings {
!token.isEmpty && URL(string: baseURL) != nil !token.isEmpty && URL(string: baseURL) != nil
} }
static var sharedDefaults: UserDefaults { /// Process-local cache store. Keychain handles cross-process sharing;
UserDefaults(suiteName: appGroup) ?? .standard /// the cached repo list lives in each process's standard defaults.
} static var localDefaults: UserDefaults { .standard }
} }