or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

app-utilities.mderror-handling.mdevent-communication.mdindex.mdnative-modules.mdnative-views.mdpermissions.mdplatform-utilities.mdshared-memory.mduuid-generation.md
tile.json

index.mddocs/

Expo Modules Core

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.

Package Information

  • Package Name: expo-modules-core
  • Package Type: npm
  • Language: TypeScript with native iOS and Android components
  • Installation: npm install expo-modules-core

Core Imports

import { 
  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");

Basic Usage

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();

Architecture

Expo Modules Core is built around several key architectural components:

  • Event System: Native-backed event emitters with full TypeScript support and automatic lifecycle management
  • Module Bridge: Direct access to native modules via JSI (JavaScript Interface) with fallback to bridge proxy
  • Shared Memory: Efficient memory sharing between JavaScript and native code via SharedObject and SharedRef
  • Platform Abstraction: Unified platform detection and environment utilities across iOS, Android, and web
  • Permission Management: React Hook-based permission system with standardized request/response patterns
  • Type Safety: Complete TypeScript integration with generic type preservation and native type definitions

Capabilities

Event Communication

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;
}

Event Communication

Native Module Integration

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 };
}

Native Module Integration

Shared Memory Management

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;
}

Shared Memory Management

Platform Utilities

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';

Platform Utilities

Permission Management

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>];

Permission Management

Native View Components

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 View Components

UUID Generation

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'
}

UUID Generation

Error Handling

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);
}

Error Handling

App Utilities

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>;

App Utilities

React Integration

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>;

Shared Memory Management

Deprecated APIs

Legacy Event Emitter

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;
}

Legacy Native Modules Proxy

Deprecated proxy object for accessing native modules.

/**
 * @deprecated Use requireNativeModule or requireOptionalNativeModule instead
 */
const NativeModulesProxy: Record<string, ProxyNativeModule>;

Global Types

// 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;
}