@react-native-tvos/config-tv 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @react-native-tvos/config-tv
2
+
3
+ Expo Config Plugin to auto-configure the native directories for TV development using the [React Native TV fork](https://github.com/react-native-tvos/react-native-tvos). The TV fork supports development for both phone (Android and iOS) and TV (Android TV and Apple TV), so the plugin can be used in a project that targets both phone and TV devices.
4
+
5
+ _Notes_:
6
+
7
+ - This is an experimental plugin, tested only against Expo 50 alpha packages.
8
+ - This package cannot be used in the "Expo Go" app because Expo Go does not support TV.
9
+ - Apple TV development will work with many of the commonly used SDK 50 packages, including `expo-updates`, but many Expo packages do not work on Apple TV and are not supported. In particular, `expo-dev-client`, `expo-dev-menu`, and `expo-dev-launcher` are not supported.
10
+
11
+ ## Expo installation
12
+
13
+ - First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
14
+
15
+ ```sh
16
+ npx expo install tv @react-native-tvos/config-tv
17
+ ```
18
+
19
+ After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
20
+
21
+ ```json
22
+ {
23
+ "expo": {
24
+ "plugins": ["@react-native-tvos/config-tv"]
25
+ }
26
+ }
27
+ ```
28
+
29
+ or
30
+
31
+ ```json
32
+ {
33
+ "expo": {
34
+ "plugins": [
35
+ [
36
+ "@react-native-tvos/config-tv",
37
+ {
38
+ "isTV": true,
39
+ "showVerboseWarnings": false
40
+ }
41
+ ]
42
+ ]
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ _Plugin parameters_:
50
+
51
+ - `isTV`: (optional boolean, default false) If true, prebuild should generate or modify Android and iOS files to build for TV (Android TV and Apple TV). If false, the default phone-appropriate files should be generated, and if existing files contain TV changes, they will be reverted. Setting the environment variable EXPO_TV to "true" or "1" will override this value and force a TV build.
52
+ - `showVerboseWarnings`: (optional boolean, default false) If true, verbose warnings will be shown during plugin execution.
53
+
54
+ _Warning_:
55
+
56
+ When this plugin is used to generate files in the iOS directory that build an Apple TV or Android TV app, your React Native dependency in `package.json` MUST be set to the React Native TV fork, as shown in the example below:
57
+
58
+ ```json
59
+ {
60
+ "dependencies": {
61
+ "react-native": "npm:react-native-tvos@^0.72.5-0"
62
+ }
63
+ }
64
+ ```
65
+
66
+ If this is not the case, the plugin will run successfully, but Cocoapods installation will fail, since React Native core repo does not support Apple TV. Android TV build will succeed, but will not contain native changes needed to correctly navigate the screen using a TV remote, and may have other problems.
67
+
68
+ _Warning_:
69
+
70
+ If you have already generated native directories for a phone build, and set `EXPO_TV` to "true" or "1" (or set the `isTV` plugin parameter to true), then running `npx expo prebuild` will lead to errors when Cocoapods installation is run again. You will need to remove `ios/Pods` and `ios/Podfile.lock` before running Cocoapods installation.
71
+
72
+ To avoid this issue, it is strongly recommended to run `npx expo prebuild --clean` if changing the `EXPO_TV` environment variable or the `isTV` plugin parameter.
package/app.plugin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require("./build/withTV");
@@ -0,0 +1,13 @@
1
+ export type ConfigData = {
2
+ /**
3
+ * If true, prebuild should generate Android and iOS files for TV (Android TV and Apple TV).
4
+ * If false, the default phone-appropriate files should be generated.
5
+ * Setting the environment variable EXPO_TV to "true" or "1" will override
6
+ * this value.
7
+ */
8
+ isTV?: boolean;
9
+ /**
10
+ * If true, verbose warnings will be shown during plugin execution.
11
+ */
12
+ showVerboseWarnings?: boolean;
13
+ };
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import { ConfigData } from "./types";
2
+ export declare function isTVEnabled(params: ConfigData): boolean;
3
+ export declare function showVerboseWarnings(params: ConfigData): boolean;
package/build/utils.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.showVerboseWarnings = exports.isTVEnabled = void 0;
4
+ const getenv_1 = require("getenv");
5
+ class Env {
6
+ /** Enable prebuild for TV */
7
+ get EXPO_TV() {
8
+ return (0, getenv_1.boolish)("EXPO_TV", false);
9
+ }
10
+ }
11
+ const env = new Env();
12
+ function isTVEnabled(params) {
13
+ return env.EXPO_TV || (params?.isTV ?? false);
14
+ }
15
+ exports.isTVEnabled = isTVEnabled;
16
+ function showVerboseWarnings(params) {
17
+ return params?.showVerboseWarnings ?? false;
18
+ }
19
+ exports.showVerboseWarnings = showVerboseWarnings;
@@ -0,0 +1,4 @@
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
+ import { ConfigData } from "./types";
3
+ declare const _default: ConfigPlugin<ConfigData>;
4
+ export default _default;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("expo/config-plugins");
4
+ const withTVAndroidManifest_1 = require("./withTVAndroidManifest");
5
+ const withTVPodfile_1 = require("./withTVPodfile");
6
+ const withTVSplashScreen_1 = require("./withTVSplashScreen");
7
+ const withTVXcodeProject_1 = require("./withTVXcodeProject");
8
+ const withTVPlugin = (config, params = {}) => {
9
+ config = (0, withTVXcodeProject_1.withTVXcodeProject)(config, params);
10
+ config = (0, withTVPodfile_1.withTVPodfile)(config, params);
11
+ config = (0, withTVSplashScreen_1.withTVSplashScreen)(config, params);
12
+ config = (0, withTVAndroidManifest_1.withTVAndroidManifest)(config, params);
13
+ return config;
14
+ };
15
+ const pkg = require("../package.json");
16
+ exports.default = (0, config_plugins_1.createRunOncePlugin)(withTVPlugin, pkg.name, pkg.version);
@@ -0,0 +1,6 @@
1
+ import { ExpoConfig } from "expo/config";
2
+ import { AndroidConfig, ConfigPlugin } from "expo/config-plugins";
3
+ import { ConfigData } from "./types";
4
+ export declare const withTVAndroidManifest: ConfigPlugin<ConfigData>;
5
+ export declare function setLeanBackLauncherIntent(_config: Pick<ExpoConfig, "android">, androidManifest: AndroidConfig.Manifest.AndroidManifest, verbose: boolean): AndroidConfig.Manifest.AndroidManifest;
6
+ export declare function removePortraitOrientation(_config: Pick<ExpoConfig, "android">, androidManifest: AndroidConfig.Manifest.AndroidManifest, verbose: boolean): Promise<AndroidConfig.Manifest.AndroidManifest>;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removePortraitOrientation = exports.setLeanBackLauncherIntent = exports.withTVAndroidManifest = void 0;
4
+ const config_plugins_1 = require("expo/config-plugins");
5
+ const utils_1 = require("./utils");
6
+ const pkg = require("../package.json");
7
+ const { getMainActivity } = config_plugins_1.AndroidConfig.Manifest;
8
+ const withTVAndroidManifest = (config, params = {}) => {
9
+ const isTV = (0, utils_1.isTVEnabled)(params);
10
+ const verbose = (0, utils_1.showVerboseWarnings)(params);
11
+ return (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
12
+ if (!isTV) {
13
+ // nothing to do
14
+ return config;
15
+ }
16
+ config.modResults = await setLeanBackLauncherIntent(config, config.modResults, verbose);
17
+ config.modResults = await removePortraitOrientation(config, config.modResults, verbose);
18
+ return config;
19
+ });
20
+ };
21
+ exports.withTVAndroidManifest = withTVAndroidManifest;
22
+ const LEANBACK_LAUNCHER_CATEGORY = "android.intent.category.LEANBACK_LAUNCHER";
23
+ function getMainLaunchIntent(androidManifest) {
24
+ const mainActivity = getMainActivity(androidManifest);
25
+ const intentFilters = mainActivity?.["intent-filter"];
26
+ const mainLaunchIntents = (intentFilters ?? []).filter((i) => {
27
+ const action = i.action ?? [];
28
+ if (action.length === 0) {
29
+ return false;
30
+ }
31
+ return action[0]?.$["android:name"] === "android.intent.action.MAIN";
32
+ });
33
+ return mainLaunchIntents.length ? mainLaunchIntents[0] : undefined;
34
+ }
35
+ function leanbackLauncherCategoryExistsInMainLaunchIntent(mainLaunchIntent) {
36
+ const mainLaunchCategories = mainLaunchIntent.category ?? [];
37
+ const mainLaunchIntentCategoriesWithLeanbackLauncher = mainLaunchCategories.filter((c) => c.$["android:name"] === LEANBACK_LAUNCHER_CATEGORY);
38
+ return mainLaunchIntentCategoriesWithLeanbackLauncher.length > 0;
39
+ }
40
+ function setLeanBackLauncherIntent(_config, androidManifest, verbose) {
41
+ const mainLaunchIntent = getMainLaunchIntent(androidManifest);
42
+ if (!mainLaunchIntent) {
43
+ throw new Error(`${pkg.name}@${pkg.version}: no main intent in main activity of Android manifest`);
44
+ }
45
+ if (!leanbackLauncherCategoryExistsInMainLaunchIntent(mainLaunchIntent)) {
46
+ // Leanback needs to be added
47
+ if (verbose) {
48
+ config_plugins_1.WarningAggregator.addWarningAndroid("manifest", `${pkg.name}@${pkg.version}: adding TV leanback launcher category to main intent in AndroidManifest.xml`);
49
+ }
50
+ const mainLaunchCategories = mainLaunchIntent.category ?? [];
51
+ mainLaunchCategories.push({
52
+ $: {
53
+ "android:name": LEANBACK_LAUNCHER_CATEGORY,
54
+ },
55
+ });
56
+ mainLaunchIntent.category = mainLaunchCategories;
57
+ }
58
+ return androidManifest;
59
+ }
60
+ exports.setLeanBackLauncherIntent = setLeanBackLauncherIntent;
61
+ async function removePortraitOrientation(_config, androidManifest, verbose) {
62
+ const mainActivity = getMainActivity(androidManifest);
63
+ if (mainActivity?.$) {
64
+ const metadata = mainActivity?.$ ?? {};
65
+ if (metadata["android:screenOrientation"]) {
66
+ if (verbose) {
67
+ config_plugins_1.WarningAggregator.addWarningAndroid("manifest", `${pkg.name}@${pkg.version}: removing screen orientation from AndroidManifest.xml`);
68
+ }
69
+ delete metadata["android:screenOrientation"];
70
+ }
71
+ }
72
+ return androidManifest;
73
+ }
74
+ exports.removePortraitOrientation = removePortraitOrientation;
@@ -0,0 +1,6 @@
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
+ import { ConfigData } from "./types";
3
+ /** Dangerously makes or reverts TV changes in the project Podfile. */
4
+ export declare const withTVPodfile: ConfigPlugin<ConfigData>;
5
+ export declare function removeTVPodfileModifications(src: string): string;
6
+ export declare function addTVPodfileModifications(src: string): string;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.addTVPodfileModifications = exports.removeTVPodfileModifications = exports.withTVPodfile = void 0;
7
+ const generateCode_1 = require("@expo/config-plugins/build/utils/generateCode");
8
+ const config_plugins_1 = require("expo/config-plugins");
9
+ const fs_1 = require("fs");
10
+ const path_1 = __importDefault(require("path"));
11
+ const utils_1 = require("./utils");
12
+ const pkg = require("../package.json");
13
+ /** Dangerously makes or reverts TV changes in the project Podfile. */
14
+ const withTVPodfile = (c, params = {}) => {
15
+ const isTV = (0, utils_1.isTVEnabled)(params);
16
+ const verbose = (0, utils_1.showVerboseWarnings)(params);
17
+ return (0, config_plugins_1.withDangerousMod)(c, [
18
+ "ios",
19
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
20
+ async (config) => {
21
+ const file = path_1.default.join(config.modRequest.platformProjectRoot, "Podfile");
22
+ const contents = await fs_1.promises.readFile(file, "utf8");
23
+ const modifiedContents = isTV
24
+ ? addTVPodfileModifications(contents)
25
+ : removeTVPodfileModifications(contents);
26
+ if (modifiedContents !== contents) {
27
+ if (verbose) {
28
+ config_plugins_1.WarningAggregator.addWarningIOS("podfile", `${pkg.name}@${pkg.version}: modifying Podfile for ${isTV ? "tvOS" : "iOS"}`);
29
+ }
30
+ await fs_1.promises.writeFile(file, modifiedContents, "utf-8");
31
+ }
32
+ return config;
33
+ },
34
+ ]);
35
+ };
36
+ exports.withTVPodfile = withTVPodfile;
37
+ const MOD_TAG = "react-native-tvos-import";
38
+ function removeTVPodfileModifications(src) {
39
+ if (src.indexOf("platform :tvos") === -1) {
40
+ return src;
41
+ }
42
+ const intermediateSrc = src.replace("platform :tvos", "platform :ios");
43
+ const newSrc = (0, generateCode_1.removeContents)({
44
+ src: intermediateSrc,
45
+ tag: MOD_TAG,
46
+ }).contents;
47
+ if (!newSrc) {
48
+ throw new Error(`${pkg.name}@${pkg.version}: Error in removing TV modifications from Podfile. Recommend running "npx expo prebuild --clean"`);
49
+ }
50
+ return newSrc;
51
+ }
52
+ exports.removeTVPodfileModifications = removeTVPodfileModifications;
53
+ function addTVPodfileModifications(src) {
54
+ if (src.indexOf("platform :tvos") !== -1) {
55
+ return src;
56
+ }
57
+ const newSrc = (0, generateCode_1.mergeContents)({
58
+ tag: MOD_TAG,
59
+ src,
60
+ newSrc: "source 'https://github.com/react-native-tvos/react-native-tvos-podspecs.git'\nsource 'https://cdn.cocoapods.org/'\n",
61
+ anchor: /^/,
62
+ offset: 0,
63
+ comment: "#",
64
+ }).contents;
65
+ return newSrc.replace("platform :ios", "platform :tvos");
66
+ }
67
+ exports.addTVPodfileModifications = addTVPodfileModifications;
@@ -0,0 +1,6 @@
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
+ import { ConfigData } from "./types";
3
+ /** Dangerously modifies or reverts changes needed for TV in SplashScreen.storyboard. */
4
+ export declare const withTVSplashScreen: ConfigPlugin<ConfigData>;
5
+ export declare function addTVSplashScreenModifications(src: string): string;
6
+ export declare function removeTVSplashScreenModifications(src: string): string;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.removeTVSplashScreenModifications = exports.addTVSplashScreenModifications = exports.withTVSplashScreen = void 0;
7
+ const config_plugins_1 = require("expo/config-plugins");
8
+ const fs_1 = require("fs");
9
+ const path_1 = __importDefault(require("path"));
10
+ const utils_1 = require("./utils");
11
+ const pkg = require("../package.json");
12
+ /** Dangerously modifies or reverts changes needed for TV in SplashScreen.storyboard. */
13
+ const withTVSplashScreen = (config, params = {}) => {
14
+ const isTV = (0, utils_1.isTVEnabled)(params);
15
+ const verbose = (0, utils_1.showVerboseWarnings)(params);
16
+ return (0, config_plugins_1.withDangerousMod)(config, [
17
+ "ios",
18
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
19
+ async (config) => {
20
+ if (!config.modRequest.projectName) {
21
+ throw new Error(`The ${pkg.name}@${pkg.version} plugin requires a configured project name.`);
22
+ }
23
+ const file = path_1.default.join(config.modRequest.platformProjectRoot, config.modRequest.projectName, "SplashScreen.storyboard");
24
+ const contents = await fs_1.promises.readFile(file, "utf8");
25
+ const modifiedContents = isTV
26
+ ? addTVSplashScreenModifications(contents)
27
+ : removeTVSplashScreenModifications(contents);
28
+ if (modifiedContents !== contents) {
29
+ if (verbose) {
30
+ config_plugins_1.WarningAggregator.addWarningIOS("splashscreen", `${pkg.name}@${pkg.version}:: modifying SplashScreen.storyboard for ${isTV ? "tvOS" : "iOS"}`);
31
+ }
32
+ await fs_1.promises.writeFile(file, modifiedContents, "utf-8");
33
+ }
34
+ return config;
35
+ },
36
+ ]);
37
+ };
38
+ exports.withTVSplashScreen = withTVSplashScreen;
39
+ const splashScreenStringsForPhone = [
40
+ "com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB",
41
+ 'targetRuntime="iOS.CocoaTouch"',
42
+ 'id="retina5_5"',
43
+ '<deployment identifier="iOS"/>',
44
+ ];
45
+ const splashScreenStringsForTV = [
46
+ "com.apple.InterfaceBuilder.AppleTV.Storyboard",
47
+ 'targetRuntime="AppleTV"',
48
+ 'id="appleTV"',
49
+ '<deployment identifier="tvOS"/>',
50
+ ];
51
+ function modifySource(src, originalStrings, replacementStrings) {
52
+ let modifiedSource = src;
53
+ originalStrings.forEach((s, i) => {
54
+ const original = new RegExp(`${s}`, "g");
55
+ const replacement = replacementStrings[i];
56
+ modifiedSource = modifiedSource.replace(original, replacement);
57
+ });
58
+ return modifiedSource;
59
+ }
60
+ function addTVSplashScreenModifications(src) {
61
+ return modifySource(src, splashScreenStringsForPhone, splashScreenStringsForTV);
62
+ }
63
+ exports.addTVSplashScreenModifications = addTVSplashScreenModifications;
64
+ function removeTVSplashScreenModifications(src) {
65
+ return modifySource(src, splashScreenStringsForTV, splashScreenStringsForPhone);
66
+ }
67
+ exports.removeTVSplashScreenModifications = removeTVSplashScreenModifications;
@@ -0,0 +1,18 @@
1
+ import { ExpoConfig } from "@expo/config-types";
2
+ import { ConfigPlugin, XcodeProject } from "expo/config-plugins";
3
+ import { ConfigData } from "./types";
4
+ export declare const withTVXcodeProject: ConfigPlugin<ConfigData>;
5
+ export declare function setXcodeProjectBuildSettings(config: Pick<ExpoConfig, "ios">, { project, isTV, verbose, }: {
6
+ project: XcodeProject;
7
+ isTV: boolean;
8
+ verbose: boolean;
9
+ }): XcodeProject;
10
+ /**
11
+ * Wrapping the families in double quotes is the only way to set a value with a comma in it.
12
+ *
13
+ * @param deviceFamilies
14
+ */
15
+ export declare function formatDeviceFamilies(deviceFamilies: number[]): string;
16
+ export declare function getSupportsTablet(config: Pick<ExpoConfig, "ios">): boolean;
17
+ export declare function getIsTabletOnly(config: Pick<ExpoConfig, "ios">): boolean;
18
+ export declare function getDeviceFamilies(config: Pick<ExpoConfig, "ios">): number[];
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDeviceFamilies = exports.getIsTabletOnly = exports.getSupportsTablet = exports.formatDeviceFamilies = exports.setXcodeProjectBuildSettings = exports.withTVXcodeProject = void 0;
4
+ const config_plugins_1 = require("expo/config-plugins");
5
+ const utils_1 = require("./utils");
6
+ const pkg = require("../package.json");
7
+ const withTVXcodeProject = (config, params) => {
8
+ const isTV = (0, utils_1.isTVEnabled)(params);
9
+ const verbose = (0, utils_1.showVerboseWarnings)(params);
10
+ return (0, config_plugins_1.withXcodeProject)(config, async (config) => {
11
+ config.modResults = await setXcodeProjectBuildSettings(config, {
12
+ project: config.modResults,
13
+ isTV,
14
+ verbose,
15
+ });
16
+ return config;
17
+ });
18
+ };
19
+ exports.withTVXcodeProject = withTVXcodeProject;
20
+ function setXcodeProjectBuildSettings(config, { project, isTV, verbose, }) {
21
+ const deviceFamilies = formatDeviceFamilies(getDeviceFamilies(config));
22
+ const configurations = project.pbxXCBuildConfigurationSection();
23
+ // @ts-ignore
24
+ for (const { buildSettings } of Object.values(configurations || {})) {
25
+ // Guessing that this is the best way to emulate Xcode.
26
+ // Using `project.addToBuildSettings` modifies too many targets.
27
+ if (typeof buildSettings?.PRODUCT_NAME !== "undefined") {
28
+ if (isTV && buildSettings.TARGETED_DEVICE_FAMILY !== "3") {
29
+ if (verbose) {
30
+ config_plugins_1.WarningAggregator.addWarningIOS("xcodeproject", `${pkg.name}@${pkg.version}: modifying target ${buildSettings?.PRODUCT_NAME} for ${isTV ? "tvOS" : "iOS"}`);
31
+ }
32
+ buildSettings.TARGETED_DEVICE_FAMILY = "3";
33
+ buildSettings.TVOS_DEPLOYMENT_TARGET = "13.0";
34
+ buildSettings.SDKROOT = "appletvos";
35
+ if (typeof buildSettings?.IOS_DEPLOYMENT_TARGET !== "undefined") {
36
+ delete buildSettings?.IOS_DEPLOYMENT_TARGET;
37
+ }
38
+ }
39
+ else if (!isTV && buildSettings.TARGETED_DEVICE_FAMILY === "3") {
40
+ config_plugins_1.WarningAggregator.addWarningIOS("xcodeproject", `${pkg.name}@${pkg.version}: modifying target ${buildSettings?.PRODUCT_NAME} for ${isTV ? "tvOS" : "iOS"}`);
41
+ buildSettings.TARGETED_DEVICE_FAMILY = deviceFamilies;
42
+ buildSettings.IOS_DEPLOYMENT_TARGET = "13.0";
43
+ buildSettings.SDKROOT = "iphoneos";
44
+ if (typeof buildSettings?.TVOS_DEPLOYMENT_TARGET !== "undefined") {
45
+ delete buildSettings?.TVOS_DEPLOYMENT_TARGET;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return project;
51
+ }
52
+ exports.setXcodeProjectBuildSettings = setXcodeProjectBuildSettings;
53
+ /**
54
+ * Wrapping the families in double quotes is the only way to set a value with a comma in it.
55
+ *
56
+ * @param deviceFamilies
57
+ */
58
+ function formatDeviceFamilies(deviceFamilies) {
59
+ return `"${deviceFamilies.join(",")}"`;
60
+ }
61
+ exports.formatDeviceFamilies = formatDeviceFamilies;
62
+ function getSupportsTablet(config) {
63
+ return !!config.ios?.supportsTablet;
64
+ }
65
+ exports.getSupportsTablet = getSupportsTablet;
66
+ function getIsTabletOnly(config) {
67
+ return !!config?.ios?.isTabletOnly;
68
+ }
69
+ exports.getIsTabletOnly = getIsTabletOnly;
70
+ function getDeviceFamilies(config) {
71
+ const supportsTablet = getSupportsTablet(config);
72
+ const isTabletOnly = getIsTabletOnly(config);
73
+ if (isTabletOnly && config.ios?.supportsTablet === false) {
74
+ // add warning
75
+ }
76
+ // 1 is iPhone, 2 is iPad
77
+ if (isTabletOnly) {
78
+ return [2];
79
+ }
80
+ else if (supportsTablet) {
81
+ return [1, 2];
82
+ }
83
+ else {
84
+ // is iPhone only
85
+ return [1];
86
+ }
87
+ }
88
+ exports.getDeviceFamilies = getDeviceFamilies;
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@react-native-tvos/config-tv",
3
+ "version": "0.0.1",
4
+ "description": "Config plugin to reconfigure native directories for Apple TV and Android TV development if needed",
5
+ "main": "build/withTV.js",
6
+ "types": "build/withTV.d.ts",
7
+ "sideEffects": false,
8
+ "license": "MIT",
9
+ "files": [
10
+ "build",
11
+ "app.plugin.js"
12
+ ],
13
+ "homepage": "https://github.com/react-native-tvos/config-tv",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/react-native-tvos/config-tv",
17
+ "directory": "packages/config-tv"
18
+ },
19
+ "scripts": {
20
+ "build": "expo-module build",
21
+ "clean": "expo-module clean",
22
+ "lint": "expo-module lint",
23
+ "test": "expo-module test",
24
+ "prepare": "expo-module prepare",
25
+ "prepublishOnly": "expo-module prepublishOnly",
26
+ "expo-module": "expo-module"
27
+ },
28
+ "keywords": [
29
+ "react",
30
+ "expo",
31
+ "config-plugins",
32
+ "prebuild",
33
+ "tv",
34
+ "react-native-tvos"
35
+ ],
36
+ "peerDependencies": {
37
+ "expo": "^50.0.0.alpha.5"
38
+ },
39
+ "devDependencies": {
40
+ "@types/getenv": "^1.0.1",
41
+ "expo-module-scripts": "^3.0.3"
42
+ },
43
+ "upstreamPackage": "tv",
44
+ "dependencies": {
45
+ "getenv": "^1.0.0"
46
+ }
47
+ }