npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-device-wake-state

v1.0.2

Published

React Native lock / screen-off detection plus keep-awake. Reports PowerManager + Keyguard on Android and iOS protected-data / lock notifications. Also blocks idle sleep (FLAG_KEEP_SCREEN_ON / idleTimerDisabled).

Readme

react-native-device-wake-state

React Native lock / screen-off detection. AppState misses many OEM lock-button cases; this plugin reports native wake and keyguard flags.

npm: react-native-device-wake-state
GitHub: Management-AND-Computer-Consultants/mcc-react-native-device-wake-state
Native module: NativeModules.DeviceWakeState

| Platform | Mechanism | Host wiring | |----------|-----------|-------------| | Android | ACTION_SCREEN_OFF / SCREEN_ON / USER_PRESENT plus PowerManager.isInteractive and KeyguardManager | Autolink only | | iOS | Protected-data unavailable/available plus app + UIScene background / foreground / active | pod install only |

No extra Android permissions. Android and iOS both autolink — no MainActivity hooks, no Xcode Compile Sources, no Info.plist keys.


Table of contents

  1. Install
  2. Architecture
  3. Package layout
  4. JS usage
  5. API
  6. Android
  7. iOS
  8. Event payload
  9. Session guard
  10. Native method map
  11. Notes

1. Install

cd your-react-native-app
npm install react-native-device-wake-state

package.json:

"react-native-device-wake-state": "^1.0.2"

GitHub install (optional):

npm install github:Management-AND-Computer-Consultants/mcc-react-native-device-wake-state

Then rebuild native on both platforms (Metro reload is not enough):

# Android
npx react-native run-android

# iOS (pod install autolinks DeviceWakeState.h / DeviceWakeState.m)
cd ios && pod install && cd .. && npx react-native run-ios

Autolink registers:

  • Android: DeviceWakeStatePackage
  • iOS: CocoaPods target react-native-device-wake-state

Do not also register an in-app DeviceWakeStatePackage in MainApplication, and do not keep DeviceWakeState.m in the app Xcode Compile Sources. Two modules with the same name will clash.

Local checkout for edits: D:\CoDe\RNPlugin\react-native-device-wake-state. Push to GitHub, then reinstall the GitHub spec in the app.


2. Architecture

┌─────────────────────────────────────────────────────────────────┐
│ Host JS                                                          │
│  getDeviceWakeState()                                           │
│  subscribeDeviceWakeState(event => …)                          │
│  subscribeSessionGuard({ onInterrupted, onResumed… })        │
└───────────────────────────────┬─────────────────────────────────┘
                                │ NativeModules.DeviceWakeState
                                │ event: DeviceWakeStateChange
┌───────────────────────────────▼─────────────────────────────────┐
│ Android — DeviceWakeStatePackage / Module (autolinked)         │
│  BroadcastReceiver on reactApplicationContext                      │
│    SCREEN_OFF → screenOff                                         │
│    SCREEN_ON  → screenOn                                          │
│    USER_PRESENT → userPresent                                     │
│  getState: isInteractive, isKeyguardLocked, isDeviceLocked        │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ iOS — DeviceWakeState.h / DeviceWakeState.m (autolinked pod)    │
│  ProtectedData unavailable → screenOff                          │
│  ProtectedData available → userPresent                          │
│  DidEnterBackground / UISceneDidEnterBackground → screenOff     │
│  WillEnterForeground / DidBecomeActive / UISceneDidActivate     │
│    → screenOn                                                    │
└─────────────────────────────────────────────────────────────────┘

3. Package layout

react-native-device-wake-state/
├── src/index.ts
├── android/
│   ├── build.gradle
│   └── src/main/java/com/reactnativedevicewakestate/
│       ├── DeviceWakeStatePackage.kt
│       └── DeviceWakeStateModule.kt
├── ios/
│   ├── DeviceWakeState.h
│   └── DeviceWakeState.m
├── react-native.config.js
├── react-native-device-wake-state.podspec
└── README.md

