@kromatv/react-native-tv
v0.1.0-alpha.2
Published
One setup for an Expo app on every TV: Apple TV, Android TV, Samsung Tizen and LG webOS behind one Metro call, one app.json entry and the Expo CLI.
Maintainers
Readme
@kromatv/react-native-tv
One setup for an Expo app on every TV. Apple TV and Android TV come from
react-native-tvos,
Samsung Tizen from
@kromatv/react-native-tizen
and LG webOS from
@kromatv/react-native-webos.
This package is the one dependency an app adds for all of them. It holds no
platform code: it brings the Samsung and LG packages and react-native-tvos'
config plugin, and sets them up together.
Install
npm install @kromatv/react-native-tvThat is every TV: @kromatv/react-native-tizen,
@kromatv/react-native-webos and @react-native-tvos/config-tv come with it.
The app itself still runs on react-native-tvos, as an Apple TV or Android TV
app does. Building for a TV needs that platform's toolchain: the README of
each platform package says what to install.
An app that lists a platform package itself keeps its own copy, which is how to pin a version.
A platform's own API and commands
What one platform has and the others do not is imported under its name:
import { SmartHubPreview } from '@kromatv/react-native-tv/tizen/preview';
import { MicButton } from '@kromatv/react-native-tv/tizen/mic-button';Each is the module of the same name in the platform package, here
@kromatv/react-native-tizen/preview, whose README documents it.
The command line of a platform is under its name too:
npx rn-tv tizen simulator run # rn-tizen simulator run
npx rn-tv webos package # rn-webos package
npx rn-tv tizen doctorOne entry in app.json
{
"expo": {
"plugins": [
[
"@kromatv/react-native-tv",
{
"package": "tv.example.app",
"locales": ["fr", "en"],
"tvos": { "androidTVRequired": true },
"tizen": { "preview": { "refreshMinutes": 30 } }
}
]
]
}
}| Key | Goes to |
|---|---|
| package, version, icon, locales | every TV platform package the app has |
| a platform's name: tizen, webos | that platform's own props, over the shared ones |
| tvos | @react-native-tvos/config-tv, for Apple TV and Android TV, with isTV on, so no script needs EXPO_TV=1 |
Each platform package still validates its own props, and its command reads them as if the app had listed its plugin itself. A platform the app does list itself keeps that entry.
The entry also sets Metro up. Expo is handed a Metro config that is the app's
own, or Expo's default when the app has none, with every TV platform added. An
app with this entry needs no change in metro.config, and none at all for TV.
Metro, by hand
An app that does not list the plugin wraps its Metro config once:
// metro.config.mjs
import { getDefaultConfig } from 'expo/metro-config';
import { withTV } from '@kromatv/react-native-tv/metro';
export default withTV(getDefaultConfig(import.meta.dirname));withTV teaches Metro the platform of every TV platform package the app has,
and leaves alone a platform the config knows already. Calling it
in an app that also lists the plugin changes nothing.
Run on a TV
npx rn-tv run:tizen --device 192.168.1.50
npx rn-tv run:webos --device 192.168.1.51
npx rn-tv platformsrun:<platform> is the platform's own run, with its own options:
rn-tv run:tizen --help prints the help of rn-tizen run. It is short for
rn-tv tizen run.
The same commands in Expo CLI
Expo CLI has run:ios and run:android and no way for a package to add a
command. rn-tv expo-patch adds one, as a patch of @expo/cli that the app
commits:
npx rn-tv expo-patch
npx expo run:tizen --device 192.168.1.50
npx expo run:webos
npx expo run tizenThe patch is a few lines in the file that holds Expo's command table. They load
this package's commands when the app in the current directory depends on it,
and do nothing anywhere else. Expo's own commands are untouched, and
npx expo --help lists the new ones.
With Bun, pnpm and Yarn 2 or later it is written with the package manager's own patch feature, and every install applies it.
rn-tv expo-patchnames the files to commit:| Manager | Patch file | Entry | |---|---|---| | Bun |
patches/@expo%2Fcli@<version>.patch|patchedDependenciesinpackage.json| | pnpm |patches/@expo__cli@<version>.patch|patchedDependenciesinpnpm-workspace.yaml| | Yarn 2 and later |.yarn/patches/@expo-cli-npm-<version>-<hash>.patch|resolutionsinpackage.json|npm and Yarn 1 have no patch feature. There
rn-tv expo-patchwrites the lines into the installed file and adds itself to the app'spostinstallscript, so an install puts them back. Commitpackage.json. In a workspace, an install from the root runs the root'spostinstallonly: runrn-tv expo-patchfrom the app after it.It belongs to one version of
@expo/cli. After an Expo upgrade that changes it, runrn-tv expo-patchagain: it removes the patch it wrote for the old version and writes the new one. Two managers need more:- pnpm refuses to install while a patch is for a version that is gone, so
remove it before the upgrade:
pnpm patch-remove @expo/cli@<old version>.rn-tv expo-patchprints that command. - npm runs no
postinstallafternpm install <package>, so an upgrade made that way leaves Expo CLI unpatched until the nextnpm installorrn-tv expo-patch.
- pnpm refuses to install while a patch is for a version that is gone, so
remove it before the upgrade:
Without it nothing is lost:
rn-tv run:<platform>does the same.
One key in expo start
With this package in an app, npx expo start has one t for every TV:
| Key | Does | |---|---| | t | Opens the app where this project opened last. With nothing remembered, an app with one platform opens on that platform's TV used last, and an app with several asks | | shift+t | Lists the TVs and simulators of every platform in one list, and opens the app on the one whose number you press; Esc cancels |
A platform package the app pins to a version from before it registered with
this package keeps its own t.
What a platform package declares
A package is a TV platform when its package.json says so. One this package
does not bring joins by being a dependency of the app:
{
"bin": { "rn-webos": "dist/cli/main.js" },
"reactNativeTvPlatform": {
"metro": "./metro",
"platform": "webos",
"cli": "rn-webos"
}
}docs/platform-packages.md has the contract.
Not there yet
initanddoctorcommands: an app is set up by hand, as above.expo start --tizenand the like, to open on a TV as the dev server starts.- The Expo CLI patch on Windows, and with pnpm before 11: neither has been run.
- With npm or Yarn 1 in a workspace, the
postinstallof the workspace root.rn-tv expo-patchadds itself to the app's script only.
