
Add a second Fastlane lane that uses platform=tvOS Simulator for tests, generic/platform=tvOS for the archive, a tvOS-specific provisioning profile, and a separate ExportOptions-tvOS.plist with method=app-store. Pass app_platform: "appletvos" to pilot for the TestFlight upload. For the runner, request a Figment M-series Mac (from $95/month; exact chip, RAM and disk are confirmed on the configuration quote) or the Managed Build Mac at $249/month if you want the CI setup, backups, monitoring and 30 minutes of monthly support handled for you. The $29/month Figment virtual Intel macOS environment (2 vCPU, 8 GiB RAM, 80 GiB disk, no GPU acceleration, no audio) can host Intel-compatible Xcode toolchains—Xcode 26 or earlier per Apple's porting guide—but Apple silicon is the practical runner for current tvOS simulators.
Apple TV support is an addition, not a rewrite: your signing certificate, Fastlane install and TestFlight account are reused. What changes is the destination specifier, the provisioning profile, and one ExportOptions.plist value.
xcodebuild uses destination specifiers to pick a platform and device. For tvOS the platform string is tvOS Simulator (with a space), not iOS Simulator. Apple documents the key/value form in Technical Note TN2339.
Run tests in the Apple TV 4K simulator:
xcodebuild test \
-scheme "MyApp-tvOS" \
-destination "platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=latest" \
-derivedDataPath ./DerivedData \
| xcpretty
set -o pipefail
Archive for distribution (generic device, not a specific simulator):
xcodebuild archive \
-scheme "MyApp-tvOS" \
-destination "generic/platform=tvOS" \
-archivePath ./build/MyApp-tvOS.xcarchive \
| xcpretty
Using generic/platform=tvOS for the archive step builds a device binary suitable for App Store submission. Using a named simulator destination for archiving produces a simulator binary and cannot be submitted.
Replace MyApp-tvOS with your project's actual shared scheme name—do not copy this verbatim without checking. To list the simulators Xcode currently knows about on your Mac:
xcrun simctl list devices --json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for runtime, devices in data['devices'].items():
if 'tvOS' in runtime:
for d in devices:
print(runtime, '|', d['name'], '|', d['udid'])
"
The exact simulator names depend on the Xcode version installed; use whatever the command prints.
Before writing CI steps, confirm your Xcode project is configured for tvOS:
com.example.myapp.tvos).#if !os(tvOS) conditional compilation blocks.A tvOS scheme must be shared to be visible to xcodebuild and Fastlane in a headless CI environment. Unshared schemes live under a user-specific directory and are not committed.
tvOS distribution uses separate provisioning profiles from iOS, even when the certificate is identical:
| Item | iOS | tvOS |
|---|---|---|
| App ID | com.example.myapp | com.example.myapp.tvos |
| Provisioning profile | MyApp iOS Distribution | MyApp tvOS Distribution |
| Distribution certificate | App Distribution (shared) | App Distribution (same cert) |
| ExportOptions method | app-store | app-store |
| ExportOptions bundle map | iOS bundle ID → iOS profile | tvOS bundle ID → tvOS profile |
Create the tvOS profile in the developer portal: Certificates, Identifiers & Profiles → Profiles → (+) → App Store Distribution → select the tvOS App ID. Apple's Distributing your app for beta testing and releases covers the end-to-end flow.
tvos_beta Fastfile LaneAdd this lane to your existing Fastfile. It assumes your iOS lane already handles certificate setup via match; the tvOS lane reuses the same match storage with a tvOS profile type.
# Fastfile
lane :tvos_beta do |options|
# 1. Ensure certificates and the tvOS profile are up to date
match(
type: "appstore",
app_identifier: "com.example.myapp.tvos",
platform: "tvos"
)
# 2. Run unit tests in the Apple TV 4K simulator
scan(
scheme: "MyApp-tvOS",
destination: "platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=latest",
output_directory: "./test-results/tvos",
output_types: "junit",
fail_build: true
)
# 3. Build and archive for App Store distribution
gym(
scheme: "MyApp-tvOS",
destination: "generic/platform=tvOS",
configuration: "Release",
archive_path: "./build/MyApp-tvOS.xcarchive",
output_directory: "./build",
output_name: "MyApp-tvOS",
export_method: "app-store",
export_options: "ExportOptions-tvOS.plist"
)
# 4. Upload to TestFlight — pass app_platform explicitly for tvOS.
pilot(
ipa: "./build/MyApp-tvOS.ipa",
app_platform: "appletvos",
skip_waiting_for_build_processing: true,
changelog: options[:changelog] || "New tvOS build from CI"
)
end
The scan step uses fail_build: true: if any test fails, the lane stops and later steps never run. The pilot action's app_platform option is documented in the Fastlane pilot action reference; pass appletvos explicitly rather than relying on auto-detection when a project ships multiple platforms. Invoke the lane with:
bundle exec fastlane tvos_beta changelog:"Fixes #452 tvOS crash on launch"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>provisioningProfiles</key>
<dict>
<key>com.example.myapp.tvos</key>
<string>MyApp tvOS Distribution</string>
</dict>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
</dict>
</plist>
Replace YOUR_TEAM_ID with your 10-character Apple Developer Team ID. The provisioningProfiles dictionary maps the tvOS bundle ID to the exact profile name as it appears in the developer portal. This file contains only identifiers, no secrets—commit it.
A tvOS simulator on a CI Mac needs the tvOS platform runtime installed. Check it:
xcrun simctl list runtimes | grep tvOS
If a required runtime shows as unavailable, Xcode 15 and later can download it from the command line:
xcodebuild -downloadPlatform tvOS
Run this once after provisioning a new Mac and confirm the runtime shows available before wiring the pipeline. Keep fail_build: true on scan; a green pipeline over failing tests is worse than no pipeline.
tvOS simulators ship with each Xcode release and are the main sizing driver—each runtime occupies roughly 5–8 GB on disk, and Xcode 27 requires an Apple silicon Mac per Apple's porting guide. On Xcode 26 or earlier, Intel-compatible hosts still work for many tvOS targets; visionOS needs Apple silicon regardless. Check the specific Xcode release row in Apple's release notes to confirm the Xcode/macOS pair you need.
Entry monthly prices for a single CI runner, verified on each vendor's own page:
| Option | Entry price | What's quoted | Source |
|---|---|---|---|
| Figment M-series | from $95/month | Apple silicon Mac; exact chip, RAM and disk confirmed on the configuration quote; provisioned on request | figment.so/mac-hosting |
| Figment Managed Build Mac | $249/month | One M-series Mac, CI setup, backups, monitoring, 30 minutes of monthly support | figment.so/mac-hosting |
| Figment virtual Intel macOS | $29/month | 2 vCPU, 8 GiB RAM, 80 GiB disk, no GPU acceleration, no audio; runs Intel-compatible Xcode (26 or earlier) | figment.so/mac-hosting |
| CloudMac monthly | $99.99/month | M4, 16 GB RAM, 256 GB SSD | cloudmac.org/pricing |
| CloudMac annual | $999/year ($83.25/month effective) | M4, 16 GB RAM, 256 GB SSD | cloudmac.org |
| MacStadium M4.S | $149/month | M4, 16 GB RAM, 256 GB SSD; support and 99.99% uptime claim on page | macstadium.com/pricing |
Honest framing: $95 at Figment is an entry M-series price, not a specific M4/16 GB/256 GB equivalent to CloudMac's $99.99 plan—the chip and RAM are set when you accept the quote. If a confirmed M4/16 GB on a 12-month commitment is what you want, CloudMac's $999/year works out to $83.25/month and beats Figment's monthly entry over a year on that specific config; CloudMac's larger-disk rows currently show "Fully reserved" with no next allocation date on the pricing page, so ask about 256 GB availability. Where Figment is directly useful is the managed path: the $249/month Managed Build Mac includes the CI setup, backups, monitoring, and 30 minutes of monthly support against your actual Fastfile, which the lower-priced vendors do not bundle in their listed plans. Taxes and fees are as stated in each actual offer.