Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/cli/src/lib/plugins/logConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function filterConfig(config: Config) {
// but in our case we don't install `@react-native-community/cli-platform-*` as a dependencies
// so the config.platforms key is empty, which makes autolinking treat it as a dependency.
delete filtered.dependencies['react-native'];
delete filtered.dependencies['react-native-tvos'];
const dependencies: Record<string, DependencyConfig> = {};
Object.keys(filtered.dependencies).forEach((item) => {
if (isValidRNDependency(filtered.dependencies[item])) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { buildAndroid, options } from './buildAndroid.js';

export function registerBuildCommand(
api: PluginApi,
pluginConfig: AndroidProjectConfig | undefined
pluginConfig: AndroidProjectConfig | undefined,
commandName: string
) {
api.registerCommand({
name: 'build:android',
name: commandName,
description: 'Builds your app for Android platform.',
action: async (args) => {
const androidConfig = getValidProjectConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import { getValidProjectConfig } from './getValidProjectConfig.js';

export function registerCreateKeystoreCommand(
api: PluginApi,
pluginConfig: AndroidProjectConfig | undefined
pluginConfig: AndroidProjectConfig | undefined,
commandName: string
) {
api.registerCommand({
name: 'create-keystore:android',
name: commandName,
description: 'Creates a keystore file for signing Android release builds.',
action: async (args) => {
const androidConfig = getValidProjectConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { runAndroid, runOptions } from './runAndroid.js';

export function registerRunCommand(
api: PluginApi,
pluginConfig: AndroidProjectConfig | undefined
pluginConfig: AndroidProjectConfig | undefined,
commandName: string
) {
api.registerCommand({
name: 'run:android',
name: commandName,
description:
'Builds your app and starts it on a connected Android emulator or a device.',
action: async (args) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ async function runOnDevice({
loader.stop(
`Failed: installing and launching the app on ${color.bold(
device.readableName
)}`
)}`,
1
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ const OPTIONS = [
},
];

export const registerSignCommand = (api: PluginApi) => {
export const registerSignCommand = (api: PluginApi, commandName: string) => {
api.registerCommand({
name: 'sign:android',
name: commandName,
description: 'Sign the Android app with modified JS bundle.',
args: ARGUMENTS,
options: OPTIONS,
Expand Down
31 changes: 27 additions & 4 deletions packages/platform-android/src/lib/platformAndroid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ type PluginConfig = AndroidProjectConfig;
export const platformAndroid =
(pluginConfig?: PluginConfig) =>
(api: PluginApi): PlatformOutput => {
registerBuildCommand(api, pluginConfig);
registerRunCommand(api, pluginConfig);
registerCreateKeystoreCommand(api, pluginConfig);
registerSignCommand(api);
registerBuildCommand(api, pluginConfig, 'build:android');
registerRunCommand(api, pluginConfig, 'run:android');
registerCreateKeystoreCommand(api, pluginConfig, 'create-keystore:keystore');
registerSignCommand(api, 'sign:android');

return {
name: '@rnef/platform-android',
Expand All @@ -31,4 +31,27 @@ export const platformAndroid =
};
};

export const platformAndroidTV =
(pluginConfig?: PluginConfig) =>
(api: PluginApi): PlatformOutput => {
registerBuildCommand(api, pluginConfig, 'build:android:tv');
registerRunCommand(api, pluginConfig, 'run:android:tv');
registerCreateKeystoreCommand(api, pluginConfig, 'create-keystore:keystore:tv');
registerSignCommand(api, 'sign:android:tv');

return {
name: '@rnef/platform-android-tv',
description: 'RNEF plugin for everything Android TV.',
autolinkingConfig: {
get project() {
const androidConfig = getValidProjectConfig(
api.getProjectRoot(),
pluginConfig
);
return { ...androidConfig };
},
},
};
};

export default platformAndroid;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.faketouch" android:required="false" />
<uses-feature android:name="android.software.leanback" android:required="false" />

<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2 changes: 1 addition & 1 deletion packages/platform-apple-helpers/src/lib/utils/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async function runCodegen(options: CodegenOptions) {
'-o',
options.sourceDir,
'-t',
options.platformName,
options.platformName === 'tvos' ? 'ios' : options.platformName,
]);
} catch (error) {
throw new RnefError('Failed to run React Native codegen script', {
Expand Down
82 changes: 76 additions & 6 deletions packages/platform-ios/src/lib/platformIOS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export const platformIOS =
action: async (args) => {
intro('Building iOS app');
const projectRoot = api.getProjectRoot();
const iosConfig = getValidProjectConfig(
const projectConfig = getValidProjectConfig(
'ios',
projectRoot,
pluginConfig
);
await createBuild({
platformName: 'ios',
projectConfig: iosConfig,
projectConfig,
args: args as BuildFlags,
projectRoot,
reactNativePath: api.getReactNativePath(),
Expand All @@ -48,14 +48,14 @@ export const platformIOS =
action: async (args) => {
intro('Running iOS app');
const projectRoot = api.getProjectRoot();
const iosConfig = getValidProjectConfig(
const projectConfig = getValidProjectConfig(
'ios',
projectRoot,
pluginConfig
);
await createRun({
platformName: 'ios',
projectConfig: iosConfig,
projectConfig,
args: args as RunFlags,
projectRoot,
remoteCacheProvider: await api.getRemoteCacheProvider(),
Expand All @@ -75,12 +75,82 @@ export const platformIOS =
description: 'RNEF plugin for everything iOS.',
autolinkingConfig: {
get project() {
const iosConfig = getValidProjectConfig(
const projectConfig = getValidProjectConfig(
'ios',
api.getProjectRoot(),
pluginConfig
);
return { ...iosConfig };
return { ...projectConfig };
},
},
};
};

export const platformTVOS =
(pluginConfig?: IOSProjectConfig) =>
(api: PluginApi): PlatformOutput => {
api.registerCommand({
name: 'build:ios:tv',
description: 'Build tvOS app.',
action: async (args) => {
intro('Building tvOS app');
const projectRoot = api.getProjectRoot();
const projectConfig = getValidProjectConfig(
'tvos',
projectRoot,
pluginConfig
);
await createBuild({
platformName: 'tvos',
projectConfig,
args: args as BuildFlags,
projectRoot,
reactNativePath: api.getReactNativePath(),
fingerprintOptions: api.getFingerprintOptions(),
remoteCacheProvider: await api.getRemoteCacheProvider(),
});
outro('Success 🎉.');
},
options: buildOptions,
});

api.registerCommand({
name: 'run:ios:tv',
description: 'Run tvOS app.',
action: async (args) => {
intro('Running tvOS app');
const projectRoot = api.getProjectRoot();
const projectConfig = getValidProjectConfig(
'tvos',
projectRoot,
pluginConfig
);
await createRun({
platformName: 'tvos',
projectConfig,
args: args as RunFlags,
projectRoot,
remoteCacheProvider: await api.getRemoteCacheProvider(),
fingerprintOptions: api.getFingerprintOptions(),
reactNativePath: api.getReactNativePath(),
});
outro('Success 🎉.');
},
// @ts-expect-error: fix `simulator` is not defined in `RunFlags`
options: runOptions,
});

return {
name: '@rnef/platform-tvos',
description: 'RNEF plugin for everything tvOS.',
autolinkingConfig: {
get project() {
const projectConfig = getValidProjectConfig(
'tvos',
api.getProjectRoot(),
pluginConfig
);
return { ...projectConfig };
},
},
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Remote Build tvOS

on:
push:
branches:
- main
pull_request:
branches:
- '**'

concurrency:
group: remote-build-tvos-${{ github.ref }}
cancel-in-progress: true

jobs:
build-device:
runs-on: macos-latest

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm install

- name: RNEF Remote Build - tvOS device
uses: callstackincubator/ios@v2
with:
destination: device
github-token: ${{ secrets.GITHUB_TOKEN }}
scheme: SCHEME_FOR_DEVICES # replace with preferred scheme
configuration: Release # replace with preferred configuration
certificate-base64: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }}
certificate-password: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }}
provisioning-profile-base64: ${{ secrets.APPLE_BUILD_PROVISIONING_PROFILE_BASE64 }}
provisioning-profile-name: 'PROVISIONING_PROFILE_NAME' # replace with actual profile name
keychain-password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}

build-simulator:
runs-on: macos-latest

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm install

- name: RNEF Remote Build - tvOS simulator
uses: callstackincubator/ios@v2
with:
destination: simulator
github-token: ${{ secrets.GITHUB_TOKEN }}
scheme: SCHEME_FOR_SIMULATORS # replace with preferred scheme
configuration: Debug # replace with preferred configuration
12 changes: 12 additions & 0 deletions packages/platform-ios/template-tv/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "rnef-platform-ios-template-tv",
"scripts": {
"tvos": "rnef run:ios:tv"
},
"dependencies": {
"react-native": "npm:[email protected]"
},
"devDependencies": {
"@rnef/platform-ios": "^0.8.6"
}
}
11 changes: 11 additions & 0 deletions packages/platform-ios/template-tv/tvos/.xcode.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.

# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.
# For example, to use nvm with brew, add the following line
# . "$(brew --prefix nvm)/nvm.sh" --no-use
export NODE_BINARY=$(command -v node)
Loading
Loading