UNPKG

expo-constants

Version:

Provides system information that remains constant throughout the lifetime of your app.

258 lines (233 loc) 7.78 kB
import type { ExpoConfig } from 'expo/config'; // @ts-ignore -- optional interface, will gracefully degrade to `any` if not installed import type { EmbeddedManifest, EASConfig, ExpoGoConfig, ExpoUpdatesManifest, // @ts-ignore -- optional interface, will gracefully degrade to `any` if not installed } from 'expo-manifests'; import { CodedError, requireOptionalNativeModule } from 'expo-modules-core'; // @ts-ignore -- optional interface, will gracefully degrade to `any` if not installed import type { Manifest as UpdatesManifest, ExpoUpdatesModule } from 'expo-updates'; import { Platform, NativeModules } from 'react-native'; import { AndroidManifest, AppOwnership, Constants, ExecutionEnvironment, IOSManifest, NativeConstants, PlatformManifest, UserInterfaceIdiom, WebManifest, } from './Constants.types'; import ExponentConstants from './ExponentConstants'; type DevLauncherManifest = ExpoUpdatesManifest; export { AndroidManifest, AppOwnership, Constants, ExecutionEnvironment, IOSManifest, NativeConstants, PlatformManifest, UserInterfaceIdiom, WebManifest, }; if (!ExponentConstants) { console.warn( "No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?" ); } const ExpoUpdates = requireOptionalNativeModule<ExpoUpdatesModule>('ExpoUpdates'); let rawUpdatesManifest: UpdatesManifest | null = null; // If expo-updates defines a non-empty manifest, prefer that one if (ExpoUpdates) { let updatesManifest: object | undefined; if (ExpoUpdates.manifest) { updatesManifest = ExpoUpdates.manifest; } else if (ExpoUpdates.manifestString) { updatesManifest = JSON.parse(ExpoUpdates.manifestString); } if (updatesManifest && Object.keys(updatesManifest).length > 0) { rawUpdatesManifest = updatesManifest as any; } } // If dev-launcher defines a non-empty manifest, prefer that one let rawDevLauncherManifest: DevLauncherManifest | null = null; if (NativeModules.EXDevLauncher) { let devLauncherManifest; if (NativeModules.EXDevLauncher.manifestString) { devLauncherManifest = JSON.parse(NativeModules.EXDevLauncher.manifestString); } if (devLauncherManifest && Object.keys(devLauncherManifest).length > 0) { rawDevLauncherManifest = devLauncherManifest as any; } } // Fall back to ExponentConstants.manifest if we don't have one from Updates let rawAppConfig: ExpoConfig | null = null; if (ExponentConstants && ExponentConstants.manifest) { const appConfig: object | string = ExponentConstants.manifest; // On Android we pass the manifest in JSON form so this step is necessary if (typeof appConfig === 'string') { rawAppConfig = JSON.parse(appConfig); } else { rawAppConfig = appConfig as any; } } type RawManifest = UpdatesManifest | DevLauncherManifest | ExpoConfig; let rawManifest: RawManifest | null = rawUpdatesManifest ?? rawDevLauncherManifest ?? rawAppConfig; const { name, appOwnership, ...nativeConstants } = (ExponentConstants || {}) as any; const constants: Constants = { ...nativeConstants, // Ensure this is null in bare workflow appOwnership: appOwnership ?? null, }; Object.defineProperties(constants, { /** * Use `manifest` property by default. * This property is only used for internal purposes. * It behaves similarly to the original one, but suppresses warning upon no manifest available. * `expo-asset` uses it to prevent users from seeing mentioned warning. */ __unsafeNoWarnManifest: { get(): EmbeddedManifest | null { const maybeManifest = getManifest(true); if (!maybeManifest || !isEmbeddedManifest(maybeManifest)) { return null; } return maybeManifest; }, enumerable: false, }, __unsafeNoWarnManifest2: { get(): ExpoUpdatesManifest | null { const maybeManifest = getManifest(true); if (!maybeManifest || !isExpoUpdatesManifest(maybeManifest)) { return null; } return maybeManifest; }, enumerable: false, }, manifest: { get(): EmbeddedManifest | null { const maybeManifest = getManifest(); if (!maybeManifest || !isEmbeddedManifest(maybeManifest)) { return null; } return maybeManifest; }, enumerable: true, }, manifest2: { get(): ExpoUpdatesManifest | null { const maybeManifest = getManifest(); if (!maybeManifest || !isExpoUpdatesManifest(maybeManifest)) { return null; } return maybeManifest; }, enumerable: true, }, expoConfig: { get(): | (ExpoConfig & { /** * Only present during development using @expo/cli. */ hostUri?: string; }) | null { const maybeManifest = getManifest(true); if (!maybeManifest) { return null; } // if running an embedded update, maybeManifest is a EmbeddedManifest which doesn't have // the expo config. Instead, the embedded expo-constants app.config should be used. if (ExpoUpdates && ExpoUpdates.isEmbeddedLaunch) { return rawAppConfig; } if (isExpoUpdatesManifest(maybeManifest)) { return maybeManifest.extra?.expoClient ?? null; } else if (isEmbeddedManifest(maybeManifest)) { return maybeManifest as any; } return null; }, enumerable: true, }, expoGoConfig: { get(): ExpoGoConfig | null { const maybeManifest = getManifest(true); if (!maybeManifest) { return null; } if (isExpoUpdatesManifest(maybeManifest)) { return maybeManifest.extra?.expoGo ?? null; } else if (isEmbeddedManifest(maybeManifest)) { return maybeManifest as any; } return null; }, enumerable: true, }, easConfig: { get(): EASConfig | null { const maybeManifest = getManifest(true); if (!maybeManifest) { return null; } if (isExpoUpdatesManifest(maybeManifest)) { return maybeManifest.extra?.eas ?? null; } else if (isEmbeddedManifest(maybeManifest)) { return maybeManifest as any; } return null; }, enumerable: true, }, __rawManifest_TEST: { get(): RawManifest | null { return rawManifest; }, set(value: RawManifest | null) { rawManifest = value; }, enumerable: false, }, }); function isEmbeddedManifest(manifest: RawManifest): manifest is EmbeddedManifest { return !isExpoUpdatesManifest(manifest); } function isExpoUpdatesManifest(manifest: RawManifest): manifest is ExpoUpdatesManifest { return 'metadata' in manifest; } function getManifest(suppressWarning = false): RawManifest | null { if (!rawManifest) { const invalidManifestType = rawManifest === null ? 'null' : 'undefined'; if ( nativeConstants.executionEnvironment === ExecutionEnvironment.Bare && Platform.OS !== 'web' ) { if (!suppressWarning) { console.warn( `Constants.manifest is ${invalidManifestType} because the embedded app.config could not be read. Ensure that you have installed the expo-constants build scripts if you need to read from Constants.manifest.` ); } } else if ( nativeConstants.executionEnvironment === ExecutionEnvironment.StoreClient || nativeConstants.executionEnvironment === ExecutionEnvironment.Standalone ) { // If we somehow get here, this is a truly exceptional state to be in. // Constants.manifest should *always* be defined in those contexts. throw new CodedError( 'ERR_CONSTANTS_MANIFEST_UNAVAILABLE', `Constants.manifest is ${invalidManifestType}, must be an object.` ); } } return rawManifest; } export default constants as Constants;