Hi,
This maybe somewhat confusing, but please bear with me.
I currently have an app in the App Store that supports iOS and tvOS. But the tvOS version was a separate app during the development process. I'd like to combine the iOS and tvOS app into one project so its easier to handle and keep track of internally.
Can I upload the new Apple TV version to the same place where the current one is, or would I have to delete the current Apple TV version before uploading the newly combined version?
I hope I made that clear enough :-)
Thank you,
Dan Uff
Posts under tvOS tag
85 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I noticed a discrepancy between the Material specifications for tvOS on the Developer page and the naming in the Design Resources (Sketch files). Which one should we consider authoritative?
https://developer.apple.com/design/human-interface-guidelines/materials
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!
Hi everyone,
I'm working on a tvOS app using SwiftUI, and I want to disable the focus effect (the default focus glow/bounce) on a specific Button. According to the documentation:
/// - Parameter disabled: A Boolean value that determines whether this view
/// can display focus effects.
/// - Returns: A view that controls whether focus effects can be displayed
/// in this view.
I used .focusEffectDisabled(true) on the Button, expecting the focus style to be completely disabled for that view. However, this doesn’t seem to have any effect in my tvOS 17+ app – the button still shows the default focus visual effect when focused.
Here’s a simplified example:
Button("Click Me") {
// action
}
.focusEffectDisabled(true)
This still shows the bounce/glow focus effect. Am I missing something, or is this a bug?
Has anyone managed to fully disable the focus effect for a view (especially Button) in tvOS using SwiftUI? Any workarounds or additional modifiers I should apply?
Thanks in advance!
Hi,
I'm trying to fix tvOS view for VoiceOver accessibility feature:
TabView { // 5 tabs
Text(title)
Button(play)
ScrollView { // Live
LazyHStack { 200 items }
}
ScrollView { // Continue watching
LazyHStack { 500 items }
}
}
When the view shows up VoiceOver reads:
"Home tab 1 of 5, Item 2" - not sure why it reads Item 2 of the first cell in scroll view, maybe beacause it just got loaded by LazyHStack.
VocieOver should only read "Home tab 1 of 5"
When moving focus to scroll view it reads:
"Live, Item 1" and after slight delay "Item 1, Item 2, Item 3, Item 4"
When moving focus to second item it reads:
"Item 2" and after slight delay "Item 1, Item 2, Item 3, Item 4"
When moving focus to third item it reads:
"Item 3" and after slight delay "Item 1, Item 2, Item 3, Item 4"
It should be just reading what is focused, idealy just
"Live, Item 1, 1 of 200"
then after moving focus on item 2
"Item 2, 2 of 200"
this time without the word "Live" because we are on the same scroll view (the same horizontal list)
Currently the app is unusable, we have visually impaired testers and this rotor reading everything on the screen is totaly confusing, because users don't know where they are and what is actually focused.
This is a video streaming app and we are streaming all the time, even on home page in background, binge plays one item after another, usually there is never ending Live stream playing, user can switch TV channel, but we continue to play. Voice over should only read what's focused after user interaction.
Original Apple TV app does not do that, so it cannot be caused by some verbose accessibility settings. It reads correctly only focused item in scrolling lists.
How do I disable reading content that is not focused?
I tried:
.accessibilityLabel(isFocused ? title : "")
.accessibilityHidden(!isFocused)
.accessibilityHidden(true) - tried on various levels in view hierarchy
.accessiblityElement(children: .ignore) - even focused item is not read back by voice over
.accessiblityElement(children: .ignore) - even focused item is not read back by voice over
.accessiblityElement(children: .contain) - tried on various levels in view hierarchy
.accessiblityElement(children: .combine) - tried on various levels in view hierarchy
.accessibilityAddTraits(.isHeader) - tried on various levels in view hierarchy
.accessibilityRemoveTraits(.isHeader) - tried on various levels in view hierarchy
// the last 2 was basically an attempt to hack it
.accessibilityRotor("", ranges []) - another hack that I tried on ScrollView, LazyHStack, also on top level view.
50+ other attempts at configuring accessibility tags attached to views.
I have seen all the accessibility videos, tried all sample code projects, I haven't found a solution anywhere, internet search didn't find anything, AI didn't help as it can only provide code that someone else wrote before.
Any idea how to fix this?
Thanks.
Hi,
I got a problem with severe hangs when I use code like this on tvOS 18.2
If I try to use HStack instead of LazyHStack inside the scrollview then the problem does not occur any more but then the scroll performance is compromised and the vertical scroll is no longer that smooth. Does someone has any experience with this? Is this SwiftUI problem or am I missing something?
ScrollView {
LazyVStack {
ForEach(0...100, id: \.self) { _ in
ScrollView {
LazyHStack {
ForEach(0...20, id: \.self) { _ in
Color.red.frame(height: 300)
}
}
}
}
}
}
We're building an SDK (let's call it MyFramework) which is distributed as an .xcframework for developers to integrate it into their own apps.
Recently, we've added tvOS support by adding it as a supported destination for the SDK. Essentially, the SDK became a cross-platform framework and easy to be adopted in both iOS and tvOS apps.
The .xcframework is generated fine, all builds correctly. We've tested the SDK integrated in test apps. We've also submitted an iOS archive app to the AppStore connect, just to make sure all is well with the AppStore submission.
However, when I tried submitting a tvOS archive app (that integrates the same SDK) to the AppStore connect, the build was marked as invalid binary and we've got the following error message:
ITMS-90562: Invalid Bundle - One of the nested bundles is built for a platform which is different from the main bundle platform. Please make sure that all bundles have correct platform specification.
First, I thought that any of the modules of the framework was not correctly configured for tvOS but that was not the case. Everything compiles ok and it runs in debug as expected.
It only fails when trying to submit the tvOS app that integrates the SDK.
After a lot of investigating, we realised that the reason for the AppStore submission error is because we codesign the framework. We use codesign to distribute it as cryptographically signed xcframework.
codesign --timestamp -v --sign "Apple Distribution: Company (xxxxxxxxxx)" "MyFramework.xcframework"
As soon as we remove the above line from our CI/CD pipeline that generates the xcframework, and submit a tvOS archive app that integrates the unsigned framework, the AppStore submission error goes away and the TestFlight build can be tested.
I've also tried to just strip the _CodeSignature folder from the .xcframework package but it still fails. So the only solution currently is to not codesign the xcframework to be able to upload tvOS archive apps that integrate the SDK to the AppStore connect.
However, we're still puzzled as to why only the tvOS archive app gets the invalid binary error when it integrates a signed SDK. I feel like the error message is quite misleading if we have to stop signing the SDK xcframework for it to be accepted during the AppStore submission.
Anyone has any idea? Or has anyone encountered a similar issue?
Thanks!
Since tvOS 18, my Picker view with inline style is not showing the checkmark on the selected item.
enum Flavor: String, Identifiable {
case chocolate, vanilla, strawberry
var id: Self { self }
}
struct ContentView: View {
@State private var selectedFlavor: Flavor = .chocolate
var body: some View {
NavigationView {
Form {
Picker("Flavor", selection: $selectedFlavor) {
Text("Chocolate").tag(Flavor.chocolate)
Text("Vanilla").tag(Flavor.vanilla)
Text("Strawberry").tag(Flavor.strawberry)
}.pickerStyle(.inline)
}
}
}
}
Am I missing something? When I run this on tvOS 17.x, it works fine.
In tvOS when using NavigationStack inside NavigationSplitView as below:
@State private var selectedItem: String?
@State private var navigationPath = NavigationPath() // Track navigation state manually
var body: some View {
NavigationSplitView {
List(selection: $selectedItem) {
Button("Item 1") { selectedItem = "Detail View 1" }
Button("Item 2") { selectedItem = "Detail View 2" }
}
} detail: {
NavigationStack(path: $navigationPath) {
DetailView()
.navigationDestination(for: String.self) { value in
Text("New Screen: \(value)")
}
}
}
}
}
This example completely breaks the animation inside NavigationStack while navigating between different views, using withAnimation also breaks the navigation as the old view seems to be still in stack and is shown in the new view background.
I have also submitted bug report: https://feedbackassistant.apple.com/feedback/16933927
Issue:- The characters in SearchController SearchBar are overlapping on focusing.
Steps:-
Select the System language as Arabic
Launch the tvOS app
Set the app language as English in the tvOS app
Focus on SearchController SearchBar
Focus on any characters there you can see overlapping issue.
Since tvOS 18.4 beta (22L5218l) i have the issue that When I turn off an Apple TV, the Apple TV and the connected TV turn off, but after a few seconds the devices start again.
This never happened before. But now it is happening with 3 different Apple TV generations on 2 LG and 1 Telefunken TVs. All 3 Apple TV devices have been updated to tvOS 18.4 beta (22L5218l) and since then show this error.
I am trying to implement in-app purchases in Apple TV.
I added a "non-consumable" product and started testing in Sandbox, but it did not work properly.
While I am trying to fetch the product from the appstore, it won't give any responses like success or failure.
So that our app gets rejected in the App Store.
Please provide me the steps to implement in-app purhcase in Apple tvos using Swift.
Note: The same code is working fine in iOS.
I found a memory leak in tvOS 17.4, but it's not happening in tvOS 18.0
here is the code flow
1.I have controller inside which I have tableView which in turn contains a collectionview
here I have passed self to tableViewcell as delegate and then from tableview cell I have passed self again as delegate to collectionViewcell, but memory is not released, because self is retained
"I have passed self as weak every where still memory leak is happening only in tvOS 17.4 and below versions. but in 18.0 and above versions it's fine"
Description
I'm developing a tvOS application where I utilize a UISearchController embedded within a UISearchContainerViewController for search functionality. In a particular flow, a custom view controller contains a TVDigitEntryViewController as a child, with its modalPresentationStyle set to .blurOverFullScreen. The issue arises when a user initiates the PIN entry but decides to cancel and return to the search interface without entering a PIN. Upon returning, the search keyboard is no longer visible, and attempts to focus or interact with it are unsuccessful.
Steps to Reproduce
Initialize and present a UISearchContainerViewController that contains a UISearchController with a results view controller.
Within the search results, present a custom view controller containing TVDigitEntryViewController as a child, setting its modalPresentationStyle to .blurOverFullScreen.
Dismiss the custom view controller without entering a PIN (e.g., by pressing the Menu button on the remote).
Observe that upon returning to the search interface, the keyboard is missing, and focus interactions are unresponsive.
Observed Behavior
After dismissing the custom view controller with TVDigitEntryViewController, the search keyboard does not reappear, and the focus system seems to lose track of the search input field.
Expected Behavior
The search keyboard should remain visible and functional after dismissing the custom view controller, allowing users to continue their search without interruption.
Additional Context
I have reviewed the TVDigitEntryViewController documentation (developer.apple.com) and related discussions on the Apple Developer Forums but have not found a solution to this specific issue.
Questions
Has anyone encountered a similar issue or have insights into why the search keyboard becomes unresponsive after dismissing a .blurOverFullScreen modal with a child TVDigitEntryViewController?
Are there recommended practices to ensure the search keyboard remains active and focusable after such modal presentations?
Any guidance or suggestions would be greatly appreciated. Thank you!
I'm working on an Apple TVOS app and trying to upload it to the App Store. My app includes a video file that’s 8GB in size, and I’ve moved the video to On-Demand Resources to optimize its size. However, when I generate the archive, the total file size comes out to 8.4GB, which is too large for App Store submission.
Uploaded the build in the test flight but the test flight build is in progress then got the error is an invalid build.
How to upload a large build of Apple TV in the App Store using on-demand resources.
on-demand video size is 8GB
I'm working on an Apple TVOS app and trying to upload it to the App Store. My app includes a video file that’s 8GB in size, and I’ve moved the video to On-Demand Resources to optimize its size. However, when I generate the archive, the total file size comes out to 8.4GB, which is too large for App Store submission.
Uploaded the build in the test flight but the test flight build is in progress then got the error is an invalid build.
How to upload a large build of Apple TV in the App Store using on-demand resources.
on-demand video size is 8GB
I've just started working on my first SpriteKit game that will eventually run on both tvOS and iOS and am looking at how to build a "button". So far, I've got a custom node that looks like:
class MyButton: SKSpriteNode {
...
#if os(tvOS)
override var canBecomeFocused: Bool {
true
}
override func didUpdateFocus(...) {
...
}
#endif
}
The above let me nicely handle focus changes in tvOS and now I'm looking at reacting to selecting the button.
Searching around, all the articles/questions/posts are from 2015-2016 - which is a LOOOONG time ago. Most of the guidance appears to be to add a tap gesture recognizer in the owning scene and getting the scene to hand it off to the button. That seems pretty brittle and I'd much prefer if the button itself is responsible for its own tap management.
So, I guess my question is whether I should just add a gesture recognizer to my custom button class? Is this inefficient if I end up having 7-8 buttons on the screen and each one has its own gesture recognizer?
Somewhat related, all of the 10-year-old advice is that if we add recognizers to scenes, then they need to be removed from the view controller... however, in the modern day world with SwiftUI, my project doesn't even have a view controller (yet, anyway)... what gesture recognizer lifecycle management do I need in a SpriteKit scene that is presented within a SpriteKitView?
Or, is there a better way? I was kind of hoping that overriding pressesBegan() (or something similar) in my custom button might have been triggered on tvOS (like touchesBegan() lets me manage touches for the iOS variant of my app)
Any pointers or suggestions would be gladly received. Thanks.
When turning VoiceOver ON, GCController does not send button press events for "Button A" and "Button Center".
This happens when using Siri 2nd generation remote (with dedicated arrow buttons on the circle around center button) and also when using iOS remote. I didn't test it on old Siri 1st generation with touchpad without arrow buttons.
Example:
gameController.microGamepad?.allButtons.forEach { button in
button.valueChangedHandler = { [weak self] _, _, _ in
self?.buttonHandler(gameController: gameController, button: button)
}
private func buttonHandler(gameController: GCController, button: GCControllerButtonInput) {
print("BUTTON: Pressed \(button.description) isPressed=\(button.isPressed) isTouched=\(button.isTouched)")
}
#endif
VoiceOver ON (incorrect behavior):
BUTTON: Pressed Direction Pad Left (value: 0.030, pressed: 1) isPressed=true isTouched=true
BUTTON: Pressed Direction Pad Down (value: 0.079, pressed: 1) isPressed=true isTouched=true
BUTTON: Pressed Direction Pad Left (value: 0.000, pressed: 0) isPressed=false isTouched=false
BUTTON: Pressed Direction Pad Down (value: 0.000, pressed: 0) isPressed=false isTouched=false
VoiceOver OFF (correct behavior):
BUTTON: Pressed Direction Pad Left (value: 0.137, pressed: 1) isPressed=true isTouched=true
BUTTON: Pressed Direction Pad Up (value: 0.078, pressed: 1) isPressed=true isTouched=true
BUTTON: Pressed Button A (value: 1.000, pressed: 1) isPressed=true isTouched=true
BUTTON: Pressed Button Center (value: 1.000, pressed: 1) isPressed=true isTouched=true
BUTTON: Pressed Button A (value: 0.000, pressed: 0) isPressed=false isTouched=false
BUTTON: Pressed Button Center (value: 0.000, pressed: 0) isPressed=false isTouched=false
BUTTON: Pressed Direction Pad Left (value: 0.000, pressed: 0) isPressed=false isTouched=false
BUTTON: Pressed Direction Pad Up (value: 0.000, pressed: 0) isPressed=false isTouched=false
I could use for detection Direction Pad Left/Right/Up/Down and detect position between -0.7 and +0.7 and handle it as center button press, because I use that on old Siri remote where I need to distinguish center button and arrows (for switching TV channels by Up/Down and Skip forward/back by Left/Right arrows), but for new Siri remote it would be unnecessary workaround.
Does anybody know why the center/select button is not detected when VoiceOver is ON. Is there another way of detecting it using GCController?
I don't want to use SwiftUI onTapGesture for this one particular case.
Is it an unexpected bug in tvOS APIs or is there some specific reason why center button is not handled by GCController when VoiceOver is ON?
Thanks.
Hi everyone, I'm currently working on my own Apple TV app. So far, things are going pretty well, but right now, I'm stuck on the design of the categories or selection menus.
Here's a screenshot of how it looks right now:
The green color and the border are intentionally added for now so I can see what is where. My actual goal is to remove the gray bar (or is this the "main bar"?). The pink bar and its border are just design elements that can be removed if needed. I want it to look more "original," like this:
Here is the code:
let title: String
let isSelected: Bool
var body: some View {
HStack {
Text(title)
.foregroundColor(isSelected ? .black : .white)
.font(.system(size: 22, weight: .regular))
.padding(.leading, 20)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(isSelected ? .black : .gray)
.padding(.trailing, 20)
}
.frame(height: 50) // Einheitliche Höhe für die Kategorien
.background(Color.pink) // Innerer Hintergrund auf pink gesetzt
.cornerRadius(10) // Abrundung direkt auf den Hintergrund anwenden
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.green, lineWidth: 3) // Äußerer Rahmen auf grün gesetzt
)
.padding(.horizontal, 0) // Entferne äußere Ränder
.background(Color.clear) // Entferne alle anderen Hintergründe
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
}
}
I’ve adjusted the code, but it’s still not quite right. When a category is not selected, it appears black instead of gray, like in the original design
Here is the code:
struct SettingsView: View {
@State private var selectedCategory: String?
var body: some View {
NavigationStack {
ZStack {
Color.black
.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
// Überschrift oben in der Mitte
Text("Einstellungen")
.font(.system(size: 40, weight: .semibold))
.foregroundColor(.white)
.padding(.top, 30)
HStack {
// Linke Seite mit Logo
VStack {
Spacer()
Image(systemName: "applelogo")
.resizable()
.scaledToFit()
.frame(width: 120, height: 120)
.foregroundColor(.white)
Spacer()
}
.frame(width: UIScreen.main.bounds.width * 0.4)
// Rechte Seite mit Kategorien
VStack(spacing: 15) {
ForEach(categories, id: \.self) { category in
NavigationLink(
value: category,
label: {
SettingsCategoryView(
title: category,
isSelected: selectedCategory == category
)
}
)
.buttonStyle(PlainButtonStyle())
}
}
.frame(width: UIScreen.main.bounds.width * 0.5)
}
}
}
.navigationDestination(for: String.self) { value in
Text("\(value)-Ansicht")
.font(.title)
.foregroundColor(.white)
.navigationTitle(value)
}
}
}
private var categories: [String] {
["Allgemein", "Benutzer:innen und Accounts", "Video und Audio", "Bildschirmschoner", "AirPlay und HomeKit", "Fernbedienungen und Geräte", "Apps", "Netzwerk", "System", "Entwickler"]
}
}
struct SettingsCategoryView: View {
let title: String
let isSelected: Bool
var body: some View {
HStack {
Text(title)
.foregroundColor(.white)
.font(.system(size: 22, weight: .medium))
.padding(.leading, 20)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.gray)
.padding(.trailing, 20)
}
.frame(height: 50) // Einheitliche Höhe für die Kategorien
.background(isSelected ? Color.gray.opacity(0.3) : Color.clear) // Hervorhebung des ausgewählten Elements
.cornerRadius(8) // Abgerundete Ecken
.scaleEffect(isSelected ? 1.05 : 1.0) // Fokus-Animation
.animation(.easeInOut, value: isSelected)
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
}
}
Hello,
I am currently developing an application for Apple TV using TVML, and I am trying to create a user registration or login form with multiple input fields (e.g., "Username" and "Password"). However, I am facing issues with displaying multiple textField components in the formTemplate.
Here are the approaches I have tried:
Attempt 1:
<document>
<formTemplate>
<banner>
<title>Login</title>
</banner>
<banner>
<textField>UserName</textField>
</banner>
<banner>
<textField>Password</textField>
</banner>
<footer>
<button id="button1">
<text>Button 1</text>
</button>
</footer>
</formTemplate>
</document>
Attemp 2:
<document>
<formTemplate>
<banner>
<title>Login</title>
</banner>
<textField>UserName</textField>
<textField>Password</textField>
<footer>
<button id="button1">
<text>Button 1</text>
</button>
</footer>
</formTemplate>
</document>
In both cases, the layout does not render the fields as expected. Either the textField components do not display at all, or the structure seems incorrect.
Could someone please guide me on the proper way to display multiple textField components in a formTemplate? Is there a limitation or specific requirement for structuring these elements?
Thank you in advance for your assistance!