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-app-lock

v1.0.1

Published

App lock for React Native — Android Accessibility Service + iOS Screen Time (FamilyControls). List installed apps, lock/unlock with toggles, works on both platforms.

Readme

react-native-app-lock

App lock for React Native — Android Accessibility Service + iOS Screen Time (FamilyControls). List installed apps, lock/unlock with toggles, works on both platforms.


Features

  • Android: lists all installed apps, locks/unlocks them via Accessibility Service, shows app icons
  • iOS: blocks selected apps via Apple's Screen Time / FamilyControls API
  • Drop-in <AppLockScreen> component with theming support
  • useAppLock() hook for custom UIs
  • Low-level AppLock bridge for direct native calls

Installation

npm install react-native-app-lock
# or
yarn add react-native-app-lock

Android setup

  1. Add the Accessibility Service declaration to AndroidManifest.xml:
<service
  android:name="com.yourapp.AppLockService"
  android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
  android:exported="true">
  <intent-filter>
    <action android:name="android.accessibilityservice.AccessibilityService" />
  </intent-filter>
  <meta-data
    android:name="android.accessibilityservice"
    android:resource="@xml/accessibility_service_config" />
</service>
  1. Rebuild the app:
npx react-native run-android

iOS setup

  1. Add the FamilyControls capability in Xcode → Signing & Capabilities.
  2. Rebuild:
npx react-native run-ios

Note: FamilyControls requires a physical device — it does not work on the simulator.


Usage

Option 1 — Drop-in screen component

The easiest way. Renders a full app-lock management screen ready to push onto your navigator.

import { AppLockScreen } from 'react-native-app-lock';

export function SettingsScreen({ navigation }) {
  return (
    <AppLockScreen
      onBack={() => navigation.goBack()}
      colors={{
        background: '#FFFFFF',
        text: '#111827',
        textSecondary: '#6B7280',
        border: '#E5E7EB',
        inputBackground: '#F9FAFB',
        inputBorder: '#D1D5DB',
        primary: '#6366F1',
      }}
      fonts={{
        regular: 'Inter-Regular',
        medium: 'Inter-Medium',
        bold: 'Inter-Bold',
      }}
    />
  );
}

AppLockScreen props

| Prop | Type | Required | Description | |------|------|----------|-------------| | onBack | () => void | Yes | Called when the user taps the back button | | colors | AppLockColors | Yes | Theme colors (see below) | | fonts | AppLockFonts | No | Font families — falls back to System |

AppLockColors

| Key | Description | |-----|-------------| | background | Screen/row background | | text | Primary text | | textSecondary | Secondary/placeholder text | | border | Dividers, toggle off-state | | inputBackground | Search bar background | | inputBorder | Search bar border | | primary | Accent color (toggle on-state, buttons) |

AppLockFonts

| Key | Description | |-----|-------------| | regular | Body text font family | | medium | Medium-weight font family | | bold | Bold font family |


Option 2 — useAppLock() hook

Use this when you want to build your own UI.

import { useAppLock } from 'react-native-app-lock';

export function MyAppLockUI() {
  const lock = useAppLock();

  if (lock.loading) return <ActivityIndicator />;

  return (
    <FlatList
      data={lock.apps}
      keyExtractor={(item) => item.packageName}
      renderItem={({ item }) => (
        <View>
          <Text>{item.appName}</Text>
          <Switch
            value={lock.lockedSet.has(item.packageName)}
            onValueChange={(val) =>
              val ? lock.lockApp(item.packageName) : lock.unlockApp(item.packageName)
            }
          />
        </View>
      )}
    />
  );
}

Hook return values

| Property | Platform | Type | Description | |----------|----------|------|-------------| | loading | Both | boolean | True while initial data loads | | lockApp(pkg) | Android | (pkg: string) => Promise<void> | Lock a single app by package name | | unlockApp(pkg) | Android | (pkg: string) => Promise<void> | Unlock a single app by package name | | unlockAll() | Both | () => Promise<void> | Remove all locks | | apps | Android | InstalledApp[] | List of all installed apps | | lockedSet | Android | Set<string> | Currently locked package names | | hasPermission | Android | boolean | Whether Accessibility Service is granted | | setLockedApps(pkgs) | Android | (pkgs: string[]) => Promise<void> | Replace the entire locked list at once | | savingPkg | Android | string \| null | Package currently being saved (for loading state) | | openAccessibilitySettings() | Android | () => Promise<void> | Open system Accessibility Settings | | openOverlaySettings() | Android | () => Promise<void> | Open overlay/draw-over-apps settings | | iosAuthStatus | iOS | AuthorizationStatus | 'approved' \| 'denied' \| 'notDetermined' | | requestIosAuthorization() | iOS | () => Promise<void> | Show the Screen Time permission dialog | | pickApps() | iOS | () => Promise<string \| null> | Open the native FamilyActivityPicker | | shieldFromEncoded(encoded) | iOS | (encoded: string) => Promise<void> | Shield apps from a picker selection string | | reApplyShields() | iOS | () => Promise<void> | Re-apply saved shields on app launch |

iOS flow example

import { useAppLock } from 'react-native-app-lock';
import { useEffect } from 'react';

function AppRoot() {
  const lock = useAppLock();

  // Re-apply shields every time the app opens
  useEffect(() => {
    lock.reApplyShields();
  }, []);

  const handleLock = async () => {
    const encoded = await lock.pickApps(); // shows native picker
    if (encoded) {
      await lock.shieldFromEncoded(encoded);
    }
  };

  if (lock.iosAuthStatus !== 'approved') {
    return <Button title="Grant Permission" onPress={lock.requestIosAuthorization} />;
  }

  return (
    <>
      <Button title="Select Apps to Lock" onPress={handleLock} />
      <Button title="Remove All Locks" onPress={lock.unlockAll} />
    </>
  );
}

Option 3 — Low-level AppLock bridge

For direct native calls without any React state.

import AppLock from 'react-native-app-lock';
// or named:
import { AppLock } from 'react-native-app-lock';

// Cross-platform helpers
await AppLock.hasRequiredPermissions(); // boolean
await AppLock.requestPermissions();     // boolean
await AppLock.lockApps(['com.instagram.android', 'com.tiktok.android']); // Android
await AppLock.unlockAll();

// Android-specific
await AppLock.android.getInstalledApps();
await AppLock.android.lockApp('com.instagram.android');
await AppLock.android.unlockApp('com.instagram.android');
await AppLock.android.getLockedApps();        // string[]
await AppLock.android.setLockedApps([...]);   // replace all
await AppLock.android.isAccessibilityEnabled();
await AppLock.android.openAccessibilitySettings();
await AppLock.android.canDrawOverlays();
await AppLock.android.openOverlaySettings();

// iOS-specific
await AppLock.ios.getAuthorizationStatus();   // AuthorizationStatus
await AppLock.ios.requestAuthorization();
await AppLock.ios.presentAppPicker();         // encoded string | null
await AppLock.ios.shieldAppsFromEncoded(encoded);
await AppLock.ios.shieldSelectedApps();       // re-apply last saved selection
await AppLock.ios.clearAllShields();
await AppLock.ios.getSavedSelection();        // encoded string | null

Types

interface InstalledApp {
  packageName: string;   // e.g. "com.instagram.android"
  appName: string;       // e.g. "Instagram"
  isSystemApp: boolean;
  icon: string;          // base64-encoded PNG
}

type AuthorizationStatus = 'approved' | 'denied' | 'notDetermined';

License

MIT