react-native-orientation-locker
Lock, detect, and react to screen orientation changes across iOS, Android, and Windows with one React Native API.
Repository Health
Technical Analysis
react-native-orientation-locker is a native module for React Native that lets apps lock the device to a specific screen orientation and listen for changes to both UI and physical device orientation. It ships platform-specific native implementations for iOS, Android, and Windows behind a single JavaScript API, so the same Orientation.lockToPortrait() call works across targets without conditional Platform.OS code.
Beyond the original imperative API, the package includes a declarative <OrientationLocker> component that merges orientation constraints from multiple mounted instances (useful for a video player that needs landscape while the rest of the app stays portrait), plus useOrientationChange and useDeviceOrientationChange hooks for function components. It has been maintained since 2017 with 55 contributors, and continues to receive updates for new iOS orientation APIs and Android 14 broadcast-receiver requirements.
What You Get
- Imperative API (
lockToPortrait,lockToLandscapeLeft,unlockAllOrientations, etc.) callable from any component - Declarative
<OrientationLocker>component that stacks orientation constraints from multiple mounted instances and resolves to the most recently mounted one useOrientationChange,useDeviceOrientationChange, anduseLockListenerhooks for function components- Native implementations for iOS (Objective-C/
RCTEventEmitter), Android (Java, withActivityLifecycleCallbacks), and Windows (C++/WinRT) - Separate UI-orientation and device-orientation events (
orientationDidChange,deviceOrientationDidChange,lockDidChange) so apps can distinguish what the screen shows from how the device is physically held
Common Use Cases
- Locking a video player or camera screen to landscape while the rest of the app stays in portrait
- Detecting device rotation to swap between portrait and landscape layouts instead of relying on width-based breakpoints alone
- Building a reader or game screen that needs a fixed orientation regardless of the device’s auto-rotate setting
- Supporting FACE-UP/FACE-DOWN detection on iOS and Windows for apps that react to a phone being laid flat
Under The Hood
Architecture
The package is a thin cross-platform native-module facade. index.js re-exports src/orientation (resolved per-platform via React Native’s .android.js/.ios.js/.windows.js file-extension convention), src/hooks, and src/OrientationLocker, so every platform target shares one static method surface and callers never branch on Platform.OS. On Android, OrientationModule (a ReactContextBaseJavaModule implementing OrientationListeners) combines a raw sensor-based OrientationEventListener with a BroadcastReceiver for onConfigurationChanged intents dispatched from the host MainActivity, and defers to OrientationActivityLifecycle (an Application.ActivityLifecycleCallbacks singleton) to reapply locks correctly across activity recreation. On iOS, Orientation.m implements RCTEventEmitter and switches between the pre- and post-iOS-13 UIWindowScene APIs for reading interface orientation. The declarative layer (OrientationLocker.js) keeps a module-level stack of orientation refs populated and cleared via useEffect on mount/unmount, recomputing the winning lock through a setImmediate-debounced update whenever the stack changes — a small hand-rolled priority-stack standing in for a context/portal-based resolution scheme.
Tech Stack
The JS layer has no runtime dependencies beyond its react/react-native peer dependencies (>=16.13.1/>=0.63.2), with react-native-windows marked optional. The Android target uses the RN bridge APIs (ReactContextBaseJavaModule, DeviceEventManagerModule) plus Android’s own OrientationEventListener and WindowManager; the iOS target is Objective-C built around RCTEventEmitter; the Windows target is C++/WinRT (ReactPackageProvider, an .idl interface) built through a Visual Studio solution and .vcxproj projects. Distribution relies on React Native’s autolinking (react-native.config.js) and a CocoaPods podspec rather than any custom build tooling.
Code Quality
There is no dedicated automated test suite for the library’s own logic — the only test files present are the React Native CLI’s default boilerplate smoke test (example/__tests__/App-test.js) and Xcode’s default generated test target inside the bundled example app, neither of which exercises orientation behavior. No CI workflow is present in the repository. Native error handling is defensive but minimal (guarded null checks like if (activity == null) return;, try/catch around receiver unregistration with logged warnings). TypeScript types are hand-maintained in index.d.ts rather than emitted from source, and naming is consistent across all three platform implementations (lockToX/unlockAllOrientations/addXListener).
API Design
The library’s core strength is developer experience: a single import and a handful of static methods cover locking, reading, and listening across three native platforms with no per-platform branching in application code. The stacked <OrientationLocker> component solves a genuinely awkward real-world problem — multiple screens wanting different orientation constraints at once — through simple mount-order resolution, and the hooks API extends the same listeners to function components with minimal boilerplate. It is not a novel technique, but it is a well-considered, low-friction surface for a narrow, recurring mobile problem.