### Start Rock Development Server Source: https://www.rockjs.dev/docs/getting-started Run this command to start the development server, which uses a bundler like Metro or Re.Pack to serve your JavaScript code to the running application. ```bash rock start ``` -------------------------------- ### Custom Plugin Example Source: https://www.rockjs.dev/docs/configuration An example of a custom Rock plugin that registers a new command 'my-command'. This demonstrates how to use the PluginApi to extend project functionality. ```javascript const simplePlugin = (pluginConfig: SamplePluginConfig) => (api: PluginApi): PluginOutput => { api.registerCommand({ name: 'my-command', description: 'My command description', action: async (args) => { console.log('hello world'); }, }); }; export default { plugins: [simplePlugin()], }; ``` -------------------------------- ### Metro Bundler Start Command Source: https://www.rockjs.dev/docs/cli/introduction Starts the Metro development server using the @rock-js/plugin-metro plugin. This command is used for local development and debugging. ```shell start ``` -------------------------------- ### GitHub Provider .env Example Source: https://www.rockjs.dev/docs/configuration Store your GitHub Personal Access Token in a .env file as GITHUB_TOKEN. ```dotenv GITHUB_TOKEN=token_value ``` -------------------------------- ### Setup Rock's Brownfield iOS Plugin in rock.config.mjs Source: https://www.rockjs.dev/docs/brownfield/ios Configure your Rock project to use the brownfield iOS plugin by installing it and adding the `pluginBrownfieldIos()` to your `rock.config.mjs` file. ```javascript import { pluginBrownfieldIos } from '@rock-js/plugin-brownfield-ios'; export default { plugins: [ pluginBrownfieldIos(), // ... ], }; ``` -------------------------------- ### Install Rock CLI Dev Dependencies Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Install the necessary development dependencies for the Rock CLI and its plugins. ```bash npm install -D rock @rock-js/plugin-metro @rock-js/platform-android @rock-js/platform-ios # or yarn add -D rock @rock-js/plugin-metro @rock-js/platform-android @rock-js/platform-ios # or pnpm add -D rock @rock-js/plugin-metro @rock-js/platform-android @rock-js/platform-ios ``` -------------------------------- ### Implement RemoteBuildCache Interface - list method Source: https://www.rockjs.dev/docs/configuration Example implementation of the `list` method for a custom remote cache provider. This function filters objects by prefix and generates signed URLs for downloadable artifacts. ```typescript async list({ artifactName, limit }) { const artifacts = await this.s3.send( new ListObjectsV2Command({ Bucket: this.bucket, Prefix: artifactName ? `${this.directory}/${artifactName}.zip` : `${this.directory}/`, }) ); const results = []; for (const artifact of artifacts.Contents ?? []) { if (!artifact.Key) continue; const name = artifactName ?? artifact.Key.split('/').pop() ?? ''; const presignedUrl = await getSignedUrl(/* ... */); results.push({ name, url: presignedUrl }); } return results; } ``` -------------------------------- ### Update package.json Scripts for Rock CLI Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Replace existing start, android, and ios script commands in `package.json` with their Rock CLI equivalents. ```json { "scripts": { "start": "rock start", "android": "rock run:android", "ios": "rock run:ios" } } ``` -------------------------------- ### Basic Rock Configuration Source: https://www.rockjs.dev/docs/configuration Sets up Rock for iOS platform with the Metro bundler. Ensure you have the necessary platform and bundler plugins installed. ```javascript // @ts-check import { platformIOS } from '@rock-js/platform-ios'; import { pluginMetro } from '@rock-js/plugin-metro'; /** @type {import('rock').Config} */ export default { bundler: pluginMetro(), platforms: { ios: platformIOS(), }, }; ``` -------------------------------- ### Start JS Dev Server Source: https://www.rockjs.dev/docs/brownfield/ios When running your iOS app in Debug configuration, you need to run a JavaScript development server. Execute this command in your Terminal. ```shell npx rock start ``` -------------------------------- ### Create New Rock Project with Brownfield iOS Plugin Source: https://www.rockjs.dev/docs/brownfield/ios Select the `brownfield-ios` plugin during `npm create rock` to automatically add brownfield capabilities and install necessary dependencies for iOS integration. ```bash > npm create rock ... ◆ What plugins do you want to start with? │ ◼ brownfield-ios ``` -------------------------------- ### Monorepo Setup for Metro Bundler Source: https://www.rockjs.dev/docs/configuration Configure Metro bundler to watch additional directories in a monorepo setup by specifying `watchFolders` and `nodeModulesPaths`. ```APIDOC ## Monorepo Setup for Metro Bundler ### Description Configure Metro bundler to watch additional directories in a monorepo setup by specifying `watchFolders` and `nodeModulesPaths`. ### Code Example ```javascript const path = require('path'); const { getDefaultConfig, mergeConfig } = require('@rock-js/plugin-metro'); const projectRoot = __dirname; const workspaceRoot = path.resolve(projectRoot, '../..'); const config = getDefaultConfig(projectRoot); module.exports = mergeConfig(config, { watchFolders: [workspaceRoot], resolver: { nodeModulesPaths: [ path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules'), ], }, }); ``` ``` -------------------------------- ### AWS S3 Provider .env Example Source: https://www.rockjs.dev/docs/configuration Store your AWS Access Key ID and Secret Access Key in a .env file. ```dotenv AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... ``` -------------------------------- ### Set Environment Variables for iOS Build Source: https://www.rockjs.dev/docs/cli/introduction Prefix the build command with environment variables to customize dependency installation. For example, disable prebuilt React Native dependencies. ```shell RCT_USE_PREBUILT_RNCORE=0 RCT_USE_RN_DEP=0 npx rock build:ios ``` -------------------------------- ### Configuring Metro Bundler Source: https://www.rockjs.dev/docs/configuration Specifies the Metro bundler for a Rock project. This configuration assumes the '@rock-js/plugin-metro' package is installed. ```javascript import { pluginMetro } from '@rock-js/plugin-metro'; export default { // ... bundler: pluginMetro(), }; ``` -------------------------------- ### Create Framework's Public Interface with React Native Brownfield Source: https://www.rockjs.dev/docs/brownfield/ios Define the public interface for your framework by installing the React Native Brownfield library and creating a Swift file to export helpers and initialize the `Bundle` instance. ```swift // Export helpers from @callstack/react-native-brownfield library @_exported import ReactBrownfield // Initializes a Bundle instance that points at the framework target. public let ReactNativeBundle = Bundle(for: InternalClassForBundle.self) class InternalClassForBundle {} ``` -------------------------------- ### Initialize Rock CLI Configuration Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Create the `rock.config.mjs` file to configure the Rock CLI, including bundler, platforms, and remote cache provider. ```javascript // @ts-check import { platformIOS } from '@rock-js/platform-ios'; import { platformAndroid } from '@rock-js/platform-android'; import { pluginMetro } from '@rock-js/plugin-metro'; /** @type {import('rock').Config} */ export default { bundler: pluginMetro(), platforms: { ios: platformIOS(), android: platformAndroid(), }, remoteCacheProvider: 'github-actions', }; ``` -------------------------------- ### Create New Rock Project Source: https://www.rockjs.dev/docs/getting-started Use this command to initialize a new React Native project with Rock. It will prompt you to select your preferred bundler and target platforms. ```bash create rock@latest ``` -------------------------------- ### Run Rock App on HarmonyOS (Experimental) Source: https://www.rockjs.dev/docs/getting-started Build and launch your application on a HarmonyOS emulator or device using this experimental command. ```bash rock run:harmony ``` -------------------------------- ### Create New Rock Project with Android Plugin Source: https://www.rockjs.dev/docs/brownfield/android Select the `brownfield-android` plugin during project creation to enable brownfield capabilities for Android integration. ```bash > npm create rock ... ◆ What plugins do you want to start with? │ ◼ brownfield-android ``` -------------------------------- ### Customizing Metro Configuration Source: https://www.rockjs.dev/docs/configuration Shows how to create a custom `metro.config.js` file to extend the default Metro configuration provided by Rock. This is useful for advanced customizations. ```javascript const { getDefaultConfig, mergeConfig } = require('@rock-js/plugin-metro'); /** * @type {import('@rock-js/plugin-metro').MetroConfig} */ module.exports = mergeConfig(getDefaultConfig(__dirname), { // Your custom configuration }); ``` -------------------------------- ### Run Rock App on iOS Source: https://www.rockjs.dev/docs/getting-started Build and launch your application on an iOS simulator or device using this command. ```bash rock run:ios ``` -------------------------------- ### Configure iOS Platform Source: https://www.rockjs.dev/docs/configuration Set up the iOS platform configuration for your Rock project. This involves importing the platform-specific plugin and optionally providing configuration details. ```javascript import { platformIOS } from '@rock-js/platform-ios'; export default { // ... platforms: { // config is optional; it translates to `project` config from react-native.config.js file ios: platformIOS(config), }, }; ``` -------------------------------- ### Add React Native and Hermes Dependencies Source: https://www.rockjs.dev/docs/brownfield/android Include the `react-native` and `hermes-android` dependencies in your `reactnativeapp/build.gradle.kts`, ensuring versions match your React Native setup. ```groovy dependencies { // Match your version of React Native, here 0.83: api("com.facebook.react:react-android:0.83.0") // For React Native 0.83 or newer use: api("com.facebook.hermes:hermes-android:0.14.0") // For React Native 0.82 or older use: // api("com.facebook.react:hermes-android:0.82.0") } ``` -------------------------------- ### Initialize React Native in MainActivity Source: https://www.rockjs.dev/docs/brownfield/android Initialize the React Native host manager when your Android Activity is created. This should be done before any React Native UI is displayed. ```kotlin import com.yourapp.reactnativeapp.ReactNativeHostManager class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ReactNativeHostManager.initialize(this.application) { println("JS bundle loaded") } // ... rest of your onCreate code } } ``` -------------------------------- ### Base64 Encode Keystore for Signing Source: https://www.rockjs.dev/docs/remote-cache/android This bash command demonstrates how to export a release keystore as a base64 string, which is required for signing release builds on GitHub Actions. ```bash ```bash base64 -i release.keystore | pbcopy ``` ``` -------------------------------- ### Run Rock App on Android Source: https://www.rockjs.dev/docs/getting-started Build and launch your application on an Android emulator or device using this command. ```bash rock run:android ``` -------------------------------- ### Rock Configuration Options Source: https://www.rockjs.dev/docs/configuration An overview of all available configuration options for a Rock project. These include settings for the root directory, React Native version, bundler, platforms, and more. ```typescript { // Optional: Root directory of your project root?: string; // Optional: React Native version being used reactNativeVersion?: string; // Optional: Custom path to React Native in node_modules reactNativePath?: string; // Optional: Custom bundler plugin bundler?: PluginType; // Optional: Array of plugins plugins?: Array; // Optional: Platform-specific configurations platforms?: Record; // Optional: Additional commands commands?: Array; // Optional: Configure remote cache provider. Currently supports: 'github-actions' or custom provider (function). remoteCacheProvider?: 'github-actions' | () => RemoteBuildCache | null; // Optional: Configure fingerprint options. fingerprint?: { // Additional source files/directories to include in fingerprint calculation extraSources?: string[]; // Paths to ignore when calculating fingerprints ignorePaths?: string[]; // Environmental variables that should affect fingerprints env?: string[]; }, // Optional: Whether to use prebuilt RN Core. Defaults to true. usePrebuiltRNCore?: boolean; } ``` -------------------------------- ### Basic Rock CLI Usage Source: https://www.rockjs.dev/docs/cli/introduction This is the basic command structure for interacting with the Rock CLI. Use this to execute various commands and options. ```shell npx rock [command] [options] ``` -------------------------------- ### Platform Configuration Source: https://www.rockjs.dev/docs/configuration Configure platform-specific functionality, such as building and running projects on iOS or Android, by importing and using platform plugins. ```APIDOC ## Platforms Platform is a plugin that registers platform-specific functionality such as commands to build the project and run it on a device or simulator. By default, Rock ships with two platforms: iOS (`@rock-js/platform-ios`) and Android (`@rock-js/platform-android`). You can configure the platform like this: ```javascript import { platformIOS } from '@rock-js/platform-ios'; export default { // ... platforms: { // config is optional; it translates to `project` config from react-native.config.js file ios: platformIOS(config), }, }; ``` ``` -------------------------------- ### Configure Rock CLI GitHub Actions for Android Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Set up a GitHub Actions workflow for remote Android builds using the Rock CLI. ```yaml - name: Rock Remote Build - Android id: rock-remote-build-android uses: callstackincubator/android@v3 with: variant: debug github-token: ${{ secrets.GITHUB_TOKEN }} ``` -------------------------------- ### Configure Maven Publishing Source: https://www.rockjs.dev/docs/brownfield/android Sets up Maven publishing for an Android library, including custom POM configuration to exclude specific dependencies and a task to clean up the module file. ```groovy plugins { id("com.android.library") id("org.jetbrains.kotlin.android") id("com.facebook.react") id("com.callstack.react.brownfield") `maven-publish` } ``` ```groovy import groovy.json.JsonOutput import groovy.json.JsonSlurper publishing { publications { create("mavenAar") { groupId = "com.yourapp" artifactId = "reactnativeapp" version = "0.0.1-local" afterEvaluate { from(components.getByName("default")) } pom { withXml { /** * As a result of `from(components.getByName("default")` all of the project * dependencies are added to `pom.xml` file. We do not need the react-native * third party dependencies to be a part of it as we embed those dependencies. */ val dependenciesNode = (asNode().get("dependencies") as groovy.util.NodeList).first() as groovy.util.Node dependenciesNode.children() .filterIsInstance() .filter { (it.get("groupId") as groovy.util.NodeList).text() == rootProject.name } .forEach { dependenciesNode.remove(it) } } } } } repositories { mavenLocal() // Publishes to the local Maven repository (~/.m2/repository by default) } } val moduleBuildDir: Directory = layout.buildDirectory.get() /** * As a result of `from(components.getByName("default")` all of the project * dependencies are added to `module.json` file. We do not need the react-native * third party dependencies to be a part of it as we embed those dependencies. */ tasks.register("removeDependenciesFromModuleFile") { doLast { file("$moduleBuildDir/publications/mavenAar/module.json").run { val json = inputStream().use { JsonSlurper().parse(it) as Map } (json["variants"] as? List>)?.forEach { (it["dependencies"] as? MutableList>)?.removeAll { it["group"] == rootProject.name } } writer().use { it.write(JsonOutput.prettyPrint(JsonOutput.toJson(json))) } } } } tasks.named("generateMetadataFileForMavenAarPublication") { finalizedBy("removeDependenciesFromModuleFile") } ``` -------------------------------- ### Download Artifact with Rock.js Source: https://www.rockjs.dev/docs/configuration Downloads an artifact from S3 and returns it as a Web Response. Appends '.zip' to artifactName and includes 'content-length' header. ```typescript async download({ artifactName }) { const res = await this.s3.send( new GetObjectCommand({ Bucket: this.bucket, Key: `${this.directory}/${artifactName}.zip`, }) ); return new Response(toWebStream(res.Body), { headers: { 'content-length': String(res.ContentLength ?? ''), }, }); } ``` -------------------------------- ### Upload iOS App for Ad-hoc Distribution Source: https://www.rockjs.dev/docs/cli/introduction Upload your built iOS app for ad-hoc distribution using the Rock CLI. Traits should include 'device' and 'Release'. ```shell npx rock remote-cache upload --ad-hoc --platform ios --traits device,Release ``` -------------------------------- ### Upload Android App for Ad-hoc Distribution Source: https://www.rockjs.dev/docs/cli/introduction Upload your built Android app for ad-hoc distribution. Ensure the traits match your build variant, such as 'release'. ```shell npx rock remote-cache upload --ad-hoc --platform android --traits release ``` -------------------------------- ### Build Android App for Ad-hoc Distribution Source: https://www.rockjs.dev/docs/cli/introduction Build your Android application for ad-hoc distribution. This requires signing with a keystore; use a signed variant like 'release'. ```shell npx rock build:android --variant release # ...other required flags ``` -------------------------------- ### Build iOS App for Simulator Source: https://www.rockjs.dev/docs/remote-cache/ios Use this snippet to build a debuggable .app file for iOS simulators. It does not require code signing. ```yaml - name: Rock Remote Build - iOS simulator id: rock-remote-build-ios uses: callstackincubator/ios@v3 with: destination: simulator github-token: ${{ secrets.GITHUB_TOKEN }} configuration: Debug ``` -------------------------------- ### Configure iOS Device Build in GitHub Actions Source: https://www.rockjs.dev/docs/remote-cache/ios Set up a GitHub Actions workflow to perform a remote iOS device build. Ensure all required secrets for code signing are configured in your repository. ```yaml - name: Rock Remote Build - iOS device id: rock-remote-build-ios uses: callstackincubator/ios@v3 with: destination: device github-token: ${{ secrets.GITHUB_TOKEN }} configuration: Release 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' keychain-password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} ``` -------------------------------- ### Configure Rock CLI GitHub Actions for iOS Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Set up a GitHub Actions workflow for remote iOS builds using the Rock CLI. ```yaml - name: Rock Remote Build - iOS simulator id: rock-remote-build-ios uses: callstackincubator/ios@v3 with: destination: simulator github-token: ${{ secrets.GITHUB_TOKEN }} configuration: Debug ``` -------------------------------- ### Initialize React Native Host Manager Source: https://www.rockjs.dev/docs/brownfield/android Encapsulates react-native-brownfield initialization. The `loadReactNative` call is conditional based on React Native version. ```kotlin package com.yourapp.reactnativeapp // If you used a different package name when creating the library, change it here import android.app.Application import com.callstack.reactnativebrownfield.OnJSBundleLoaded import com.callstack.reactnativebrownfield.ReactNativeBrownfield import com.facebook.react.PackageList import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative object ReactNativeHostManager { fun initialize(application: Application, onJSBundleLoaded: OnJSBundleLoaded? = null) { loadReactNative(application) // Only required if you're on RN version >= 0.80.0 val packageList = PackageList(application).packages ReactNativeBrownfield.initialize(application, packageList, onJSBundleLoaded) } } ``` -------------------------------- ### Dummy Local Cache Provider Implementation Source: https://www.rockjs.dev/docs/configuration Implements the RemoteBuildCache interface for local caching. Useful for testing or environments without a remote cache server. Requires 'fs' module. ```typescript import type { RemoteBuildCache } from '@rock-js/tools'; import fs from 'fs'; class DummyLocalCacheProvider implements RemoteBuildCache { name = 'dummy'; async list({ artifactName }) { const url = new URL(`${artifactName}.zip`, import.meta.url); return [{ name: artifactName, url }]; } async download({ artifactName }) { const artifacts = await this.list({ artifactName }); const filePath = artifacts[0].url.pathname; const fileStream = fs.createReadStream(filePath); return new Response(fileStream); } async delete({ artifactName }) { // optional... } async upload({ artifactName, uploadArtifactName }) { // optional... } } const pluginDummyLocalCacheProvider = (options) => () => new DummyLocalCacheProvider(options); ``` -------------------------------- ### Run Android Release Build on GitHub Actions Source: https://www.rockjs.dev/docs/remote-cache/android Use this snippet to build an APK in release variants for testing. It requires signing and specific GitHub secrets to be configured. ```yaml ```yaml - name: Rock Remote Build - Android device id: rock-remote-build-android uses: callstackincubator/android@v3 with: variant: release github-token: ${{ secrets.GITHUB_TOKEN }} # if you need to sign with non-debug keystore sign: true keystore-base64: ${{ secrets.KEYSTORE_BASE64 }} keystore-store-file: ${{ secrets.ROCK_UPLOAD_STORE_FILE }} keystore-store-password: ${{ secrets.ROCK_UPLOAD_STORE_PASSWORD }} keystore-key-alias: ${{ secrets.ROCK_UPLOAD_KEY_ALIAS }} keystore-key-password: ${{ secrets.ROCK_UPLOAD_KEY_PASSWORD }} ``` ``` -------------------------------- ### Export Provisioning Profile to Base64 Source: https://www.rockjs.dev/docs/remote-cache/ios This command exports a provisioning profile to base64 format, which is required for storing it as a GitHub secret for CI builds. ```bash base64 -i PROVISIONING_PROFILE.mobileprovision | pbcopy ``` -------------------------------- ### Configure .gitignore for Rock CLI Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Add the `.rock/` cache directory to your `.gitignore` file to prevent it from being tracked by Git. ```gitignore .rock/ ``` -------------------------------- ### Compile iOS XCFramework Source: https://www.rockjs.dev/docs/brownfield/ios Use this command in Terminal to compile frameworks for Hermes, React Native Brownfield library, and your app. Replace `` with your specific target name. ```sh rock package:ios --scheme --configuration Release ``` -------------------------------- ### Add Maven Local Repository to settings.gradle.kts Source: https://www.rockjs.dev/docs/brownfield/android Configure your app's build to resolve dependencies from the local Maven repository. ```groovy dependencyResolutionManagement { repositories { mavenLocal() } } ``` -------------------------------- ### Configure Fingerprint Settings in Rock.js Source: https://www.rockjs.dev/docs/configuration Customizes fingerprinting behavior for cache invalidation. Use `extraSources` for git submodules, `ignorePaths` for irrelevant directories, and `env` for affecting variables. ```javascript export default { // ... fingerprint: { extraSources: ['./git-submodule'], ignorePaths: ['./temp'], env: [process.env.CUSTOM_ENV], }, }; ``` -------------------------------- ### Download and Unpack Android APK Artifact Source: https://www.rockjs.dev/docs/remote-cache/android This script downloads an APK artifact using its ID, unzips it, and sets the APK path as an environment variable for subsequent steps. Ensure the GitHub token has the necessary permissions. ```bash curl -L -H "Authorization: token ${{ github.token }}" -o artifact.zip "https://api.github.com/repos/${{ github.repository }}/actions/artifacts/${{ needs.build-release.outputs.artifact-id }}/zip" unzip artifact.zip -d downloaded-artifacts ls -l downloaded-artifacts APK_PATH=$(find downloaded-artifacts -name "*.apk" -print -quit) echo "ARTIFACT_PATH_FOR_E2E=$APK_PATH" >> $GITHUB_ENV ``` -------------------------------- ### download Source: https://www.rockjs.dev/docs/configuration Returns a Web Response with a readable stream of the artifact and its content-length header. Used for download progress reporting. ```APIDOC ## download ### Description Return a Web `Response` whose `body` is a readable stream of the artifact and (if available) a `content-length` header. Rock uses this to report download progress. :::info The artifacts are uploaded as ZIP archives (excluding ad-hoc scenario), so make sure to append the `.zip` suffix to the `artifactName`. ::: If your SDK returns a Node stream, convert it to a Web stream and wrap in `Response`: ```ts function toWebStream(node: Readable): ReadableStream { return new ReadableStream({ start(controller) { node.on('data', (chunk) => controller.enqueue(chunk)); node.on('end', () => controller.close()); node.on('error', (e) => controller.error(e)); }, }); } async download({ artifactName }) { const res = await this.s3.send( new GetObjectCommand({ Bucket: this.bucket, Key: `${this.directory}/${artifactName}.zip`, }) ); return new Response(toWebStream(res.Body), { headers: { 'content-length': String(res.ContentLength ?? ''), }, }); } ``` ``` -------------------------------- ### Migrate Project Configuration to Rock CLI Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Translate project-specific configurations from `react-native.config.js` to the platform arguments in `rock.config.mjs`. ```javascript export default { platforms: { ios: platformIOS({ sourceDir: 'custom-source' }), android: platformAndroid({ appName: 'custom' }), }, }; ``` -------------------------------- ### Build iOS App for Ad-hoc Distribution Source: https://www.rockjs.dev/docs/cli/introduction Build your iOS application for ad-hoc distribution. Ensure your provisioning profile includes your testers' devices. ```shell npx rock build:ios --archive # ...other required flags ``` -------------------------------- ### Configure Autolinking for React Native Libraries Source: https://www.rockjs.dev/docs/brownfield/android Set up autolinking for libraries within the `react` block in your `reactnativeapp/build.gradle.kts` file. ```groovy react { autolinkLibrariesWithApp() } ``` -------------------------------- ### Download and Unpack iOS IPA Artifact Source: https://www.rockjs.dev/docs/remote-cache/ios This script downloads the IPA artifact using its ID, unpacks it, and sets the path to the IPA file as an environment variable for subsequent steps. Ensure you have the correct GitHub token and repository information. ```bash curl -L -H "Authorization: token ${{ github.token }}" -o artifact.zip "https://api.github.com/repos/${{ github.repository }}/actions/artifacts/${{ needs.build-release.outputs.artifact-id }}/zip" unzip artifact.zip -d downloaded-artifacts ls -l downloaded-artifacts IPA_PATH=$(find downloaded-artifacts -name "*.ipa" -print -quit) echo "ARTIFACT_PATH_FOR_E2E=$IPA_PATH" >> $GITHUB_ENV ``` -------------------------------- ### upload Source: https://www.rockjs.dev/docs/configuration Initiates an artifact upload, returning metadata and a `getResponse` function for progress signaling. Supports different buffer types and content types. ```APIDOC ## upload ### Description Rock expects `upload()` to return metadata and a `getResponse` function: * `getResponse(buffer, contentType?) => Response`: * Rock calls this to initiate the upload and to surface upload progress * It passes either: * a `Buffer` (for normal builds), or * a function `(baseUrl) => Buffer` (for ad‑hoc pages) so you can inject absolute URLs into HTML/plist before upload * You should start the actual upload here and return a `Response` object * Rock will read that stream to display progress * for ad-hoc scenario `upload` will pass the `uploadArtifactName` variable, so use that instead of `artifactName` **For progress signaling, you can:** * Stream the original buffer in chunks, or * Use your SDK's progress events (e.g. S3's `httpUploadProgress`) to enqueue chunks proportional to actual bytes uploaded **Example (S3-like) using real SDK progress:** ```ts async upload({ artifactName, uploadArtifactName }) { const key = uploadArtifactName ? `${this.directory}/${uploadArtifactName}` : `${this.directory}/${artifactName}.zip`; const presignedUrl = await getSignedUrl(/* ... */); return { name: artifactName, url: presignedUrl, getResponse: (buffer, contentType) => { const upload = new Upload({ client: this.s3, params: { Bucket: this.bucket, Key: key, Body: buffer, ContentType: contentType ?? 'application/octet-stream', Metadata: { createdAt: new Date().toISOString() }, }, }); const stream = new ReadableStream({ start(controller) { let last = 0; upload.on('httpUploadProgress', ({ loaded, total }) => { if (loaded != null && total != null && loaded > last) { controller.enqueue(buffer.subarray(last, loaded)); last = loaded; if (loaded >= total) controller.close(); } }); upload.done().catch((e) => controller.error(e)); }, }); return new Response(stream, { headers: { 'content-length': String(buffer.length), 'content-type': contentType ?? 'application/octet-stream', }, }); }, }; } ``` ``` -------------------------------- ### Initialize React Native in AppDelegate Source: https://www.rockjs.dev/docs/brownfield/ios Integrate React Native into your native iOS app by initializing it in `AppDelegate.swift` and presenting it using `ReactNativeViewController`. Ensure the `moduleName` matches the component registered with `AppRegistry.registerComponent` in your React Native app. ```swift import @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Initialize React Native ReactNativeBrownfield.shared.bundle = ReactNativeBundle ReactNativeBrownfield.shared.startReactNative(onBundleLoaded: { print("React Native bundle loaded") }, launchOptions: launchOptions) // Add `window` property required by React Native window = UIWindow(frame: UIScreen.main.bounds) // Create VC that calls your module by name registered by `AppRegistry.registerComponent` of your React Native app let reactNativeVC = ReactNativeViewController(moduleName: "ReactNativeApp") // Display the view as full window or anyhow you need window?.rootViewController = reactNativeVC window?.makeKeyAndVisible() } } ``` -------------------------------- ### Upload Artifact with Rock.js using SDK Progress Source: https://www.rockjs.dev/docs/configuration Uploads an artifact to S3, supporting both normal builds and ad-hoc pages. Uses SDK progress events to signal upload progress via Web Streams. ```typescript async upload({ artifactName, uploadArtifactName }) { const key = uploadArtifactName ? `${this.directory}/${uploadArtifactName}` : `${this.directory}/${artifactName}.zip`; const presignedUrl = await getSignedUrl(/* ... */); return { name: artifactName, url: presignedUrl, getResponse: (buffer, contentType) => { const upload = new Upload({ client: this.s3, params: { Bucket: this.bucket, Key: key, Body: buffer, ContentType: contentType ?? 'application/octet-stream', Metadata: { createdAt: new Date().toISOString() }, }, }); const stream = new ReadableStream({ start(controller) { let last = 0; upload.on('httpUploadProgress', ({ loaded, total }) => { if (loaded != null && total != null && loaded > last) { controller.enqueue(buffer.subarray(last, loaded)); last = loaded; if (loaded >= total) controller.close(); } }); upload.done().catch((e) => controller.error(e)); }, }); return new Response(stream, { headers: { 'content-length': String(buffer.length), 'content-type': contentType ?? 'application/octet-stream', }, }); }, }; } ``` -------------------------------- ### Generate and Publish Android AAR Source: https://www.rockjs.dev/docs/brownfield/android Use the `rock package:aar` command to create the AAR file, specifying the variant and module name. Subsequently, use `rock publish-local:aar` to make the AAR available in your local Maven repository for native app consumption. ```bash rock package:aar --variant Release --module-name reactnativeapp ``` ```bash rock publish-local:aar --module-name reactnativeapp ``` -------------------------------- ### Download Remote Cache Artifact by Traits Source: https://www.rockjs.dev/docs/cli/introduction This command downloads a remote cache artifact by specifying the platform and traits, which constructs the artifact name automatically. This is useful when the exact fingerprint is unknown. ```shell npx rock remote-cache download --platform ios --traits simulator,Release ``` -------------------------------- ### Run Rock CLI Commands Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Execute the new Rock CLI commands to run your Android or iOS application. ```sh npx rock run:android npx rock run:ios ``` -------------------------------- ### Display React Native Fragment in MainActivity Source: https://www.rockjs.dev/docs/brownfield/android Update your MainActivity to handle button clicks and replace a container with a React Native Fragment. Ensure the React Native host is initialized. ```kotlin import com.yourapp.reactnativeapp.ReactNativeHostManager import com.callstack.reactnativebrownfield.ReactNativeFragment class MainActivity : AppCompatActivity() { private lateinit var showRNAppBtn: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ReactNativeHostManager.initialize(this.application) { println("JS bundle loaded") } val rnAppFragment = ReactNativeFragment.createReactNativeFragment("BrownFieldTest") showRNAppBtn = findViewById(R.id.show_rn_app_btn) showRNAppBtn.setOnClickListener { supportFragmentManager .beginTransaction() .replace(R.id.fragmentContainer, rnAppFragment) .commit() } } } ``` -------------------------------- ### Configure GitHub PAT in Rock.js Config Source: https://www.rockjs.dev/docs/remote-cache/github-actions-setup This TypeScript snippet shows how to configure the GitHub remote cache provider in `rock.config.mjs`. It uses `dotenv` to load the `GITHUB_TOKEN` from a `.env` file, which is required for downloading cached builds. ```typescript import { providerGitHub } from '@rock-js/provider-github'; import { config } from 'dotenv'; config(); // load .env file containing GITHUB_TOKEN export default { // ...rest of the config remoteCacheProvider: providerGitHub({ owner: 'github_org', repository: 'github_repo_name', }), }; ``` -------------------------------- ### Configure GitHub Actions Provider Source: https://www.rockjs.dev/docs/configuration Use this snippet to configure the GitHub Actions provider for remote caching. Ensure GITHUB_TOKEN is loaded from a .env file. ```typescript import { providerGitHub } from '@rock-js/provider-github'; import { config } from 'dotenv'; config(); // load .env file containing GITHUB_TOKEN export default { // ...rest of the config remoteCacheProvider: providerGitHub({ owner: 'github_org', repository: 'github_repo_name', }), }; ``` -------------------------------- ### Configure Build Config Fields Source: https://www.rockjs.dev/docs/brownfield/android Adds build configuration fields for edge-to-edge display, new architecture, and Hermes engine to the Android build. ```groovy android { defaultConfig { minSdk = 24 buildConfigField("boolean", "IS_EDGE_TO_EDGE_ENABLED", properties["edgeToEdgeEnabled"].toString()) buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", properties["newArchEnabled"].toString()) buildConfigField("boolean", "IS_HERMES_ENABLED", properties["hermesEnabled"].toString()) } publishing { multipleVariants { allVariants() } } } ``` -------------------------------- ### getDefaultConfig(projectRoot) Source: https://www.rockjs.dev/docs/configuration Returns the default Metro configuration. This function is re-exported from `@react-native/metro-config`. ```APIDOC ## `getDefaultConfig(projectRoot)` ### Description Returns the default Metro configuration. Re-exported from `@react-native/metro-config`. ### Parameters #### Path Parameters * **projectRoot** (`string`) - Required - The root directory of your project (usually `__dirname`) ### Returns * `MetroConfig` object ``` -------------------------------- ### Specify Working Directory for Monorepo Builds Source: https://www.rockjs.dev/docs/remote-cache/ios When working within a monorepo, use the `working-directory` input to specify the root of your iOS project if it's not at the repository's root. ```yaml - name: Rock Remote Build - iOS device id: rock-remote-build-ios uses: callstackincubator/ios@v3 with: destination: device github-token: ${{ secrets.GITHUB_TOKEN }} working-directory: ./packages/mobile ``` -------------------------------- ### Remote Cache Configuration Source: https://www.rockjs.dev/docs/configuration Configure remote build caching to speed up development by storing and retrieving native build artifacts from remote storage providers like S3 or GitHub Actions. ```APIDOC ## Remote Cache Configuration One of the key features of Rock is remote build caching to speed up your development workflow. By remote cache we mean native build artifacts (e.g. APK, or IPA binaries), which are discoverable by the user and available for download. Remote cache can live on any static storage provider, such as S3, R2, or GitHub Artifacts. For Rock to know how and where to access this cache, you'll need to define `remoteCacheProvider`, which can be either bundled with the framework (such as the one for GitHub Actions) or a custom one that you can provide. When `remoteCacheProvider` is set, the CLI will: 1. Look at local cache under `.rock/` directory for builds downloaded from a remote cache. 2. If not found, it will look for a remote build matching your local native project state (a fingerprint). 3. If not found, it will fall back to local build. Available providers you can use: * [@rock-js/provider-github](#github-actions-provider): store artifacts on GitHub Workflow Artifacts * [@rock-js/provider-s3](#aws-s3-provider): store artifacts on S3 (or Cloudflare R2) In case you would like to store native build artifacts in a different kind of remote storage, you can implement your own [custom provider](#custom-remote-cache-provider). ### Uploading artifacts to remote storage Regardless of remote cache provider set, to download native build artifats from a remote storage, you'll need to upload them first, ideally in a continuous manner. That's why the best place to put the upload logic would be your Continuous Integration server. Rock provides out-of-the-box GitHub Actions for: * [`callstackincubator/ios`](https://github.com/callstackincubator/ios): action for iOS compatible with `@rock-js/provider-github` * [`callstackincubator/android`](https://github.com/callstackincubator/android): action for Android compatible with `@rock-js/provider-github` For other CI providers you'll need to manage artifacts yourself. We recommend mimicking the GitHub Actions setup on your CI server. ``` -------------------------------- ### Run Android Debug Build on GitHub Actions Source: https://www.rockjs.dev/docs/remote-cache/android Use this snippet to build an APK in debug variants for development. It does not require signing. ```yaml ```yaml - name: Rock Remote Build - Android id: rock-remote-build-android uses: callstackincubator/android@v3 with: variant: debug github-token: ${{ secrets.GITHUB_TOKEN }} ``` ``` -------------------------------- ### Apply Brownfield Plugin in Android Library Source: https://www.rockjs.dev/docs/brownfield/android Apply the necessary plugins, including `com.callstack.react.brownfield`, to your `reactnativeapp/build.gradle.kts` file. ```groovy plugins { id("com.android.library") id("org.jetbrains.kotlin.android") id("com.facebook.react") id("com.callstack.react.brownfield") } ``` -------------------------------- ### Download Remote Cache Artifact by Name Source: https://www.rockjs.dev/docs/cli/introduction Use this command to download a specific artifact from the remote cache using its full name, including the fingerprint. ```shell npx rock remote-cache download --name rock-ios-simulator-Release-abc123fbd28298 ``` -------------------------------- ### Pass Extra Parameters to Rock Build Command Source: https://www.rockjs.dev/docs/remote-cache/android Use the `rock-build-extra-params` input to pass custom parameters to the `rock build:android` command, such as building an Android App Bundle (`--aab`). ```yaml ```yaml - name: Rock Remote Build - Android id: rock-remote-build-android uses: callstackincubator/android@v3 with: variant: release github-token: ${{ secrets.GITHUB_TOKEN }} rock-build-extra-params: '--aab' # build an Android App Bundle for the Play Store ``` ``` -------------------------------- ### Update iOS Podfile for Rock CLI Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Modify the `ios/Podfile` to use the Rock CLI for native module linking. ```ruby # config = use_native_modules! config = use_native_modules!(['npx', 'rock', 'config', '-p', 'ios']) ``` -------------------------------- ### Configure Metro for Monorepo Source: https://www.rockjs.dev/docs/configuration Extend Metro's watch folders and node module paths to support monorepo structures. This ensures the bundler can find modules across different packages in your workspace. ```javascript const path = require('path'); const { getDefaultConfig, mergeConfig } = require('@rock-js/plugin-metro'); const projectRoot = __dirname; const workspaceRoot = path.resolve(projectRoot, '../..'); const config = getDefaultConfig(projectRoot); module.exports = mergeConfig(config, { watchFolders: [workspaceRoot], resolver: { nodeModulesPaths: [ path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules'), ], }, }); ``` -------------------------------- ### Metro Bundler Bundle Command Source: https://www.rockjs.dev/docs/cli/introduction Bundles JavaScript code using the Metro bundler via the @rock-js/plugin-metro plugin. This is typically used for creating production builds. ```shell bundle ``` -------------------------------- ### Update Android Settings Gradle for Rock CLI Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Adjust `android/settings.gradle` to use the Rock CLI for autolinking libraries. ```groovy // extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand(['npx', 'rock', 'config', '-p', 'android']) } ``` -------------------------------- ### Configure Xcode Build Phase for Rock CLI Source: https://www.rockjs.dev/docs/cli/migrating-from-community-cli Update the 'Bundle React Native code and images' Build Phase in Xcode to use the Rock CLI for environment variables and path resolution. ```shell set -e if [[ -f "$PODS_ROOT/../.xcode.env" ]]; then source "$PODS_ROOT/../.xcode.env" fi if [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then source "$PODS_ROOT/../.xcode.env.local" fi export CONFIG_CMD="dummy-workaround-value" export CLI_PATH="$($NODE_BINARY --print \"require('path').dirname(require.resolve('rock/package.json')) + '/dist/src/bin.js'\")" WITH_ENVIRONMENT="$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh" ``` -------------------------------- ### Optimize GitHub Actions with paths-ignore Source: https://www.rockjs.dev/docs/remote-cache/github-actions-setup This YAML configuration demonstrates how to use `paths-ignore` in a GitHub Actions workflow to prevent the workflow from running when changes occur in specified files or directories. This is useful for skipping mobile builds when only documentation or web code is modified. ```yaml name: Mobile Build on: push: branches: - main paths-ignore: - '*.md' # Skip documentation changes - 'docs/**' # Skip documentation directory - '.github/ISSUE_TEMPLATE/**' # Skip issue templates - 'web/**' # Skip web-specific code - 'server/**' # Skip backend code - 'design/**' # Skip design files # You can set similar config for pull_request hook ```