4. JS usage

Same API on Android and iOS.

Keep screen on (idle sleep)

Replaces @sayem314/react-native-keep-awake. Does not intercept the lock button.

import {
  activateKeepAwake,
  deactivateKeepAwake,
} from 'react-native-device-wake-state';

useEffect(() => {
  activateKeepAwake();
  return () => deactivateKeepAwake();
}, []);

One-shot poll

import { getDeviceWakeState, isLockedOrScreenOff } from 'react-native-device-wake-state';

const state = await getDeviceWakeState();
if (isLockedOrScreenOff(state)) {
  // screen off or keyguard showing
}

Native events

import { subscribeDeviceWakeState } from 'react-native-device-wake-state';

useEffect(() => {
  return subscribeDeviceWakeState(event => {
    console.log(event.type, event.isKeyguardLocked);
  });
}, []);

Subscribe only while you need it (for example while recording). Always unsubscribe so Android does not leak the receiver.

Session guard (lock then unlock)

import {
  subscribeSessionGuard,
} from 'react-native-device-wake-state';
import {
  isPictureInPictureActive,
  isPictureInPictureEnabled,
} from 'react-native-picture-in-picture';

useEffect(() => {
  if (!isRecording) {
    return;
  }

  return subscribeSessionGuard({
    onForeground: () => {
      activateKeepAwake();
    },
    onInterrupted: () => {
      wentToBackgroundRef.current = true;
    },
    onResumedAfterInterrupt: () => {
      // show "keep the screen unlocked" alert
    },
    isPipEnabled: isPictureInPictureEnabled,
    isPipActive: isPictureInPictureActive,
  });
}, [isRecording]);

isPipEnabled / isPipActive are optional. Pass them so Home → Picture-in-Picture is not treated as a lock.

Alias: subscribeRecordingSessionGuard is the same function.


5. API

| Export | Description | |--------|-------------| | getDeviceWakeState() | Promise<IDeviceWakeState \| null> | | startListening() / stopListening() | Native receiver / observers | | activateKeepAwake() / deactivateKeepAwake() | Block idle sleep (FLAG_KEEP_SCREEN_ON / idleTimerDisabled). JS re-applies every 3 s. | | subscribeDeviceWakeState(listener) | Event subscription; returns unsubscribe | | isLockedOrScreenOff(state) | !interactive \|\| keyguard \|\| deviceLocked | | subscribeSessionGuard(options) | AppState + native events + 2 s poll |

Default export: { getState, startListening, stopListening, subscribe, subscribeSessionGuard, isLockedOrScreenOff }.


6. Android

Autolink is enough. There is no MainActivity host class (unlike Picture-in-Picture).

| Piece | What happens | |--------|----------------| | DeviceWakeStatePackage | Registered from react-native.config.js | | DeviceWakeStateModule | NativeModules.DeviceWakeState | | Receiver | reactApplicationContext (survives activity pause / lock) | | API 33+ | Context.RECEIVER_NOT_EXPORTED | | Permissions | None |

getState() reads:

  • PowerManager.isInteractive
  • KeyguardManager.isKeyguardLocked
  • KeyguardManager.isDeviceLocked (API 22+)

Events:

| Broadcast | type | |-----------|--------| | ACTION_SCREEN_OFF | screenOff | | ACTION_SCREEN_ON | screenOn | | ACTION_USER_PRESENT | userPresent |

If you previously had in-app DeviceWakeStatePackage(), remove that add(...) from MainApplication after switching to this plugin.


7. iOS

Autolink is enough. No Xcode Compile Sources step and no Info.plist keys.

  1. cd ios && pod install after npm install.
  2. CocoaPods compiles ios/DeviceWakeState.h + ios/DeviceWakeState.m.
  3. New Architecture (RCT_NEW_ARCH_ENABLED=1) is supported via the React interop layer (RCTEventEmitter).

