NewiPhone Duo, live in your browser. Try it →
Vibeview
Pricing
Cloud Builds · TV

Build an Apple TV app without a Mac

Rokas Kašinskas — Co-founder, VibeViewPublished 2026-10-07Updated 2026-10-07

A tvOS app has every Mac dependency an iPhone app has: Xcode, the Apple TV simulator, a distribution certificate in a keychain, and Transporter or Xcode’s Organizer for the upload. On top of that it needs its own provisioning profile, because Apple’s profiles are platform-specific. VibeView cloud builds cover the whole chain from Windows, Linux or macOS. Your machine runs the CLI and nothing else.

This guide takes a react-native-tvos project from source to TestFlight, then does the same for Android TV, so one repository ships to both TV stores. If you’d rather watch it happen, a coding agent did this whole flow in 46 minutes: An AI agent shipped an Apple TV and Android TV app.

What you need

  • A VibeView account and the CLI: npm install -g vibeview && vibeview login
  • A React Native TV project built on react-native-tvos, either bare or Expo with the @react-native-tvos/config-tv plugin
  • For TestFlight: an Apple Developer account, an App Store Connect API key, and the app record created in App Store Connect with tvOS as its platform

Every plan includes cloud builds each month; builds beyond your plan’s allowance draw from usage credit. See pricing.

Step 1: a tvOS simulator build

VibeView doesn’t suggest a tvOS build command, because TV schemes vary too much to guess: some projects build the app’s own scheme, older bare templates use a separate MyApp-tvOS scheme. You write the command once and vibeview.json keeps it. For an Expo project with config-tv, where prebuild generates the TV project when EXPO_TV is set:

{
  "defaultPlatform": "tvos",
  "platforms": {
    "tvos": {
      "build": {
        "command": "npm ci && npx expo prebuild --platform ios && xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk appletvsimulator -derivedDataPath ios/build CODE_SIGNING_ALLOWED=NO",
        "artifact": "ios/build/Build/Products/Debug-appletvsimulator/*.app",
        "env": { "EXPO_TV": "1" }
      }
    }
  }
}

For a bare project, drop the prebuild leg and use your own workspace and TV scheme. Either way the important parts are -sdk appletvsimulator and an artifact path under Debug-appletvsimulator. Then:

vibeview build --cloud --platform tvos

The CLI uploads your source (git-tracked files plus untracked files .gitignore doesn’t exclude; never node_modules or ios/Pods) and streams the Xcode log. The first succeeded build creates the app in VibeView from the binary and saves its appId to vibeview.json.

Step 2: run it on a cloud Apple TV

Open the build’s page and choose Run this build, or run vibeview dev --platform tvos to work on it with Metro and Fast Refresh. The app opens on an Apple TV simulator in your browser, where your arrow keys move the d-pad and Enter selects. This is where you check focus: that moving down lands on the right row, that back returns focus to the poster you came from. Testing tvOS focus navigation covers that in detail.

Step 3: a signed tvOS build

A production build signs a tvOS .ipa for the App Store. It can’t run on a simulator, so it appears on the Builds page with a Download action rather than in Build history.

  1. Connect your Apple account once. In App Store Connect under Users and Access → Integrations, create a team API key with the App Manager or Admin role and download the .p8 file. Store it:

    vibeview credentials asc-key add --key-id <KEY_ID> --issuer-id <ISSUER_ID> --file AuthKey_<KEY_ID>.p8
  2. Generate the tvOS credential.

    vibeview credentials generate --platform tvos --name tv-release --app <app-id>

    VibeView reuses the Apple Distribution certificate it already made for your team (for example, for your iOS app) or creates one, registers the bundle id if needed, and issues a tvOS App Store profile. Prefer your own files? Upload the same .p12 you use for iOS with your tvOS profile: vibeview credentials add --platform tvos --file cert.p12 --profile app-tvos.mobileprovision.

  3. Add the release command. React Native TV projects use CocoaPods, and a provisioning profile passed on the xcodebuild command line applies to every Pod target and fails the archive. So set manual signing on the app target in the project itself (an Expo project does it with a config plugin; Marquee has a working one), and pass only the signing identity on the command line:

    {
      "platforms": {
        "tvos": {
          "appId": "my-tv-app-abc123",
          "build": {
            "command": "...",
            "artifact": "ios/build/Build/Products/Debug-appletvsimulator/*.app",
            "env": { "EXPO_TV": "1" },
            "productionCommand": "npm ci && npx expo prebuild --platform ios && xcodebuild archive -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Release -destination generic/platform=tvOS -archivePath ios/build/MyApp.xcarchive ${VIBEVIEW_CODE_SIGN_IDENTITY:+\"CODE_SIGN_IDENTITY=$VIBEVIEW_CODE_SIGN_IDENTITY\"} && xcodebuild -exportArchive -archivePath ios/build/MyApp.xcarchive -exportPath ios/build -exportOptionsPlist \"$VIBEVIEW_EXPORT_OPTIONS_PLIST\"",
            "productionArtifact": "ios/build/*.ipa",
            "autoIncrement": true
          }
        }
      }
    }

    VibeView writes the export options file from your profile during the build; you never author it. App Signing explains every part of this command.

  4. Build.

    vibeview build --cloud --production --platform tvos

    With autoIncrement on, each production build gets the next build number as VIBEVIEW_BUILD_NUMBER; wire it into your app config once (how). Because an App Store Connect key is stored, the first allocation checks the app’s existing builds in App Store Connect and starts above the highest one, so an app that’s already in TestFlight usually needs no manual seeding.

