### Install example app dependencies Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Installs dependencies for the example React Native app. It's recommended to run `bun install --frozen-lockfile` from the repo root first, then navigate to the `example` directory and run `bun install`. This step is crucial for `bun run typecheck:example` as it relies on devDependencies installed within the example app. ```bash # From repo root bun install --frozen-lockfile # Then install example dependencies cd example bun install ``` -------------------------------- ### Install iOS example app dependencies and run Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Installs Ruby dependencies and CocoaPods for the iOS example app, then provides instructions to run it. This requires macOS and Xcode. After running `bundle exec pod install`, you can open the `.xcworkspace` in Xcode or run the app from the `example` directory using `bun ios`. ```bash cd example/ios && bundle install && bundle exec pod install # Then open the .xcworkspace in Xcode or run: cd example && bun ios ``` -------------------------------- ### Start example app Metro bundler Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Starts the Metro bundler for the example React Native application. Ensure you are in the `example` directory before running this command. ```bash cd example && bun start ``` -------------------------------- ### Build Android example app Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Builds a debug version of the Android example app using Gradle. This requires the Android SDK and an emulator or physical device to be set up. Navigate to the `example/android` directory before executing. ```bash cd example/android && ./gradlew assembleDebug ``` -------------------------------- ### Run Android native tests from example app Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Executes Gradle tasks within the example app's Android directory to verify library autolinking, run unit tests for the library module, and generate a Jacoco coverage report. This confirms the native library integrates correctly and meets coverage standards. ```bash cd example/android # Verify the library module is autolinked ./gradlew projects # Run library unit tests ./gradlew :rnforge_react-native-in-app-updates:testDebugUnitTest # Generate the Android JVM coverage report ./gradlew :rnforge_react-native-in-app-updates:jacocoDebugUnitTestReport ``` -------------------------------- ### Run TypeScript Type Checking for Example Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Perform TypeScript type checking specifically for the example directory using the 'typecheck:example' script. ```bash # TypeScript type checking (example/) bun run typecheck:example ``` -------------------------------- ### Start Flexible Update on Android Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Initiates a flexible update flow on Android, presenting a non-blocking UI for background download. On iOS and non-Play Android installs, it returns `supported: false`. ```typescript import { startFlexibleUpdate } from '@rnforge/react-native-in-app-updates' const result = await startFlexibleUpdate() console.log(result.reason) // 'update-available', 'update-not-allowed', etc. ``` -------------------------------- ### startFlexibleUpdate Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Starts an Android flexible update flow. Presents a non-blocking Play Core snackbar/banner that begins a background download. On iOS and non-Play Android installs, it returns `supported: false` with a typed reason. ```APIDOC ## startFlexibleUpdate(options?) ### Description Starts an Android flexible update flow. Presents a non-blocking Play Core snackbar/banner that begins a background download. ### Method `startFlexibleUpdate` ### Parameters #### Options - `options` (object) - Optional - `android.allowAssetPackDeletion` (boolean) - Optional - Defaults to `false`. Opt-in to allow Play Core to delete asset packs under storage pressure during the flexible update flow. ### Request Example ```typescript // Basic usage const result = await startFlexibleUpdate() console.log(result.reason) // 'update-available', 'update-not-allowed', etc. // Opt-in to asset-pack deletion during flexible update await startFlexibleUpdate({ android: { allowAssetPackDeletion: true } }) ``` ### Response - `reason` (string) - Indicates the status of the update flow (e.g., 'update-available', 'update-not-allowed'). - `supported` (boolean) - Indicates if the platform supports this feature. ``` -------------------------------- ### Start Immediate Update Flow Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Initiate an immediate update flow on Android. This presents a full-screen dialog that blocks the user until they accept or decline. On iOS or non-Play Android installs, it returns `supported: false`. ```typescript import { startImmediateUpdate } from '@rnforge/react-native-in-app-updates' const result = await startImmediateUpdate() console.log(result.reason) // 'update-available', 'update-not-allowed', 'unsupported-install-source', etc. ``` -------------------------------- ### Install @rnforge/react-native-in-app-updates Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Add the package and its peer dependency to your project using bun, npm, or yarn. ```bash bun add @rnforge/react-native-in-app-updates react-native-nitro-modules # or npm install @rnforge/react-native-in-app-updates react-native-nitro-modules # or yarn add @rnforge/react-native-in-app-updates react-native-nitro-modules ``` -------------------------------- ### addInstallStateListener Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Registers a callback to listen for changes in the download and installation progress of flexible in-app updates. It returns a subscription object that can be used to unsubscribe from further updates. ```APIDOC ## `addInstallStateListener(callback)` — Listen to flexible update download and install progress Registers a callback that fires on every install-state change during a flexible update's download and install lifecycle. Returns a subscription object with a `remove()` method. On iOS, fires a single event with `supported: false` and `reason: 'unsupported-platform'`, then becomes a no-op subscription. ### Parameters #### Callback Function - **callback** (function) - Required - A function that will be called with an `InstallStateEvent` object on each state change. ### Event Object (`InstallStateEvent`) - **platform** (string) - The platform ('android' or 'ios'). - **supported** (boolean) - Indicates if the feature is supported on the current platform. - **reason** (string) - The reason for the event (e.g., 'download-progress', 'flexible-update-downloaded', 'unsupported-platform'). - **installStatus** (string) - The current status of the installation (e.g., 'unknown', 'pending', 'downloading', 'downloaded', 'installing', 'installed', 'failed', 'canceled', 'unsupported'). - **progress** (number) - Optional. The download progress as a float between 0.0 and 1.0, available when `installStatus` is 'downloading'. - **errorCode** (string) - Optional. An error code if the installation failed. - **android** (object) - Optional. Android-specific details. - **playCore** (object) - Optional. Play Core library details. - **installErrorCode** (string) - The install error code from Play Core. ### Returns - **InstallStateSubscription** - An object with a `remove()` method to unsubscribe from the listener. ``` -------------------------------- ### Listen to Install State Changes Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Subscribes to events related to Android flexible update progress and install status. On iOS, it fires a single event indicating an unsupported platform and becomes a no-op. ```typescript import { addInstallStateListener } from '@rnforge/react-native-in-app-updates' const subscription = addInstallStateListener((event) => { console.log(event.platform) // 'android' | 'ios' console.log(event.supported) // boolean console.log(event.installStatus) // 'downloading' | 'downloaded' | 'installing' | 'failed' | ... console.log(event.reason) // 'download-progress' | 'install-state-changed' console.log(event.bytesDownloaded) // number console.log(event.totalBytesToDownload) // number console.log(event.progress) // 0.0 - 1.0 console.log(event.android?.playCore) // raw Play Core details }) // Remove listener when done subscription.remove() ``` -------------------------------- ### Listen to Flexible Update Download and Install Progress Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Registers a callback to receive updates on the download and install status of flexible in-app updates. Ensure to call `remove()` on the returned subscription when the component unmounts to prevent memory leaks. On iOS, this listener will fire a single event with `supported: false` and `reason: 'unsupported-platform'` and then become a no-op. ```typescript import { addInstallStateListener, type InstallStateSubscription, type InstallStateEvent, } from '@rnforge/react-native-in-app-updates' import { useEffect, useRef } from 'react' function useFlexibleUpdateProgress(onDownloaded: () => void) { const subscriptionRef = useRef(null) useEffect(() => { subscriptionRef.current = addInstallStateListener((event: InstallStateEvent) => { console.log('platform:', event.platform) // 'android' | 'ios' console.log('supported:', event.supported) // false on iOS console.log('reason:', event.reason) // 'download-progress' | 'install-state-changed' | 'flexible-update-downloaded' // | 'unsupported-platform' | ... console.log('installStatus:', event.installStatus) // 'unknown' | 'pending' | 'downloading' | 'downloaded' | // 'installing' | 'installed' | 'failed' | 'canceled' | 'unsupported' if (event.installStatus === 'downloading' && event.progress != null) { console.log(`Progress: ${(event.progress * 100).toFixed(1)}%`) // event.progress is computed as bytesDownloaded / totalBytesToDownload (0.0–1.0) } if (event.installStatus === 'failed') { console.warn('Install failed, errorCode:', event.errorCode) } if (event.installStatus === 'downloaded') { onDownloaded() } // Android-only raw details if (event.android?.playCore) { console.log('Play Core install error code:', event.android.playCore.installErrorCode) } }) return () => { subscriptionRef.current?.remove() subscriptionRef.current = null } }, [onDownloaded]) } ``` -------------------------------- ### Complete Downloaded Flexible Update Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Applies a flexible update that has already been downloaded. Call this when the install status is 'downloaded'. If no downloaded update is pending, it returns 'update-not-allowed' without throwing. ```typescript import { getUpdateStatus, completeFlexibleUpdate, canCompleteFlexibleUpdate, InAppUpdatesError, } from '@rnforge/react-native-in-app-updates' async function applyDownloadedUpdate() { const status = await getUpdateStatus() if (!canCompleteFlexibleUpdate(status)) { // No downloaded update is pending console.log('No flexible update ready to complete, reason:', status.reason) return } try { const result = await completeFlexibleUpdate() // result.reason === 'flexible-update-downloaded' means install was triggered // result.reason === 'update-not-allowed' means no downloaded update was pending console.log('Complete result:', result.reason) } catch (err) { if (err instanceof InAppUpdatesError) { console.error(`[${err.code}] ${err.message}`) } } } ``` -------------------------------- ### startImmediateUpdate Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Starts an Android immediate update flow. Presents a full-screen Play Core dialog that blocks the user until they accept or decline. ```APIDOC ## startImmediateUpdate(options?) ### Description Starts an Android immediate update flow. Presents a full-screen Play Core dialog that blocks the user until they accept or decline. ### Method `startImmediateUpdate` ### Endpoint None (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None #### Options - `android.allowAssetPackDeletion` (boolean) - Optional. Opt-in to allow Play Core to delete asset packs under storage pressure during the immediate update flow. Defaults to `false`. ### Request Example ```typescript import { startImmediateUpdate, } from '@rnforge/react-native-in-app-updates' // Basic usage await startImmediateUpdate() // With Android option await startImmediateUpdate({ android: { allowAssetPackDeletion: true } }) ``` ### Response #### Success Response Returns an object with a `reason` field indicating the outcome of the update attempt. - `reason` (string): e.g., `'update-available'`, `'update-not-allowed'`, `'unsupported-install-source'`, etc. #### Response Example ```json { "reason": "update-available" } ``` ### Notes - On Android Play installs: triggers the Play immediate UI. App may restart if the user accepts. - On iOS and non-Play Android installs: returns `supported: false` with a typed reason. No silent noop. ``` -------------------------------- ### Start Flexible Update Flow (Android Play) Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Initiates a non-blocking background download for updates on Android Play. The user can continue using the app during download. Requires calling `completeFlexibleUpdate()` after download is complete. Returns 'supported: false' on iOS and non-Play Android. ```typescript import { getUpdateStatus, startFlexibleUpdate, addInstallStateListener, canStartFlexibleUpdate, InAppUpdatesError, type InstallStateSubscription, } from '@rnforge/react-native-in-app-updates' async function triggerFlexibleUpdate() { const status = await getUpdateStatus() if (!canStartFlexibleUpdate(status)) { console.log('Flexible update not available:', status.reason) return } // Register listener before starting the flow to capture all progress events let subscription: InstallStateSubscription | null = null subscription = addInstallStateListener((event) => { console.log('Install status:', event.installStatus) // 'pending' | 'downloading' | 'downloaded' | 'installing' | 'installed' | 'failed' | 'canceled' if (typeof event.progress === 'number') { console.log(`Download progress: ${(event.progress * 100).toFixed(1)}%`) console.log(`Bytes: ${event.bytesDownloaded} / ${event.totalBytesToDownload}`) } if (event.installStatus === 'downloaded') { console.log('Update ready — call completeFlexibleUpdate()') subscription?.remove() } }) try { const result = await startFlexibleUpdate({ android: { allowAssetPackDeletion: false }, }) console.log('Flexible update initiated, reason:', result.reason) // 'update-available' means the Play download dialog was shown } catch (err) { subscription.remove() if (err instanceof InAppUpdatesError) { console.error(`[${err.code}] ${err.message}`) } } } ``` -------------------------------- ### Start Immediate Update Flow (Android Play) Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Triggers a full-screen, blocking update flow on Android Play. Use when an immediate update is critical. Returns 'supported: false' on iOS and non-Play Android. ```typescript import { getUpdateStatus, startImmediateUpdate, canStartImmediateUpdate, InAppUpdatesError, } from '@rnforge/react-native-in-app-updates' async function triggerImmediateUpdate() { const status = await getUpdateStatus() if (!canStartImmediateUpdate(status)) { // Reason could be: 'no-update-available', 'update-not-allowed', // 'unsupported-install-source', 'unsupported-platform', etc. console.log('Immediate update not available:', status.reason) return } try { const result = await startImmediateUpdate({ android: { allowAssetPackDeletion: true }, // optional; only for Play Asset Delivery apps }) // result.reason after the flow: // 'update-available' — user accepted; app may restart // 'update-not-allowed' — Play policy denied the flow console.log('Immediate update result:', result.reason) } catch (err) { if (err instanceof InAppUpdatesError) { console.error(`[${err.code}] ${err.message}`) // err.android?.playCore?.taskErrorCode for Play Core task failure codes } } } ``` -------------------------------- ### Import Core Update Functions Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Import the necessary functions for managing in-app updates from the package. These functions handle checking status, initiating updates, and listening for installation events. ```typescript import { getUpdateStatus, startImmediateUpdate, startFlexibleUpdate, completeFlexibleUpdate, openStorePage, addInstallStateListener, } from '@rnforge/react-native-in-app-updates' ``` -------------------------------- ### UpdateStatus and InstallStateEvent Type Definitions Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt These TypeScript types define the structure for update status and installation state events. They include platform-agnostic fields and optional platform-specific details for Android and iOS. Ensure all necessary types are imported from the library. ```typescript import type { UpdateStatus, InstallStateEvent, Platform, Capabilities, AllowedFlows, AndroidDetails, PlayCoreDetails, IosDetails, IosAppStoreDetails, InstallStatus, AvailabilityReason, UnsupportedReason, } from '@rnforge/react-native-in-app-updates' // UpdateStatus shape (returned by getUpdateStatus, startImmediateUpdate, // startFlexibleUpdate, completeFlexibleUpdate) const exampleStatus: UpdateStatus = { platform: 'android', // 'android' | 'ios' supported: true, updateAvailable: true, // boolean | null (null when unsupported) reason: 'update-available', capabilities: { immediate: true, flexible: true, storePage: true, latestVersionLookup: false, installStateListener: true, }, allowed: { immediate: true, flexible: true }, currentVersion: '1.2.3', currentBuild: 10, latestStoreVersion: '1.3.0', latestStoreBuild: 11, installStatus: 'unknown', android: { packageName: 'com.example.app', playCore: { updateAvailability: 'UPDATE_AVAILABLE', availableVersionCode: 11, clientVersionStalenessDays: 5, updatePriority: 3, immediateAllowed: true, flexibleAllowed: true, }, }, } // InstallStateEvent shape (delivered to addInstallStateListener callback) const exampleEvent: InstallStateEvent = { platform: 'android', supported: true, installStatus: 'downloading', // see InstallStatus union reason: 'download-progress', // see InstallStateEventReason union bytesDownloaded: 5242880, totalBytesToDownload: 20971520, progress: 0.25, // computed: bytesDownloaded / totalBytesToDownload android: { playCore: { bytesDownloaded: 5242880, totalBytesToDownload: 20971520 }, }, } ``` -------------------------------- ### Opt-in to Asset Pack Deletion During Immediate Update Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md When starting an immediate update, you can opt-in to allow Play Core to delete asset packs under storage pressure by setting `android.allowAssetPackDeletion` to `true`. ```typescript // Opt-in to asset-pack deletion during immediate update await startImmediateUpdate({ android: { allowAssetPackDeletion: true } }) ``` -------------------------------- ### startImmediateUpdate Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Triggers the Google Play Core immediate update UI for a full-screen blocking update flow. This UI overlays the app and requires user interaction to proceed. The app may restart automatically after the user accepts the update. On iOS and non-Play Android installs, this function returns `supported: false` with a reason. ```APIDOC ## `startImmediateUpdate(options?)` ### Description Triggers the Google Play Core immediate update UI, which overlays the app with a full-screen dialog that blocks the user until they accept or decline the update. The app may restart automatically after the user accepts. On iOS and non-Play Android installs, returns `supported: false` with a typed reason instead of throwing. ### Parameters #### Options - **android** (object) - Optional. Configuration for Android. - **allowAssetPackDeletion** (boolean) - Optional. Only for Play Asset Delivery apps. Defaults to `false`. ### Request Example ```typescript import { startImmediateUpdate, canStartImmediateUpdate, getUpdateStatus, } from '@rnforge/react-native-in-app-updates'; async function triggerImmediateUpdate() { const status = await getUpdateStatus(); if (!canStartImmediateUpdate(status)) { console.log('Immediate update not available:', status.reason); return; } try { const result = await startImmediateUpdate({ android: { allowAssetPackDeletion: true }, }); console.log('Immediate update result:', result.reason); } catch (err) { console.error('Error starting immediate update:', err); } } ``` ### Response - **supported** (boolean) - Indicates if the update flow is supported on the current platform. - **reason** (string) - Provides context for the update status or result. Possible values include: - `'update-available'` - User accepted the update; app may restart. - `'update-not-allowed'` - Play policy denied the flow. - `'no-update-available'` - `'update-not-allowed'` - `'unsupported-install-source'` - `'unsupported-platform'` ### Error Handling - Throws an `InAppUpdatesError` on failure, which includes `code` and `message` properties. For Play Core task failures, `err.android?.playCore?.taskErrorCode` may be available. ``` -------------------------------- ### Run TypeScript type checking Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Executes `tsc --noEmit` to check TypeScript types across the entire source tree, including specifications and mocks. Ensure all dependencies are installed before running. ```bash bun run typecheck ``` -------------------------------- ### Set Up Local Includes Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Configures the include directories for local C++ source files. ```cmake # Set up local includes include_directories( "src/main/cpp" "../cpp" ) ``` -------------------------------- ### Build Verification Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Run the build script to verify the project's build process. ```bash # Build verification bun run build ``` -------------------------------- ### addInstallStateListener Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Listens to Android flexible update progress and install-state changes. On iOS, it fires a single event with `supported: false`, `reason: 'unsupported-platform'`, and then becomes a no-op subscription. ```APIDOC ## addInstallStateListener(callback) ### Description Listen to Android flexible update progress and install-state changes. ### Method `addInstallStateListener` ### Parameters #### Callback Function - `callback` (function) - A function that will be called with an event object containing update status details. - `event.platform` (string) - 'android' | 'ios' - `event.supported` (boolean) - `event.installStatus` (string) - 'downloading' | 'downloaded' | 'installing' | 'failed' | ... - `event.reason` (string) - 'download-progress' | 'install-state-changed' - `event.bytesDownloaded` (number) - `event.totalBytesToDownload` (number) - `event.progress` (number) - 0.0 - 1.0 - `event.android.playCore` (object) - Raw Play Core details. ### Request Example ```typescript import { addInstallStateListener } from '@rnforge/react-native-in-app-updates' const subscription = addInstallStateListener((event) => { console.log(event.platform) console.log(event.supported) console.log(event.installStatus) console.log(event.reason) console.log(event.bytesDownloaded) console.log(event.totalBytesToDownload) console.log(event.progress) console.log(event.android?.playCore) }) // Remove listener when done subscription.remove() ``` ### Response - Returns a subscription object with a `remove()` method to unsubscribe from the listener. ``` -------------------------------- ### Handle Update Flow with Helper Predicates Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Use helper predicates like `isUpdateAvailable`, `canStartImmediateUpdate`, `canStartFlexibleUpdate`, `canCompleteFlexibleUpdate`, and `canOpenStorePage` to conditionally execute update flows. Ensure the `addInstallStateListener` is used only if `supportsInstallStateListener` returns true. ```typescript import { getUpdateStatus, startImmediateUpdate, startFlexibleUpdate, completeFlexibleUpdate, openStorePage, isUpdateAvailable, canStartImmediateUpdate, canStartFlexibleUpdate, canCompleteFlexibleUpdate, canOpenStorePage, supportsInstallStateListener, addInstallStateListener, } from '@rnforge/react-native-in-app-updates' async function handleUpdateFlow() { const status = await getUpdateStatus({ ios: { appStoreId: '1234567890' } }) // isUpdateAvailable: status.updateAvailable === true if (!isUpdateAvailable(status)) { console.log('App is up to date') return } // canStartImmediateUpdate: supported + capabilities.immediate + updateAvailable + allowed.immediate if (canStartImmediateUpdate(status)) { await startImmediateUpdate() return } // canStartFlexibleUpdate: supported + capabilities.flexible + updateAvailable + allowed.flexible if (canStartFlexibleUpdate(status)) { await startFlexibleUpdate() return } // canCompleteFlexibleUpdate: supported + capabilities.flexible + installStatus === 'downloaded' if (canCompleteFlexibleUpdate(status)) { await completeFlexibleUpdate() return } // canOpenStorePage: capabilities.storePage === true (true even on iOS where in-app updates are unsupported) if (canOpenStorePage(status)) { await openStorePage({ ios: { appStoreId: '1234567890' } }) return } // supportsInstallStateListener: capabilities.installStateListener === true if (supportsInstallStateListener(status)) { const sub = addInstallStateListener((event) => { console.log(event.installStatus) if (event.installStatus === 'downloaded') sub.remove() }) } } ``` -------------------------------- ### Build package verification Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Runs `bun run typecheck && bob build` to perform type checking and build the package, generating output in `lib/commonjs/`, `lib/module/`, and `lib/typescript/`. This verifies the build process and output structure. ```bash bun run build ``` -------------------------------- ### Project and Build Configuration Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Sets the project name, minimum CMake version, and build verbosity. Also defines the C++ standard to be used. ```cmake project(InAppUpdates) cmake_minimum_required(VERSION 3.9.0) set (PACKAGE_NAME InAppUpdates) set (CMAKE_VERBOSE_MAKEFILE ON) set (CMAKE_CXX_STANDARD 20) ``` -------------------------------- ### Capability-First Branching with Helpers Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md This pattern demonstrates how to handle unsupported states gracefully without try-catch blocks, leveraging helper functions for clarity. It checks for supported status, update availability, and then proceeds with immediate or flexible updates. ```typescript // Capability-first branching with helpers const status = await getUpdateStatus() if (!status.supported) { // Expected unsupported state — no try/catch needed console.log('Unsupported:', status.reason) return } if (!isUpdateAvailable(status)) { console.log('No update available') return } if (canStartImmediateUpdate(status)) { await startImmediateUpdate() } else if (canStartFlexibleUpdate(status)) { await startFlexibleUpdate() } ``` -------------------------------- ### Run SwiftPM Tests Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Execute Swift Package Manager tests for pure iOS lookup core logic. This command is used to verify the functionality of the Swift helpers that bridge Core logic to the Nitro native module. ```bash swift test ``` -------------------------------- ### completeFlexibleUpdate Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Completes a downloaded flexible update. This should be called after `getUpdateStatus()` returns `reason: 'flexible-update-downloaded'` or after the install-state listener reports `installStatus: 'downloaded'`. If no downloaded flexible update is pending, it returns `reason: 'update-not-allowed'`. No JavaScript exception is thrown for expected unavailable states. ```APIDOC ## completeFlexibleUpdate() ### Description Completes a downloaded flexible update. Call this after `getUpdateStatus()` returns `reason: 'flexible-update-downloaded'` or after the install-state listener reports `installStatus: 'downloaded'`. ### Method `completeFlexibleUpdate` ### Response - `reason` (string) - Indicates the status of the update completion (e.g., 'flexible-update-downloaded', 'update-not-allowed'). - `supported` (boolean) - Indicates if the platform supports this feature. ### Request Example ```typescript import { completeFlexibleUpdate } from '@rnforge/react-native-in-app-updates' const result = await completeFlexibleUpdate() console.log(result.reason) // 'flexible-update-downloaded' | 'update-not-allowed' ``` ``` -------------------------------- ### Open App Store Page on iOS Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Directs the user to the App Store page for the application. Requires the `appStoreId` to be provided for iOS. ```typescript import { openStorePage } from '@rnforge/react-native-in-app-updates' // iOS — requires appStoreId await openStorePage({ ios: { appStoreId: '1234567890', }, }) ``` -------------------------------- ### openStorePage Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Opens the platform-specific store page for the application. On Android, it opens the Google Play Store. On iOS, it opens the App Store product page. ```APIDOC ## `openStorePage(options?)` — Open the platform store page for the current app Opens the Google Play Store page on Android (using a `market://` URI with a browser fallback), or the App Store product page on iOS. On iOS, `ios.appStoreId` is required and must be a digits-only string; omitting it throws `InAppUpdatesError('invalid-input')`. An optional two-letter `country` code localizes the App Store URL. ### Parameters #### Options Object (Optional) - **ios** (object) - Optional. iOS-specific options. - **appStoreId** (string) - Required on iOS. The digits-only App Store ID for the application. - **country** (string) - Optional. A two-letter ISO country code to localize the App Store URL. ### Returns - **Promise** - A promise that resolves when the store page is successfully opened, or rejects on error. ### Errors - **InAppUpdatesError** - Thrown if there is an issue opening the store page. - **code**: 'invalid-input' - Missing or non-numeric `appStoreId` on iOS. - **code**: 'native-error' - An unexpected failure occurred while launching the intent or URL. ``` -------------------------------- ### openStorePage Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Opens the platform store page for the current app. On Android, it opens the Play Store. On iOS, it opens the App Store if an `appStoreId` is provided. ```APIDOC ## openStorePage(options?) ### Description Open the platform store page for the current app. ### Method `openStorePage` ### Parameters #### Options - `options` (object) - Optional - `ios.appStoreId` (string) - Required for iOS. The App Store ID of the application. ### Request Example ```typescript import { openStorePage } from '@rnforge/react-native-in-app-updates' // iOS — requires appStoreId await openStorePage({ ios: { appStoreId: '1234567890', }, }) // Android — no options required await openStorePage() ``` ### Behavior - **Android**: Opens `market://details?id=` with a browser fallback to the Play Store web URL. - **iOS**: Opens `https://apps.apple.com/app/id`. Throws `InAppUpdatesError('invalid-input')` if `appStoreId` is missing. ``` -------------------------------- ### Open App Store Page on Android Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Opens the Google Play Store page for the application. No options are required for Android. ```typescript import { openStorePage } from '@rnforge/react-native-in-app-updates' // Android — no options required await openStorePage() ``` -------------------------------- ### Run Unit Tests with Jest Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Execute unit tests using Jest, which mocks the native layer for isolated testing. ```bash # Unit tests (Jest, mocked native layer) bunx jest ``` -------------------------------- ### getUpdateStatus Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Checks for update availability and platform capabilities. This is the recommended entry point for every update check. ```APIDOC ## getUpdateStatus(options?) ### Description Checks update availability and platform capabilities. This is the recommended entry point for every update check. ### Method `getUpdateStatus` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None #### Options - `ios.appStoreId` (string) - Required for iOS to check for updates. - `android.allowAssetPackDeletion` (boolean) - Optional. Opt-in to allow Play Core to delete asset packs under storage pressure. Only affects Play Asset Delivery apps. Defaults to `false`. ### Request Example ```typescript import { getUpdateStatus, } from '@rnforge/react-native-in-app-updates' const status = await getUpdateStatus({ ios: { appStoreId: '1234567890', }, }) // Example with Android option const statusWithAndroidOption = await getUpdateStatus({ android: { allowAssetPackDeletion: true }, }) ``` ### Response #### Success Response Returns a typed `UpdateStatus` object with the following key fields: - `supported` (boolean): Whether the current platform + install source supports in-app updates. - `updateAvailable` (boolean | null): `true` if a newer version is available, `false` if not, `null` if unsupported. - `reason` (string): Typed reason for the result (e.g. `'update-available'`, `'unsupported-install-source'`, `'no-update-available'`). - `capabilities` (object): What flows are available on this platform regardless of current state. - `allowed` (object): Whether immediate/flexible flows are currently permitted by Play policy. - `android.playCore` (object): Raw Play Core details: `updateAvailability`, `availableVersionCode`, `clientVersionStalenessDays`, etc. (Android only). #### Response Example ```json { "platform": "android", "supported": true, "updateAvailable": true, "reason": "update-available", "capabilities": { "immediate": true, "flexible": true, "storePage": true }, "allowed": { "immediate": true, "flexible": true }, "android": { "playCore": { "updateAvailability": 2, "availableVersionCode": 100, "clientVersionStalenessDays": 1 } } } ``` ``` -------------------------------- ### Complete Flexible Update Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Finalizes a downloaded flexible update. This should be called after `getUpdateStatus()` indicates a downloaded update or the install-state listener reports `installStatus: 'downloaded'`. Returns `reason: 'update-not-allowed'` if no update is pending. ```typescript import { completeFlexibleUpdate } from '@rnforge/react-native-in-app-updates' const result = await completeFlexibleUpdate() console.log(result.reason) // 'flexible-update-downloaded' | 'update-not-allowed' ``` -------------------------------- ### Run Jest unit tests Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/TESTING.md Executes the Jest test suite against `src/__tests__/**/*.test.ts`. This command mocks `react-native-nitro-modules` and covers various functionalities of the in-app updates API, including status retrieval, update initiation, listener management, and error handling. ```bash bunx jest ``` -------------------------------- ### Enable Raw Props Parsing Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Enables Raw Props parsing for Nitro Views by adding a compile-time option. ```cmake # Enable Raw Props parsing in react-native (for Nitro Views) add_compile_options(-DRN_SERIALIZABLE_STATE=1) ``` -------------------------------- ### Link Libraries Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Links the main project library with necessary system libraries, including the Android core and the log library. ```cmake # Link all libraries together target_link_libraries( ${PACKAGE_NAME} ${LOG_LIB} android # <-- Android core ) ``` -------------------------------- ### Handle Update Status with Helper Predicates Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Use these JavaScript helpers to safely branch logic based on the update status. Ensure the necessary functions are imported from the library. ```typescript import { getUpdateStatus, isUpdateAvailable, canStartImmediateUpdate, canStartFlexibleUpdate, canCompleteFlexibleUpdate, canOpenStorePage, supportsInstallStateListener, } from '@rnforge/react-native-in-app-updates' const status = await getUpdateStatus() if (canStartImmediateUpdate(status)) { await startImmediateUpdate() } else if (canStartFlexibleUpdate(status)) { await startFlexibleUpdate() } else if (canCompleteFlexibleUpdate(status)) { await completeFlexibleUpdate() } else if (canOpenStorePage(status)) { await openStorePage() } ``` -------------------------------- ### Find Log Library Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Locates the Android logging library. ```cmake find_library(LOG_LIB log) ``` -------------------------------- ### Check Update Availability with getUpdateStatus Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Use getUpdateStatus as the entry point to check for update availability and platform capabilities. Configure options for iOS and Android, and handle potential InAppUpdatesError exceptions. ```typescript import { getUpdateStatus, InAppUpdatesError, type GetUpdateStatusOptions, type UpdateStatus, } from '@rnforge/react-native-in-app-updates' async function checkForUpdate() { const options: GetUpdateStatusOptions = { ios: { appStoreId: '1234567890', // required for iOS version lookup country: 'us', // optional two-letter country code }, android: { allowAssetPackDeletion: false, // opt-in; only affects Play Asset Delivery apps }, } let status: UpdateStatus try { status = await getUpdateStatus(options) } catch (err) { if (err instanceof InAppUpdatesError) { // Only thrown for bridge errors or unexpected native failures console.error(`Bridge error [${err.code}]: ${err.message}`) } return } console.log(status.platform) // 'android' | 'ios' console.log(status.supported) // true if Play/App Store in-app updates are supported console.log(status.updateAvailable) // true | false | null (null if unsupported) console.log(status.reason) // 'update-available' | 'no-update-available' | 'unsupported-install-source' | ... console.log(status.capabilities) // { immediate: boolean, flexible: boolean, storePage: boolean, ... } console.log(status.allowed) // { immediate: boolean, flexible: boolean } console.log(status.currentVersion) // e.g. '1.2.3' console.log(status.latestStoreVersion) // e.g. '1.3.0' console.log(status.android?.playCore) // raw Play Core details (Android only) console.log(status.ios?.appStore) // App Store metadata (iOS only, if lookup succeeded) // Example reasons for UpdateStatus.reason: // Android Play: 'update-available', 'no-update-available', 'flexible-update-downloaded', // 'developer-triggered-update-in-progress', 'update-not-allowed', 'unknown' // Android other: 'unsupported-install-source', 'play-core-unavailable', 'apk-expansion-files-unsupported' // iOS: 'store-lookup-unavailable', 'missing-app-store-id', 'unsupported-platform' } ``` -------------------------------- ### Run TypeScript Type Checking Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Execute TypeScript type checking for the source files and specifications using the 'typecheck' script. ```bash # TypeScript type checking (src + specs) bun run typecheck ``` -------------------------------- ### Define C++ Library and Sources Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Defines the main shared C++ library for the project and lists its source files. ```cmake # Define C++ library and add all sources add_library(${PACKAGE_NAME} SHARED src/main/cpp/cpp-adapter.cpp ) ``` -------------------------------- ### Include Nitrogen Autolinking Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/android/CMakeLists.txt Includes the autolinking configuration for Nitrogen, which is necessary for certain features. ```cmake # Add Nitrogen specs :) include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/InAppUpdates+autolinking.cmake) ``` -------------------------------- ### Open Platform Store Page for Current App Source: https://context7.com/rnforge/react-native-in-app-updates/llms.txt Opens the app's store page on Google Play (Android) or the App Store (iOS). On iOS, `ios.appStoreId` is mandatory and must be a string of digits. An optional `ios.country` code can be provided for localization. ```typescript import { openStorePage, InAppUpdatesError, } from '@rnforge/react-native-in-app-updates' import { Platform } from 'react-native' async function redirectToStore() { try { if (Platform.OS === 'ios') { // appStoreId is required on iOS; country is optional (default: storefront of device) await openStorePage({ ios: { appStoreId: '1234567890', country: 'us', // optional two-letter ISO country code }, }) } else { // Android: no options required; opens market:// with Play Store web fallback await openStorePage() } console.log('Store page opened successfully') } catch (err) { if (err instanceof InAppUpdatesError) { // code === 'invalid-input' — missing or non-numeric appStoreId on iOS // code === 'native-error' — unexpected failure launching the intent/URL console.error(`openStorePage failed [${err.code}]: ${err.message}`) } } } ``` -------------------------------- ### Open App Store Page with App Store ID Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md When opening the App Store page on iOS, you must provide an explicit `appStoreId`. Failure to do so will result in an `invalid-input` error. ```typescript await openStorePage({ ios: { appStoreId: '1234567890' } }) ``` -------------------------------- ### Check Update Availability and Capabilities Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Use `getUpdateStatus` to check if an update is available and to understand platform capabilities. This function returns a typed `UpdateStatus` object. ```typescript import { getUpdateStatus } from '@rnforge/react-native-in-app-updates' const status = await getUpdateStatus({ ios: { appStoreId: '1234567890', }, }) console.log(status.platform) // 'android' | 'ios' console.log(status.supported) // boolean console.log(status.updateAvailable) // boolean | null console.log(status.reason) // e.g. 'update-available' console.log(status.capabilities) // { immediate, flexible, storePage, ... } console.log(status.allowed) // { immediate, flexible } console.log(status.android?.playCore) // raw Play Core details (Android only) ``` -------------------------------- ### Opt-in to Asset Pack Deletion for Flexible Update Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md Allows Play Core to delete asset packs during a flexible update if storage is low. This is an opt-in feature for Android. ```typescript // Opt-in to asset-pack deletion during flexible update await startFlexibleUpdate({ android: { allowAssetPackDeletion: true } }) ``` -------------------------------- ### Opt-in to Asset Pack Deletion on Status Check Source: https://github.com/rnforge/react-native-in-app-updates/blob/main/README.md When checking the update status, you can opt-in to allow Play Core to delete asset packs under storage pressure by setting `android.allowAssetPackDeletion` to `true`. ```typescript // Opt-in to asset-pack deletion during status check const status = await getUpdateStatus({ android: { allowAssetPackDeletion: true }, }) ```