Post

Replies

Boosts

Views

Activity

Unable to Write to App Group Shared Container on Device
Hi everyone, I'm facing an issue where I cannot write a file to a shared App Group container in my tvOS app when running on a real device. My code works perfectly on the simulator, but fails on a physical device with a permissions error. I’ve set up an App Group with a custom identifier (e.g., group.<my.identifier>), and it’s correctly configured in the Capabilities section of Xcode for both my main app and widget targets. Here’s the code I’m using to save a test file: func saveTestFile() { guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.<my.identifier>") else { print("Couldn't access the Group URL.") return } let containerURL = groupURL.appendingPathComponent("Library", isDirectory: true) if FileManager.default.isWritableFile(atPath: containerURL.path) { print("Directory IS writable") } else { print("Directory IS NOT writable") } let fileURL = containerURL.appendingPathComponent("test.txt") let content = "Hello App Group!" do { try content.write(to: fileURL, atomically: true, encoding: .utf8) print("File test.txt is saved at: \(fileURL.path)") } catch { print("Error while saving the file: \(error)") } } Console: Directory IS NOT writable Error while saving the file: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “test.txt” in the folder “”." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup//Library/test.txt, NSURL=file:///private/var/mobile/Containers/Shared/AppGroup//Library/test.txt, NSUnderlyingError=0x14387fbe0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}} I’ve tried saving the file in different subdirectories within the App Group container: Directly in groupURL (root of the container). In groupURL.appendingPathComponent("Library"). In groupURL.appendingPathComponent("Caches"). Do you have any ideas what is the problem? Thanks in advance for any help!
1
0
58
Apr ’25
How to customise text field? tvOS
I'd like to customise text fields in my application, but I don't see any options for it. When I click text field, new window opens. And there is no title or description. But there must be something that allows me to customize it, right? Apple applications contain customised text fields. This is apple's text field (after clicking on it) This is my text field (after clicking on it) Here is my code: Form { //... TextField("", text: $address) //... } And there is one more problem. After filling this TextField I click enter and it immediately opens the next TextField. I don't want this behaviour.
1
1
652
Jun ’24
SwiftUI, tvOS - can't focus buttons
I'm trying to create a simple app for tvOS. But I immediately encountered difficulties. At the top I have a tab selection, and at the bottom there is item management. The problem is that all buttons in HStack are connected into one big button. So I solved it by adding .plain style to the buttons. But now I have a new problem - I can't focus on my buttons for tab selection. Here is the code: struct ContentView: View { var body: some View { VStack { HStack (alignment: .center) { Button("tab1"){} Button("tab2"){} } .frame(width: 500) // works when remove List { HStack { Text("Item 1") Spacer() Button("Button1"){} .buttonStyle(.plain) // added Button("Button2"){} .buttonStyle(.plain) // added } HStack { Text("Item 2") Spacer() Button("Button1"){} .buttonStyle(.plain) // added Button("Button2"){} .buttonStyle(.plain) // added } } } } } I would appreciate any help. Unfortunately, there is very little information on the Internet about designing applications for tvOS, which confuses me.
1
0
1.2k
May ’24
How to prevent Menu view from redrawing?
I have a complex project that includes a background process sending requests to the backend for updates. It sends requests once per second. So, I have the MyView where the PresetPicker is located. When I open the PresetPicker and try to scroll down, it keeps pushing me back up every second. PresetPicker redraws itself every second due to some changes from the background process. (Turning off the background process confirmed that everything works fine.) I wrapped my PresetPicker in EquatableView, added a bunch of logs triggered by changes/redraws of the PresetPicker, but the logs are empty and EquatableView didn't help. I tried setting breakpoints; they trigger when the PresetPicker first appears but don't trigger afterward. How can I fix/debug this? Here is some code: struct PresetPicker: View, Equatable { var body: some View { Menu { Text("1") Text("2") Text("3") Text("4") } label: { Text("menu") } } } struct MyView: View { var body: some View { EquatableView(content: PresetPicker() ) } }
1
0
570
May ’24
NotificationService is not called
I have read through many forums but haven't found a solution for myself. When sending a notification, my NotificationService is not being called. I added it exactly as described in the official Apple tutorial and tried adding it again following other tutorials. Nothing helped. I haven't made any changes to it; it is in the same form as it is automatically created. Here it is: import UserNotifications class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { // Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } } It does not print anything or hit any breakpoints. The notification payload looks like this: { "Simulator Target Bundle": "my.bundle", "aps": { "alert": { "title": "Its title", "body": "Very nice text" }, "sound": "default", "category": "CustomSamplePush", "mutable-content": 1 } } Things I've tried: Ensured the minimum version matches that of the application. Configured info.plist, including UNNotificationExtensionCategory. Ensured "Copy Only When Installed" is unchecked. The Content extension works. However, prints and breakpoints are also not working.
1
2
1.3k
Jan ’24
Switches to another View for no reason
I've shortened my code as much as possible. The problem is that when I click on the "Generate" button inside CreateView, I am transferred to WaitView for a tenth of a second, after which I am transferred back to CreateView. I quickly realized that the problem was a modification of the DataManager, since when I deleted this code: dataManager.data.append(SomeData(data: newData)) this problem disappeared. But this obviously doesn’t suit me, because I need to change the data. I also noticed that if you remove this code from ListView, then everything will work: NavigationLink(destination: CreateView(dataManager: dataManager)) { Text(data_item.data) } I can't imagine how this should affect this at all. What could be the problem? code: import Foundation import SwiftUI struct SomeData: Identifiable { let id = UUID() var data: String } class DataManager: ObservableObject { @Published var data: [SomeData] init() { data = [SomeData(data: "test")] } } struct ContentView: View { @StateObject var dataManager: DataManager = DataManager() var body: some View { NavigationView { ListView(dataManager: dataManager) .navigationTitle("First View") } } } struct ListView: View { @ObservedObject var dataManager: DataManager var body: some View { NavigationView { VStack { NavigationLink(destination: CreateView(dataManager: dataManager)) { Text("GENERATE") .font(.title) .foregroundColor(.white) .padding() .frame(width: 200, height: 200) .background(Color.blue) .clipShape(Circle()) } .padding(100) Spacer() VStack (alignment: .leading) { Text("History") .font(.title3) List { ForEach(dataManager.data) {data_item in NavigationLink(destination: CreateView(dataManager: dataManager)) { //When I remove this line everything works Text(data_item.data) } } } .listStyle(.automatic) .cornerRadius(20) } .padding() } } } } struct CreateView: View { @ObservedObject var dataManager: DataManager @State var fieldData: String = "some data here" var body: some View { UITableView.appearance().backgroundColor = .clear return VStack { NavigationLink(destination: WaitView(dataManager: dataManager, newData: fieldData)) { Text("Generate") .padding() .background(Color.red) } } .navigationBarTitleDisplayMode(.inline) }} struct WaitView: View { @ObservedObject var dataManager: DataManager let newData: String var body: some View { Text("Wait for something...") .navigationTitle("Third View") .onAppear { dataManager.data.append(SomeData(data: newData))//When I remove this line everything works print("adding") } } }
4
0
1.2k
Sep ’23