Step 4: upload the Apple TV app to TestFlight

Create the app record in App Store Connect first (My Apps → + → New App, platform tvOS, your bundle id). Apple only accepts uploads for apps that exist there. Then check and submit:

vibeview submit --check --platform tvos --bundle-id com.example.mytvapp
vibeview submit --platform tvos --latest

The CLI streams the upload and exits once Apple accepts it. The build shows up in TestFlight after Apple’s processing, usually 10 to 15 minutes later. Listing, screenshots and App Review stay in App Store Connect.

The same project on Android TV

The Android half of a react-native-tvos project builds with --platform androidtv. A debug build runs on a cloud Android TV emulator; keep both x86 and x86_64 native code in it so it runs on every Android TV device.

{
  "platforms": {
    "androidtv": {
      "build": {
        "command": "npm ci && npx expo prebuild --platform android --no-install && cd android && ./gradlew assembleDebug",
        "artifact": "android/app/build/outputs/apk/debug/*.apk",
        "env": { "EXPO_TV": "1" },
        "productionCommand": "npm ci && npx expo prebuild --platform android --no-install && cd android && ./gradlew bundleRelease",
        "productionArtifact": "android/app/build/outputs/bundle/release/*.aab"
      }
    }
  }
}

Android TV needs no credential of its own: production builds sign with your Android keystore, so vibeview credentials generate --platform android --name release covers phone and TV. Add the guarded Gradle signing block from App Signing, then:

vibeview build --cloud --production --platform androidtv
vibeview submit --platform androidtv --latest --track internal

vibeview build --cloud --platform all builds every configured platform at once, so Apple TV and Android TV come out of one command. The Android cloud build guide covers the Play service account setup.

Roku is the exception. A Roku channel has no compile step and can’t be cloud-built: package the channel .zip and upload it with vibeview build --platform roku (without --cloud). See Test a Roku channel in your browser.

Troubleshooting

  • The tvOS archive fails with “does not support provisioning profiles”. A profile reached the Pod targets through the command line. Move manual signing into the app target and keep only CODE_SIGN_IDENTITY on the archive command.
  • “Apple doesn’t know this app yet”. The App Store Connect record is missing, was created for iOS instead of tvOS, or uses a different bundle id. vibeview submit --check catches this before you build.
  • Apple refuses a duplicate build number. Turn on autoIncrement, or seed the counter with vibeview versions set --app <app-id> --platform tvos <number>.
  • The Android TV build installs on some TV emulators but not others. The build is missing x86 or x86_64 native code.

Frequently asked questions

Frequently asked questions

Can I build a tvOS app without a Mac?

Yes. The build runs on VibeView’s macOS builders, the Apple TV simulator streams to your browser, the profile comes from Apple’s API through your App Store Connect key, and the TestFlight upload runs server-side. Nothing on your machine needs macOS.

Do I need a separate certificate for tvOS?

No. tvOS uses the same Apple Distribution certificate as iOS; only the provisioning profile differs. When you generate both, VibeView reuses the certificate and issues a second profile.

Does it work with a plain React Native project?

TV builds need react-native-tvos, the community fork that adds tvOS and Android TV support. Standard React Native doesn’t target tvOS.

Can a VibeView Apple TV run my signed TestFlight build?

No. A signed App Store build only installs on physical hardware. Test the simulator build from Step 1 on the cloud Apple TV, and use TestFlight for the hardware pass.

Next steps

Try it yourself

Open a live iOS simulator or Android emulator in your browser.

Start free