Dear Apple Developer Forum community,
I have a Multiplatform SwiftUI app that runs on both iOS and macOS. The app is available in the Mac App Store, and I aim to maintain backward compatibility. I use App Groups to synchronize data between the main app, where users configure content, and the widget, which displays this content. The data is stored using SwiftData.
With macOS Sequoia now in beta testing, I have encountered a breaking change that affects my app.
In macOS Sequoia, apps must use the team identifier number $(TeamIdentifierPrefix) as the prefix for App Groups on macOS. I cannot properly test future versions of my app without instructing my beta testers to turn off System Integrity Protection (SIP). This presents a significant issue for my Multiplatform SwiftUI app. On iOS, the app group identifier must start with group.identifier. Before macOS Sequoia, you could name your app group freely, and testing with TestFlight and publishing to the App Store was straightforward. Now, however, testing an app intended for the App Store is complicated by this rule. On macOS, you must use $(TeamIdentifierPrefix) to bypass this rule and allow for widgets to be tested and allow for synchronization between SwiftData. While on iOS, this approach is not allowed as the App Group becomes considered invalid.
Additionally, this annoying popup appears every time a beta tester tries to open the app if they have SIP turned on:
Instead of prompting for the app extensions, it rejects it. Rejecting this popup also prevents the main SwiftData app from opening.
I am unsure how to proceed. If I want to test widgets (which is a primary focus of the app), I must use macOS Sequoia. I am particularly concerned about the implications if I decide to stop supporting macOS Sonoma in the future.
Thank you in advance,
LocalWE
Post
Replies
Boosts
Views
Activity
Hello!
I made a lock screen widget that is much-needed,
However, it does not appear on the lock screen of the actual iOS.
I tried changing the Extension, but that does not appear to work.
Here is my code:
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SecondsEntry {
SecondsEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SecondsEntry) -> ()) {
let entry = SecondsEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SecondsEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for secondOffset in 0 ..< 60 {
let entryDate = Calendar.current.date(byAdding: .second, value: secondOffset, to: currentDate)!
let entry = SecondsEntry(date: entryDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SecondsEntry: TimelineEntry {
let date: Date
}
struct SecondsEntryView : View {
@Environment(\.widgetFamily) var widgetFamily
var entry: Provider.Entry
var body: some View {
switch widgetFamily {
case .accessoryCircular:
Gauge(value: 1) {
Text(entry.date.secondDisplayFormat)
.font(.largeTitle)
}
.gaugeStyle(.accessoryCircularCapacity)
case .accessoryRectangular:
HStack {
Text(entry.date.secondDisplayFormat)
.font(.title)
Text("Seconds")
.font(.headline)
}
case .accessoryInline:
Text("● " + entry.date.secondDisplayFormat + " Seconds")
.font(.largeTitle)
default:
Text("Error loading...")
}
}
}
struct Seconds: Widget {
let kind: String = "Seconds"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
SecondsEntryView(entry: entry)
}
.configurationDisplayName("Seconds")
.description("You will be able to track seconds, directly on your lock screen")
.supportedFamilies([.accessoryInline, .accessoryCircular, .accessoryRectangular])
}
}
struct Seconds_Previews: PreviewProvider {
static var previews: some View {
SecondsEntryView(entry: SecondsEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .accessoryInline))
.previewDisplayName("Inline")
SecondsEntryView(entry: SecondsEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .accessoryCircular))
.previewDisplayName("Circular")
SecondsEntryView(entry: SecondsEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .accessoryRectangular))
.previewDisplayName("Rectangular")
}
}
extension Date {
var secondDisplayFormat: String {
self.formatted(.dateTime.second())
}
}
Hello! I am fairly new to Swift, and I am trying out random things inside of Swift. I also tried learning with Swift Playgrounds, but it feels like code.org only that you type in functions. If you know the best learning methods, please let me know! Thanks, WE
P.S. I know Roblox LuaU, so Swift is not my first language.