The Expo SDK provides a comprehensive native module system that enables JavaScript code to communicate with platform-specific native implementations. This system handles module loading, type safety, web fallbacks, and cross-platform compatibility automatically.
Load native modules with different availability guarantees and error handling strategies.
/**
* Loads a native module and throws an error if the module is not available
* @param moduleName - Name of the native module to load
* @returns The native module instance with full type safety
* @throws Error if module is not available or fails to load
*/
function requireNativeModule<T>(moduleName: string): T;
/**
* Loads a native module and returns null if the module is not available
* @param moduleName - Name of the native module to load
* @returns The native module instance or null if not available
*/
function requireOptionalNativeModule<T>(moduleName: string): T | null;Usage Examples:
import { requireNativeModule, requireOptionalNativeModule } from 'expo';
// Required module - will throw if not available
const Constants = requireNativeModule('expo-constants');
console.log('App version:', Constants.appVersion);
// Optional module - returns null if not available
const Camera = requireOptionalNativeModule('expo-camera');
if (Camera) {
const permission = await Camera.requestCameraPermissionsAsync();
}
// With TypeScript interfaces
interface ExpoConstants {
appVersion: string;
deviceId: string;
platform: {
ios?: { platform: string; model: string; };
android?: { versionCode: number; };
};
}
const constants = requireNativeModule<ExpoConstants>('expo-constants');Access native view managers for creating custom native UI components.
/**
* Loads a native view manager for creating custom native views
* @param viewName - Name of the native view manager
* @returns The view manager instance for creating native views
*/
function requireNativeView(viewName: string): any;Usage Examples:
import { requireNativeView } from 'expo';
// Load a native view manager
const CustomMapView = requireNativeView('ExpoMapView');
// Use in a React Native component
function MapComponent() {
return (
<CustomMapView
style={{ flex: 1 }}
region={{ latitude: 37.78825, longitude: -122.4324 }}
/>
);
}Register web implementations for native modules to enable cross-platform functionality.
/**
* Registers a web implementation for a native module
* @param moduleName - Name of the native module
* @param moduleImplementation - Web-specific implementation object
*/
function registerWebModule(moduleName: string, moduleImplementation: any): void;Usage Examples:
import { registerWebModule } from 'expo';
// Web implementation of a native module
const webLocationModule = {
async getCurrentPositionAsync(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(position) => resolve({
coords: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy,
},
}),
reject,
options
);
});
},
};
// Register web implementation
registerWebModule('expo-location', webLocationModule);Programmatically reload the application during development or in response to updates.
/**
* Reloads the entire application
* @returns Promise that resolves when reload is initiated
*/
function reloadAppAsync(): Promise<void>;Usage Examples:
import { reloadAppAsync } from 'expo';
import { Button } from 'react-native';
function DeveloperMenu() {
const handleReload = async () => {
try {
await reloadAppAsync();
} catch (error) {
console.error('Failed to reload app:', error);
}
};
return <Button title="Reload App" onPress={handleReload} />;
}Base classes that provide the foundation for the native module system.
/**
* Base class for all shared objects between JavaScript and native code
*/
class SharedObject {
constructor();
release(): void;
}
/**
* Reference to a shared native object with automatic memory management
*/
class SharedRef<T> {
constructor(nativeObject: T);
get(): T | null;
release(): void;
}
/**
* Base class for all native modules with common functionality
*/
class NativeModule {
constructor();
addListener(eventName: string, listener: (...args: any[]) => void): Subscription;
removeListeners(count: number): void;
}Usage Examples:
import { NativeModule, SharedObject, SharedRef } from 'expo';
// Extending NativeModule for custom modules
class CustomNativeModule extends NativeModule {
async performOperation(): Promise<string> {
// Native module implementation
return 'Operation complete';
}
}
// Using SharedRef for memory management
function handleNativeResource(resourceRef: SharedRef<any>) {
const resource = resourceRef.get();
if (resource) {
// Use the resource
console.log('Resource available');
}
// Automatically cleaned up when SharedRef is garbage collected
}The Expo SDK includes these pre-configured native modules:
// Check module availability pattern
const CameraModule = requireOptionalNativeModule('expo-camera');
if (CameraModule) {
// Camera functionality available
const hasCameraPermission = await CameraModule.getCameraPermissionsAsync();
} else {
// Fallback for missing camera functionality
console.warn('Camera module not available on this platform');
}
// Required module with error handling
try {
const Constants = requireNativeModule('expo-constants');
console.log('Device ID:', Constants.deviceId);
} catch (error) {
console.error('Failed to load constants module:', error);
}
// Conditional loading based on platform
import { Platform } from 'react-native';
if (Platform.OS === 'ios') {
const iOSModule = requireOptionalNativeModule('expo-ios-specific-module');
// iOS-specific functionality
} else if (Platform.OS === 'android') {
const AndroidModule = requireOptionalNativeModule('expo-android-specific-module');
// Android-specific functionality
}The native module system provides several error handling patterns:
requireNativeModule throws if module cannot be loadedrequireOptionalNativeModule returns null for graceful fallbacks