getState() reads:

  • UIApplication.isProtectedDataAvailable → inverted as isKeyguardLocked / isDeviceLocked
  • applicationState != background && !locked → isInteractive

Observers (registered on startListening / NativeEventEmitter):

| Notification | type | |-------------|--------| | UIApplicationProtectedDataWillBecomeUnavailable | screenOff | | UIApplicationProtectedDataDidBecomeAvailable | userPresent | | UIApplicationDidEnterBackground / UISceneDidEnterBackground | screenOff | | UIApplicationWillEnterForeground / UISceneWillEnterForeground | screenOn | | UIApplicationDidBecomeActive / UISceneDidActivate | screenOn |

If you previously compiled Universal_App/DeviceWakeState.m inside the app target, remove it from the Xcode project after switching so the pod is the only DeviceWakeState module.

Devices without a passcode may keep isProtectedDataAvailable == YES while locked. The session guard still sees Home / lock via background + AppState.


8. Event payload

interface IDeviceWakeStateEvent {
  type: 'screenOff' | 'screenOn' | 'userPresent';
  isInteractive: boolean;
  isKeyguardLocked: boolean;
  isDeviceLocked: boolean;
}

| type | Android | iOS | |--------|--------|-----| | screenOff | ACTION_SCREEN_OFF | protected data unavailable or enter background | | screenOn | ACTION_SCREEN_ON | will enter foreground / did become active | | userPresent | ACTION_USER_PRESENT | protected data available |

JS treats !isInteractive || isKeyguardLocked || isDeviceLocked as locked, even if type is screenOn (PIN can still be showing).

null from getDeviceWakeState is treated as not locked (fail open).


9. Session guard

subscribeSessionGuard combines:

  1. AppState — background marks interrupt unless PiP is enabled; inactive is ignored; active runs onForeground
  2. Native DeviceWakeStateChange
  3. Poll every 2 s (override with pollMs) for OEM skins that drop a broadcast

onResumedAfterInterrupt runs only when interrupted is true, AppState is active, and getState() is not locked.

Always stopListening in the returned unsubscribe.


10. Native method map

| JS | Android | iOS | |----|---------|-----| | getState() | PowerManager + KeyguardManager | protected data + applicationState | | activateKeepAwake() | FLAG_KEEP_SCREEN_ON | idleTimerDisabled = YES | | deactivateKeepAwake() | clear FLAG_KEEP_SCREEN_ON | idleTimerDisabled = NO | | startListening() | register BroadcastReceiver (RECEIVER_NOT_EXPORTED on API 33+) | registerObservers (app + UIScene) | | stopListening() | unregister | removeObserver | | addListener / removeListeners | RN stubs | RCTEventEmitter startObserving / stopObserving |

Event name: DeviceWakeStateChange.

On iOS, isKeyguardLocked and isDeviceLocked are the same boolean.


11. Notes

  • Rebuild native after installing or changing this package.
  • Do not also keep an in-app DeviceWakeStatePackage / DeviceWakeState.m in the host app.
  • Listen only while a session needs it. Do not call startListening from App.tsx or Splash.
  • Always unsubscribe; a leaked Android receiver keeps firing after the screen unmounts.
  • PiP is not a lock. Pass isPipEnabled / isPipActive into subscribeSessionGuard.
  • inactive is not an interrupt (permission sheets, PiP transitions).
  • Android 13+ must use RECEIVER_NOT_EXPORTED (the plugin already does).
  • Register on reactApplicationContext, not the activity — activity-scoped receivers die when the activity pauses (exactly when lock happens).

Checklist

  1. package.json uses react-native-device-wake-state from npm.
  2. Native rebuild: Android run-android, iOS pod install then run-ios.
  3. Subscribe in a useEffect tied to the session (isRecording), not app mount.
  4. If you also use Picture-in-Picture, pass the PiP flags into subscribeSessionGuard.
  5. Remove in-app DeviceWakeStateModule.kt / DeviceWakeStatePackage.kt / DeviceWakeState.m after switching.