From d4f4ad4c8dbb8948a1a63503b783335c725b9818 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sat, 4 Apr 2026 12:39:22 -0400 Subject: [PATCH 1/7] ci: add tvos build smoke test --- .github/workflows/ci.yml | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abb9644..33160b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,7 +141,42 @@ jobs: with: xcode-version: ${{ env.XCODE_VERSION }} - - name: Build example for iOS run: | yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" + + build-tvos: + runs-on: macos-latest + + env: + XCODE_VERSION: 26 + LANG: en_US.UTF-8 + LC_ALL: en_US.UTF-8 + RCT_USE_RN_DEP: 1 + RCT_USE_PREBUILT_RNCORE: 1 + + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Setup + uses: ./.github/actions/setup + + - name: Use appropriate Xcode version + uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 + with: + xcode-version: ${{ env.XCODE_VERSION }} + + - name: Build smoke-test tvOS app with local package + run: | + npx create-expo-app@latest tvos-smoke -e with-router-tv --yes + cd tvos-smoke + yarn add file:.. + npm run prebuild:tv + xcodebuild \ + -workspace ios/*.xcworkspace \ + -scheme tvossmoke \ + -configuration Debug \ + -sdk appletvsimulator \ + -destination 'generic/platform=tvOS Simulator' \ + build From 87a454ce72240ee00265aec9bc0df91872412519 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sat, 4 Apr 2026 13:12:01 -0400 Subject: [PATCH 2/7] ci: build tvos from example app --- .github/workflows/ci.yml | 14 ++------------ example/app.json | 5 ++++- example/package.json | 5 ++++- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33160b3..0a02aad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -167,16 +167,6 @@ jobs: with: xcode-version: ${{ env.XCODE_VERSION }} - - name: Build smoke-test tvOS app with local package + - name: Build example for tvOS run: | - npx create-expo-app@latest tvos-smoke -e with-router-tv --yes - cd tvos-smoke - yarn add file:.. - npm run prebuild:tv - xcodebuild \ - -workspace ios/*.xcworkspace \ - -scheme tvossmoke \ - -configuration Debug \ - -sdk appletvsimulator \ - -destination 'generic/platform=tvOS Simulator' \ - build + yarn workspace react-native-ease-example build:tvos diff --git a/example/app.json b/example/app.json index 0596f32..806af06 100644 --- a/example/app.json +++ b/example/app.json @@ -16,7 +16,8 @@ { "root": "./app" } - ] + ], + "@react-native-tvos/config-tv" ], "web": { "bundler": "metro", @@ -26,8 +27,10 @@ "platforms": [ "ios", "android", + "tvos", "web" ], + "isTV": false, "android": { "package": "com.janic.easeexample", "adaptiveIcon": { diff --git a/example/package.json b/example/package.json index 7d05adc..663f2b0 100644 --- a/example/package.json +++ b/example/package.json @@ -9,11 +9,14 @@ "start": "expo start", "web": "expo start --web", "prebuild": "expo prebuild", + "prebuild:tv": "EXPO_TV=1 expo prebuild --clean", "build:android": "expo prebuild --platform android --clean && cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a", - "build:ios": "expo prebuild --platform ios --clean && xcodebuild -workspace ios/Ease.xcworkspace -scheme Ease -configuration Debug -sdk iphonesimulator -arch x86_64 build" + "build:ios": "expo prebuild --platform ios --clean && xcodebuild -workspace ios/Ease.xcworkspace -scheme Ease -configuration Debug -sdk iphonesimulator -arch x86_64 build", + "build:tvos": "yarn prebuild:tv && xcodebuild -workspace ios/Ease.xcworkspace -scheme Ease -configuration Debug -sdk appletvsimulator -destination 'generic/platform=tvOS Simulator' build" }, "dependencies": { "@expo/metro-runtime": "~55.0.6", + "@react-native-tvos/config-tv": "^0.1.7", "expo": "~55.0.0", "expo-constants": "^55.0.7", "expo-linking": "^55.0.7", From 95ea2febade25837e2bed74f0b1343a2324116dc Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sat, 4 Apr 2026 13:19:03 -0400 Subject: [PATCH 3/7] ci: use Expo TV config plugin setup --- example/package.json | 2 +- yarn.lock | 74 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/example/package.json b/example/package.json index 663f2b0..6fe9d95 100644 --- a/example/package.json +++ b/example/package.json @@ -16,7 +16,6 @@ }, "dependencies": { "@expo/metro-runtime": "~55.0.6", - "@react-native-tvos/config-tv": "^0.1.7", "expo": "~55.0.0", "expo-constants": "^55.0.7", "expo-linking": "^55.0.7", @@ -40,6 +39,7 @@ "@react-native-community/cli": "20.0.0", "@react-native-community/cli-platform-android": "20.0.0", "@react-native-community/cli-platform-ios": "20.0.0", + "@react-native-tvos/config-tv": "^0.1.6", "@react-native/babel-preset": "0.83.0", "@react-native/metro-config": "0.83.0", "@react-native/typescript-config": "0.83.0", diff --git a/yarn.lock b/yarn.lock index e15edc5..8c719c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4319,6 +4319,13 @@ __metadata: languageName: node linkType: hard +"@isaacs/cliui@npm:^9.0.0": + version: 9.0.0 + resolution: "@isaacs/cliui@npm:9.0.0" + checksum: 10c0/971063b7296419f85053dacd0a0285dcadaa3dfc139228b23e016c1a9848121ad4aa5e7fcca7522062014e1eb6239a7424188b9f2cba893a79c90aae5710319c + languageName: node + linkType: hard + "@isaacs/fs-minipass@npm:^4.0.0": version: 4.0.1 resolution: "@isaacs/fs-minipass@npm:4.0.1" @@ -5649,6 +5656,18 @@ __metadata: languageName: node linkType: hard +"@react-native-tvos/config-tv@npm:^0.1.6": + version: 0.1.6 + resolution: "@react-native-tvos/config-tv@npm:0.1.6" + dependencies: + getenv: "npm:^1.0.0" + glob: "npm:^11.0.0" + peerDependencies: + expo: ">=52.0.0" + checksum: 10c0/cc6dfc3358c6cc96b1cd56d3bd76ff4108db60e69b7b288de32bf5bc723cf556383b7ffce4acd46c26ea6397f5cae61adfa8f885f42fa35435c85564ef21383d + languageName: node + linkType: hard + "@react-native/assets-registry@npm:0.83.0": version: 0.83.0 resolution: "@react-native/assets-registry@npm:0.83.0" @@ -8892,6 +8911,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^5.0.5": + version: 5.0.5 + resolution: "brace-expansion@npm:5.0.5" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/4d238e14ed4f5cc9c07285550a41cef23121ca08ba99fa9eb5b55b580dcb6bf868b8210aa10526bdc9f8dc97f33ca2a7259039c4cc131a93042beddb424c48e3 + languageName: node + linkType: hard + "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -12615,7 +12643,7 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^3.1.0": +"foreground-child@npm:^3.1.0, foreground-child@npm:^3.3.1": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" dependencies: @@ -12931,6 +12959,13 @@ __metadata: languageName: node linkType: hard +"getenv@npm:^1.0.0": + version: 1.0.0 + resolution: "getenv@npm:1.0.0" + checksum: 10c0/9661c5996c7622e12eab1d23448474ae51dbec6f8862eed903ebaa864dcd332895441c23d962e3ff5c180a9e3dff6cb1f569a115e1447db4acb52af2d880d655 + languageName: node + linkType: hard + "getenv@npm:^2.0.0": version: 2.0.0 resolution: "getenv@npm:2.0.0" @@ -13034,6 +13069,22 @@ __metadata: languageName: node linkType: hard +"glob@npm:^11.0.0": + version: 11.1.0 + resolution: "glob@npm:11.1.0" + dependencies: + foreground-child: "npm:^3.3.1" + jackspeak: "npm:^4.1.1" + minimatch: "npm:^10.1.1" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^2.0.0" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/1ceae07f23e316a6fa74581d9a74be6e8c2e590d2f7205034dd5c0435c53f5f7b712c2be00c3b65bf0a49294a1c6f4b98cd84c7637e29453b5aa13b79f1763a2 + languageName: node + linkType: hard + "glob@npm:^13.0.0": version: 13.0.6 resolution: "glob@npm:13.0.6" @@ -14836,6 +14887,15 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^4.1.1": + version: 4.2.3 + resolution: "jackspeak@npm:4.2.3" + dependencies: + "@isaacs/cliui": "npm:^9.0.0" + checksum: 10c0/b5c0c414f1607c2aa0597f4bf2c03b8443897fccd5fd3c2b3e4f77d556b2bc7c3d3413828ba91e0789f6fb40ad90242f7f89fb20aee9e9d705bc1681f7564f67 + languageName: node + linkType: hard + "jest-changed-files@npm:30.3.0": version: 30.3.0 resolution: "jest-changed-files@npm:30.3.0" @@ -18000,6 +18060,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.1.1": + version: 10.2.5 + resolution: "minimatch@npm:10.2.5" + dependencies: + brace-expansion: "npm:^5.0.5" + checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd + languageName: node + linkType: hard + "minimatch@npm:^10.2.2": version: 10.2.4 resolution: "minimatch@npm:10.2.4" @@ -19102,7 +19171,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^2.0.2": +"path-scurry@npm:^2.0.0, path-scurry@npm:^2.0.2": version: 2.0.2 resolution: "path-scurry@npm:2.0.2" dependencies: @@ -20643,6 +20712,7 @@ __metadata: "@react-native-community/cli": "npm:20.0.0" "@react-native-community/cli-platform-android": "npm:20.0.0" "@react-native-community/cli-platform-ios": "npm:20.0.0" + "@react-native-tvos/config-tv": "npm:^0.1.6" "@react-native/babel-preset": "npm:0.83.0" "@react-native/metro-config": "npm:0.83.0" "@react-native/typescript-config": "npm:0.83.0" From 153ba13b30f7131aa66057b82ce24806704a3aea Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 5 Apr 2026 03:48:09 -0400 Subject: [PATCH 4/7] ci: validate tvos with temp Expo app --- .github/workflows/ci.yml | 25 ++++++++++++-- example/app.json | 5 +-- example/package.json | 5 +-- yarn.lock | 74 ++-------------------------------------- 4 files changed, 27 insertions(+), 82 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a02aad..f9de92b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -167,6 +167,27 @@ jobs: with: xcode-version: ${{ env.XCODE_VERSION }} - - name: Build example for tvOS + - name: Pack library + run: yarn pack -o react-native-ease.tgz + + - name: Create tvOS smoke test app + run: | + npx create-expo-app@latest tvos-smoke -e with-router-tv --yes + cd tvos-smoke + yarn add file:../react-native-ease.tgz + + - name: Prebuild tvOS app + working-directory: tvos-smoke + run: | + npm run prebuild:tv + + - name: Build Apple TV simulator app + working-directory: tvos-smoke run: | - yarn workspace react-native-ease-example build:tvos + xcodebuild \ + -workspace ios/*.xcworkspace \ + -scheme tvossmoke \ + -configuration Debug \ + -sdk appletvsimulator \ + -destination 'generic/platform=tvOS Simulator' \ + build diff --git a/example/app.json b/example/app.json index 806af06..0596f32 100644 --- a/example/app.json +++ b/example/app.json @@ -16,8 +16,7 @@ { "root": "./app" } - ], - "@react-native-tvos/config-tv" + ] ], "web": { "bundler": "metro", @@ -27,10 +26,8 @@ "platforms": [ "ios", "android", - "tvos", "web" ], - "isTV": false, "android": { "package": "com.janic.easeexample", "adaptiveIcon": { diff --git a/example/package.json b/example/package.json index 6fe9d95..7d05adc 100644 --- a/example/package.json +++ b/example/package.json @@ -9,10 +9,8 @@ "start": "expo start", "web": "expo start --web", "prebuild": "expo prebuild", - "prebuild:tv": "EXPO_TV=1 expo prebuild --clean", "build:android": "expo prebuild --platform android --clean && cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a", - "build:ios": "expo prebuild --platform ios --clean && xcodebuild -workspace ios/Ease.xcworkspace -scheme Ease -configuration Debug -sdk iphonesimulator -arch x86_64 build", - "build:tvos": "yarn prebuild:tv && xcodebuild -workspace ios/Ease.xcworkspace -scheme Ease -configuration Debug -sdk appletvsimulator -destination 'generic/platform=tvOS Simulator' build" + "build:ios": "expo prebuild --platform ios --clean && xcodebuild -workspace ios/Ease.xcworkspace -scheme Ease -configuration Debug -sdk iphonesimulator -arch x86_64 build" }, "dependencies": { "@expo/metro-runtime": "~55.0.6", @@ -39,7 +37,6 @@ "@react-native-community/cli": "20.0.0", "@react-native-community/cli-platform-android": "20.0.0", "@react-native-community/cli-platform-ios": "20.0.0", - "@react-native-tvos/config-tv": "^0.1.6", "@react-native/babel-preset": "0.83.0", "@react-native/metro-config": "0.83.0", "@react-native/typescript-config": "0.83.0", diff --git a/yarn.lock b/yarn.lock index 8c719c7..e15edc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4319,13 +4319,6 @@ __metadata: languageName: node linkType: hard -"@isaacs/cliui@npm:^9.0.0": - version: 9.0.0 - resolution: "@isaacs/cliui@npm:9.0.0" - checksum: 10c0/971063b7296419f85053dacd0a0285dcadaa3dfc139228b23e016c1a9848121ad4aa5e7fcca7522062014e1eb6239a7424188b9f2cba893a79c90aae5710319c - languageName: node - linkType: hard - "@isaacs/fs-minipass@npm:^4.0.0": version: 4.0.1 resolution: "@isaacs/fs-minipass@npm:4.0.1" @@ -5656,18 +5649,6 @@ __metadata: languageName: node linkType: hard -"@react-native-tvos/config-tv@npm:^0.1.6": - version: 0.1.6 - resolution: "@react-native-tvos/config-tv@npm:0.1.6" - dependencies: - getenv: "npm:^1.0.0" - glob: "npm:^11.0.0" - peerDependencies: - expo: ">=52.0.0" - checksum: 10c0/cc6dfc3358c6cc96b1cd56d3bd76ff4108db60e69b7b288de32bf5bc723cf556383b7ffce4acd46c26ea6397f5cae61adfa8f885f42fa35435c85564ef21383d - languageName: node - linkType: hard - "@react-native/assets-registry@npm:0.83.0": version: 0.83.0 resolution: "@react-native/assets-registry@npm:0.83.0" @@ -8911,15 +8892,6 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^5.0.5": - version: 5.0.5 - resolution: "brace-expansion@npm:5.0.5" - dependencies: - balanced-match: "npm:^4.0.2" - checksum: 10c0/4d238e14ed4f5cc9c07285550a41cef23121ca08ba99fa9eb5b55b580dcb6bf868b8210aa10526bdc9f8dc97f33ca2a7259039c4cc131a93042beddb424c48e3 - languageName: node - linkType: hard - "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -12643,7 +12615,7 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^3.1.0, foreground-child@npm:^3.3.1": +"foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" dependencies: @@ -12959,13 +12931,6 @@ __metadata: languageName: node linkType: hard -"getenv@npm:^1.0.0": - version: 1.0.0 - resolution: "getenv@npm:1.0.0" - checksum: 10c0/9661c5996c7622e12eab1d23448474ae51dbec6f8862eed903ebaa864dcd332895441c23d962e3ff5c180a9e3dff6cb1f569a115e1447db4acb52af2d880d655 - languageName: node - linkType: hard - "getenv@npm:^2.0.0": version: 2.0.0 resolution: "getenv@npm:2.0.0" @@ -13069,22 +13034,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^11.0.0": - version: 11.1.0 - resolution: "glob@npm:11.1.0" - dependencies: - foreground-child: "npm:^3.3.1" - jackspeak: "npm:^4.1.1" - minimatch: "npm:^10.1.1" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^2.0.0" - bin: - glob: dist/esm/bin.mjs - checksum: 10c0/1ceae07f23e316a6fa74581d9a74be6e8c2e590d2f7205034dd5c0435c53f5f7b712c2be00c3b65bf0a49294a1c6f4b98cd84c7637e29453b5aa13b79f1763a2 - languageName: node - linkType: hard - "glob@npm:^13.0.0": version: 13.0.6 resolution: "glob@npm:13.0.6" @@ -14887,15 +14836,6 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^4.1.1": - version: 4.2.3 - resolution: "jackspeak@npm:4.2.3" - dependencies: - "@isaacs/cliui": "npm:^9.0.0" - checksum: 10c0/b5c0c414f1607c2aa0597f4bf2c03b8443897fccd5fd3c2b3e4f77d556b2bc7c3d3413828ba91e0789f6fb40ad90242f7f89fb20aee9e9d705bc1681f7564f67 - languageName: node - linkType: hard - "jest-changed-files@npm:30.3.0": version: 30.3.0 resolution: "jest-changed-files@npm:30.3.0" @@ -18060,15 +18000,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^10.1.1": - version: 10.2.5 - resolution: "minimatch@npm:10.2.5" - dependencies: - brace-expansion: "npm:^5.0.5" - checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd - languageName: node - linkType: hard - "minimatch@npm:^10.2.2": version: 10.2.4 resolution: "minimatch@npm:10.2.4" @@ -19171,7 +19102,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^2.0.0, path-scurry@npm:^2.0.2": +"path-scurry@npm:^2.0.2": version: 2.0.2 resolution: "path-scurry@npm:2.0.2" dependencies: @@ -20712,7 +20643,6 @@ __metadata: "@react-native-community/cli": "npm:20.0.0" "@react-native-community/cli-platform-android": "npm:20.0.0" "@react-native-community/cli-platform-ios": "npm:20.0.0" - "@react-native-tvos/config-tv": "npm:^0.1.6" "@react-native/babel-preset": "npm:0.83.0" "@react-native/metro-config": "npm:0.83.0" "@react-native/typescript-config": "npm:0.83.0" From acc0b52ca9665a155e786f83c18d8589681d2430 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 5 Apr 2026 03:58:42 -0400 Subject: [PATCH 5/7] ci: make Expo TV scaffold non-interactive --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9de92b..a4f9e92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -171,8 +171,10 @@ jobs: run: yarn pack -o react-native-ease.tgz - name: Create tvOS smoke test app + env: + CI: '1' run: | - npx create-expo-app@latest tvos-smoke -e with-router-tv --yes + npx create-expo-app@latest tvos-smoke --template with-router-tv --yes cd tvos-smoke yarn add file:../react-native-ease.tgz From 5673b5ef35a92922669d8c03902b5c3cb33f01c9 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 5 Apr 2026 04:11:20 -0400 Subject: [PATCH 6/7] ci: add Stripe-style Expo tvOS integration test --- .github/workflows/ci.yml | 27 +----------- scripts/test-expo-tv-project.sh | 76 +++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 25 deletions(-) create mode 100755 scripts/test-expo-tv-project.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4f9e92..9deb377 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -167,29 +167,6 @@ jobs: with: xcode-version: ${{ env.XCODE_VERSION }} - - name: Pack library - run: yarn pack -o react-native-ease.tgz - - - name: Create tvOS smoke test app - env: - CI: '1' - run: | - npx create-expo-app@latest tvos-smoke --template with-router-tv --yes - cd tvos-smoke - yarn add file:../react-native-ease.tgz - - - name: Prebuild tvOS app - working-directory: tvos-smoke - run: | - npm run prebuild:tv - - - name: Build Apple TV simulator app - working-directory: tvos-smoke + - name: Run tvOS Expo integration build run: | - xcodebuild \ - -workspace ios/*.xcworkspace \ - -scheme tvossmoke \ - -configuration Debug \ - -sdk appletvsimulator \ - -destination 'generic/platform=tvOS Simulator' \ - build + bash ./scripts/test-expo-tv-project.sh diff --git a/scripts/test-expo-tv-project.sh b/scripts/test-expo-tv-project.sh new file mode 100755 index 0000000..447474d --- /dev/null +++ b/scripts/test-expo-tv-project.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +set -euo pipefail +IFS=$'\n\t' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +PROJECT_NAME="EaseExpoTVTest" +EXPO_SDK_VERSION="55" + +export EXPO_NO_TELEMETRY=1 +export CI=1 +export LANG=${LANG:-en_US.UTF-8} +export LC_ALL=${LC_ALL:-en_US.UTF-8} + +cd "$REPO_ROOT" + +echo "Packing local react-native-ease package" +PACK_OUTPUT="$(npm pack)" +TARBALL_FILENAME="$(echo "$PACK_OUTPUT" | tail -n 1 | tr -d '\r\n')" +TARBALL_PATH="$REPO_ROOT/$TARBALL_FILENAME" + +TMP_DIR="$(mktemp -d)" +PROJECT_DIR="$TMP_DIR/$PROJECT_NAME" + +cleanup() { + rm -f "$TARBALL_PATH" + rm -rf "$TMP_DIR" +} +trap cleanup EXIT + +echo "Creating Expo project ($PROJECT_NAME) targeting SDK $EXPO_SDK_VERSION" +cd "$TMP_DIR" +npx create-expo-app@latest "$PROJECT_NAME" --template "default@$EXPO_SDK_VERSION" --yes + +cd "$PROJECT_DIR" + +echo "Installing TV dependencies" +npx expo install react-native@npm:react-native-tvos@0.83.4-1 expo-dev-client @react-native-tvos/config-tv -- --dev + +echo "Installing local tarball" +npm install "$TARBALL_PATH" + +APP_JSON_PATH="$PROJECT_DIR/app.json" +node <<'NODE' +const fs = require('fs'); +const path = process.env.APP_JSON_PATH; +const json = JSON.parse(fs.readFileSync(path, 'utf8')); +json.expo = json.expo || {}; +json.expo.plugins = json.expo.plugins || []; +if (!json.expo.plugins.includes('@react-native-tvos/config-tv')) { + json.expo.plugins.push('@react-native-tvos/config-tv'); +} +json.expo.install = json.expo.install || {}; +const exclude = new Set(json.expo.install.exclude || []); +exclude.add('react-native'); +json.expo.install.exclude = Array.from(exclude); +fs.writeFileSync(path, JSON.stringify(json, null, 2) + '\n'); +NODE + +echo "Running Expo TV prebuild" +EXPO_TV=1 npx expo prebuild --clean --platform ios + +cd ios + +echo "Building tvOS app" +xcodebuild \ + -workspace "$PROJECT_NAME.xcworkspace" \ + -configuration Debug \ + -scheme "$PROJECT_NAME" \ + -sdk appletvsimulator \ + -destination 'generic/platform=tvOS Simulator' \ + -derivedDataPath "$TMP_DIR/DerivedData" \ + build + +echo "tvOS Expo integration build completed successfully." From 787f32aa4012e201107a1f25b644887f5f6e0d1b Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 5 Apr 2026 04:15:43 -0400 Subject: [PATCH 7/7] ci: export app json path for tvOS patcher --- scripts/test-expo-tv-project.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-expo-tv-project.sh b/scripts/test-expo-tv-project.sh index 447474d..5c47dd0 100755 --- a/scripts/test-expo-tv-project.sh +++ b/scripts/test-expo-tv-project.sh @@ -42,7 +42,7 @@ echo "Installing local tarball" npm install "$TARBALL_PATH" APP_JSON_PATH="$PROJECT_DIR/app.json" -node <<'NODE' +APP_JSON_PATH="$APP_JSON_PATH" node <<'NODE' const fs = require('fs'); const path = process.env.APP_JSON_PATH; const json = JSON.parse(fs.readFileSync(path, 'utf8'));