The core infrastructure for Expo Modules architecture enabling seamless integration between React Native applications and native platform code.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Expo Modules Core provides the foundational infrastructure for the Expo Modules architecture, enabling seamless integration between React Native applications and native platform code. It offers a comprehensive set of APIs including native module proxies for cross-platform communication, event emitters for real-time event handling, shared objects and references for efficient memory management, and permission handling utilities for secure access control.
npm install expo-modules-coreimport {
EventEmitter,
NativeModule,
SharedObject,
SharedRef,
Platform,
requireNativeModule,
requireOptionalNativeModule,
requireNativeViewManager,
registerWebModule,
uuid,
reloadAppAsync,
createSnapshotFriendlyRef,
useReleasingSharedObject,
createPermissionHook,
CodedError,
UnavailabilityError,
PermissionStatus,
type EventsMap,
type PermissionResponse,
type EventSubscription
} from "expo-modules-core";For CommonJS:
const {
EventEmitter,
NativeModule,
requireNativeModule,
requireOptionalNativeModule,
Platform,
uuid,
reloadAppAsync,
CodedError,
UnavailabilityError,
PermissionStatus
} = require("expo-modules-core");import {
EventEmitter,
requireNativeModule,
Platform,
type EventSubscription
} from "expo-modules-core";
// Create an event emitter for custom events
const emitter = new EventEmitter<{
dataReceived: (data: string) => void;
error: (error: Error) => void;
}>();
// Add event listeners
const subscription: EventSubscription = emitter.addListener("dataReceived", (data) => {
console.log("Received:", data);
});
// Emit events
emitter.emit("dataReceived", "Hello from native!");
// Load a native module
try {
const nativeModule = requireNativeModule("MyCustomModule");
const result = await nativeModule.performOperation();
} catch (error) {
console.log("Native module not available");
}
// Platform-specific code
const platformSpecificValue = Platform.select({
ios: "iOS implementation",
android: "Android implementation",
web: "Web implementation",
default: "Fallback implementation"
});
// Clean up
subscription.remove();Expo Modules Core is built around several key architectural components:
Native-backed event system for real-time communication between JavaScript and native code, with full TypeScript support and automatic lifecycle management.
class EventEmitter<TEventsMap extends EventsMap = Record<never, never>> {
addListener<EventName extends keyof TEventsMap>(
eventName: EventName,
listener: TEventsMap[EventName]
): EventSubscription;
emit<EventName extends keyof TEventsMap>(
eventName: EventName,
...args: Parameters<TEventsMap[EventName]>
): void;
}
interface EventSubscription {
remove(): void;
}Direct integration with native platform modules through JSI with automatic fallback to bridge proxy for backwards compatibility.
function requireNativeModule<ModuleType = any>(moduleName: string): ModuleType;
function requireOptionalNativeModule<ModuleType = any>(
moduleName: string
): ModuleType | null;
class NativeModule<TEventsMap extends EventsMap = Record<never, never>>
extends EventEmitter<TEventsMap> {
ViewPrototypes?: { [viewName: string]: object };
}Efficient memory sharing between JavaScript and native code with manual memory management capabilities for performance-critical scenarios.
class SharedObject<TEventsMap extends EventsMap = Record<never, never>>
extends EventEmitter<TEventsMap> {
release(): void;
}
class SharedRef<
TNativeRefType extends string = 'unknown',
TEventsMap extends EventsMap = Record<never, never>
> extends SharedObject<TEventsMap> {
nativeRefType: string;
}Cross-platform utilities for environment detection, platform-specific code execution, and browser capability checking.
interface Platform {
OS: string;
select: <T>(specifics: { [platform in PlatformSelectOSType]?: T }) => T;
isDOMAvailable: boolean;
canUseEventListeners: boolean;
canUseViewport: boolean;
isAsyncDebugging: boolean;
}
type PlatformSelectOSType = 'ios' | 'android' | 'web' | 'native' | 'electron' | 'default';React Hook-based permission system with standardized request/response patterns and automatic lifecycle management.
enum PermissionStatus {
GRANTED = 'granted',
UNDETERMINED = 'undetermined',
DENIED = 'denied'
}
interface PermissionResponse {
status: PermissionStatus;
expires: PermissionExpiration;
granted: boolean;
canAskAgain: boolean;
}
function createPermissionHook<Permission extends PermissionResponse, Options extends object>(
methods: PermissionHookMethods<Permission, Options>
): (options?: PermissionHookOptions<Options>) =>
[Permission | null, () => Promise<Permission>, () => Promise<Permission>];Integration system for React Native components backed by native view managers, with automatic prototype binding and lifecycle management.
function requireNativeViewManager<P>(
moduleName: string,
viewName?: string
): ComponentType<P>;Native-backed UUID generation with support for both random (v4) and deterministic (v5) UUID creation.
interface UUID {
v4(): string;
v5(name: string, namespace: string | number[]): string;
namespace: typeof Uuidv5Namespace;
}
enum Uuidv5Namespace {
dns = '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
url = '6ba7b811-9dad-11d1-80b4-00c04fd430c8',
oid = '6ba7b812-9dad-11d1-80b4-00c04fd430c8',
x500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'
}Standardized error classes with error codes for consistent error handling across Expo modules.
class CodedError extends Error {
code: string;
info?: any;
constructor(code: string, message: string);
}
class UnavailabilityError extends CodedError {
constructor(moduleName: string, propertyName: string);
}Additional utility functions for application lifecycle management, app reloading, and React development helpers.
function reloadAppAsync(reason?: string): Promise<void>;
function createSnapshotFriendlyRef<T>(): RefObject<T | null>;React hooks and utilities for seamless integration with React components and automatic resource management.
function useReleasingSharedObject<TSharedObject extends SharedObject>(
factory: () => TSharedObject,
dependencies: DependencyList
): TSharedObject;
function createSnapshotFriendlyRef<T>(): RefObject<T | null>;Deprecated event emitter class for backward compatibility with older modules.
/**
* @deprecated Use EventEmitter instead
*/
class LegacyEventEmitter {
constructor(nativeModule: any);
addListener<T>(eventName: string, listener: (event: T) => void): EventSubscription;
removeAllListeners(eventName: string): void;
removeSubscription(subscription: EventSubscription): void;
emit(eventName: string, ...params: any[]): void;
}Deprecated proxy object for accessing native modules.
/**
* @deprecated Use requireNativeModule or requireOptionalNativeModule instead
*/
const NativeModulesProxy: Record<string, ProxyNativeModule>;// Core event system types
type EventsMap = Record<string, (...args: any[]) => void>;
type PermissionExpiration = 'never' | number;
// Typed array support
type TypedArray = IntBasedTypedArray | UintBasedTypedArray | FloatBasedTypedArray;
type IntBasedTypedArray = Int8Array | Int16Array | Int32Array;
type UintBasedTypedArray = Uint8Array | Uint8ClampedArray | Uint16Array | Uint32Array;
type FloatBasedTypedArray = Float32Array | Float64Array;
// Platform types
type PlatformSelectOSType = 'ios' | 'android' | 'web' | 'native' | 'electron' | 'default';
// Legacy module proxy interface
interface ProxyNativeModule {
addListener?(eventName: string): void;
removeListeners?(count: number): void;
[key: string]: any;
}
// React integration types
type ComponentType<P = {}> = React.ComponentType<P>;
interface RefObject<T> {
readonly current: T | null;
}
type DependencyList = ReadonlyArray<any>;
// Permission system types
interface PermissionHookMethods<Permission extends PermissionResponse, Options = never> {
requestMethod: (options?: Options) => Promise<Permission>;
getMethod: (options?: Options) => Promise<Permission>;
}
interface PermissionHookOptions<Options extends object> extends Options {
get?: boolean;
request?: boolean;
}
// Global Expo namespace types
interface ViewConfig {
validAttributes: Record<string, any>;
directEventTypes: Record<string, { registrationName: string }>;
}
interface ExpoGlobal {
modules: Record<string, any>;
expoModulesCoreVersion?: { major: number; minor: number; patch: number };
cacheDir?: string;
documentsDir?: string;
uuidv4(): string;
uuidv5(name: string, namespace: string): string;
getViewConfig(moduleName: string, viewName?: string): ViewConfig | null;
reloadAppAsync(reason: string): Promise<void>;
}
declare global {
const expo: ExpoGlobal;
}