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

expo-mdm

v0.1.11

Published

An expo module to access Managed Device Management (MDM) features on iOS and Android.

Downloads

164

Readme

expo-mdm

A React Native library for integrating Mobile Device Management (MDM) capabilities into Expo applications.

Overview

This project has been created with the intention of integrating MDM functionality for React Native applications. While there is already a project called react-native-mdm that provides similar functionality, this library aims to provide better Expo compatibility and modern implementation.

Platform Support

  • Android - Fully implemented
  • iOS - Fully implemented

Both platforms support MDM configuration reading and app locking features.

Key Platform Differences

| Feature | Android | iOS | |---------|---------|-----| | Build-time Config | ✅ Required (app_restrictions.xml) | ❌ Not needed | | Config Source | App defines schema, MDM sets values | MDM defines schema and sets values | | Config Location | RestrictionsManager API | UserDefaults (com.apple.configuration.managed) | | Info.plist | Not used | Not used | | Plugin Setup | Required | Optional (no-op) |

Getting Started

Installation

npm install expo-mdm
# or
yarn add expo-mdm

Configuration

Android Configuration (Required)

Android requires build-time configuration to generate the app_restrictions.xml file that MDM providers use.

Add the expo-mdm plugin to your app.json or app.config.js:

{
  "expo": {
    "plugins": [
      [
        "expo-mdm",
        {
          "android": {
            "QueryPackages": [
              "com.azure.authenticator",
              "UserDetailsClient.Droid",
              "com.microsoft.windowsintune.companyportal"
            ],
            "AppRestrictionsMap": {
              "apiUrl": {
                "title": "API URL",
                "description": "The URL of the API server.",
                "type": "string",
                "defaultValue": "https://api.example.com"
              },
              "enableAnalytics": {
                "title": "Enable Analytics",
                "description": "Whether to enable analytics.",
                "type": "bool",
                "defaultValue": false
              },
              "maxRetries": {
                "title": "Max Retries",
                "description": "Maximum number of retry attempts",
                "type": "integer",
                "defaultValue": 3
              }
            }
          }
        }
      ]
    ]
  }
}

iOS Configuration (None Required)

iOS does NOT require any build-time configuration.

Unlike Android, iOS MDM works entirely at runtime:

  • 🚫 No Info.plist entries needed
  • 🚫 No build-time configuration files
  • ✅ MDM providers (Intune, Jamf, Workspace ONE, etc.) define the configuration schema in their admin consoles
  • ✅ Configuration is pushed directly to the device and stored in UserDefaults at com.apple.configuration.managed
  • ✅ Your app simply reads the configuration at runtime using getConfiguration()

Example: If you want to configure apiUrl and enableAnalytics for iOS:

  1. Log into your MDM provider's admin console (e.g., Microsoft Intune)
  2. Create an "App Configuration Policy" for your iOS app
  3. Add key-value pairs:
    • Key: apiUrl, Value: https://api.example.com
    • Key: enableAnalytics, Value: true
  4. Deploy the policy to your test devices
  5. Your app will automatically read these values via getConfiguration()

Android Plugin Configuration Options

QueryPackages (Android Only)

The QueryPackages array specifies which package names your app can query for. This is essential for MDM functionality as it allows your app to detect and interact with specific MDM-related applications on Android.

Supported packages:

  • com.azure.authenticator - Microsoft Authenticator app
  • UserDetailsClient.Droid - User details client for Android
  • com.microsoft.windowsintune.companyportal - Microsoft Intune Company Portal

Example:

"QueryPackages": [
  "com.azure.authenticator",
  "com.microsoft.windowsintune.companyportal"
]
AppRestrictionsMap (Android Only)

The AppRestrictionsMap defines the managed app configuration schema that MDM administrators will see when configuring your app. This generates the app_restrictions.xml file that Android MDM providers use. Each restriction has the following properties:

  • title - Display name for the restriction
  • description - Description of what the restriction does
  • type - Data type (string, bool, integer, choice, multi-select)
  • defaultValue - Default value if not set by MDM

Supported types:

  • string - Text input
  • bool - Boolean (true/false)
  • integer - Numeric input
  • choice - Single selection from predefined options
  • multi-select - Multiple selections from predefined options

Example configurations:

"AppRestrictionsMap": {
  "serverUrl": {
    "title": "Server URL",
    "description": "The URL of the backend server",
    "type": "string",
    "defaultValue": "https://api.company.com"
  },
  "debugMode": {
    "title": "Debug Mode",
    "description": "Enable debug logging",
    "type": "bool",
    "defaultValue": false
  },
  "maxRetries": {
    "title": "Max Retries",
    "description": "Maximum number of retry attempts",
    "type": "integer",
    "defaultValue": 3
  }
}

Testing

Testing MDM functionality requires different approaches for each platform. Below are detailed instructions for both Android and iOS.

Testing on Android

The easiest way to test MDM functionality on Android is to use TestDPC (Test Device Policy Controller), a free testing tool provided by Google.

Prerequisites

  1. Profile Support: You can use TestDPC with either work profile or personal profile
  2. Device Admin Setup: When setting TestDPC as device admin, ensure you have no Google accounts signed in if you're using your personal device
  3. Development Environment: Make sure you have Android development environment properly configured

Setup Steps

  1. Install TestDPC from Google Play Store
  2. Set up Device Admin:
    • Open TestDPC
    • Follow the device admin setup wizard
    • Grant all necessary permissions
  3. Configure your test policies
  4. Install your app (either via ADB or as a managed app)

Testing App Restrictions

  1. Open TestDPC
  2. Navigate to "Manage app restrictions"
  3. Find your app in the list
  4. Configure the restrictions defined in your AppRestrictionsMap:
    • Set values for apiUrl, enableAnalytics, etc.
    • These values will be immediately available to your app
  5. Test in your app:
    import { getConfiguration, isSupported } from 'expo-mdm';
    
    const supported = await isSupported();
    console.log('MDM Supported:', supported);
    
    const config = await getConfiguration();
    console.log('MDM Config:', config);
    // Output: { apiUrl: "https://...", enableAnalytics: true }

Testing App Lock Mode (Kiosk Mode)

  1. In TestDPC, navigate to "Device Policy Management""Lock task mode"
  2. Add your app package name to the lock task whitelist
  3. In your app, test the lock functions:
    import { lockApp, unlockApp, isAppLockingAllowed, isAppLocked } from 'expo-mdm';
    
    const canLock = await isAppLockingAllowed();
    if (canLock) {
      await lockApp(); // Enters kiosk mode
      // User cannot exit app or access other apps
    
      await unlockApp(); // Exits kiosk mode
    }

Alternative Android Testing with Microsoft Intune

For enterprise testing:

  1. Enroll device in Microsoft Intune
  2. Create app configuration policy in Intune admin center
  3. Deploy configuration to test devices
  4. Test with production MDM configuration

Testing on iOS

iOS MDM testing requires an Apple MDM solution. Here are several options:

Option 1: Microsoft Intune (Recommended for Development)

  1. Set up Intune trial account:

    • Sign up for a free Microsoft 365 trial
    • Enable Intune in the admin center
  2. Enroll your iOS device:

    • Install Microsoft Intune Company Portal from App Store
    • Sign in with your test account
    • Follow enrollment instructions
  3. Configure App Configuration Policy:

    • In Intune admin center, navigate to AppsApp configuration policies
    • Create a new policy for iOS/iPadOS managed apps
    • Select your app
    • Add configuration keys matching your AppRestrictionsMap:
      <key>apiUrl</key>
      <string>https://api.example.com</string>
      <key>enableAnalytics</key>
      <true/>
    • Assign to test users/devices
  4. Test in your app:

    import { getConfiguration, isSupported } from 'expo-mdm';
    
    const supported = await isSupported();
    console.log('MDM Supported:', supported);
    
    const config = await getConfiguration();
    console.log('MDM Config:', config);
    // Output: { apiUrl: "https://...", enableAnalytics: 1 }

Option 2: Apple Business Manager + MDM

For production testing:

  1. Enroll in Apple Business Manager
  2. Connect an MDM solution (Jamf, Workspace ONE, etc.)
  3. Create managed app configuration
  4. Deploy to test devices

Option 3: Manual Testing with Xcode (Development Only)

For quick local testing without MDM enrollment:

  1. In your iOS project, add managed configuration to your scheme:

    • Edit Scheme → Run → Arguments
    • Add to Environment Variables:
      com.apple.configuration.managed = {"apiUrl":"https://test.com","enableAnalytics":true}
  2. Or manually set UserDefaults in your app (for development only):

    // Development testing only - this will be replaced by actual MDM in production
    import { NativeModules } from 'react-native';
    
    if (__DEV__) {
      // This simulates MDM configuration for testing
      NativeModules.UserDefaults?.setObject(
        { apiUrl: "https://test.com", enableAnalytics: true },
        "com.apple.configuration.managed"
      );
    }

Testing iOS Guided Access (App Lock Mode)

iOS uses Guided Access instead of a programmatic lock mode. To test:

  1. Enable Guided Access:

    • Go to SettingsAccessibilityGuided Access
    • Toggle on and set a passcode
  2. Configure Triple Click:

    • Settings → AccessibilityAccessibility Shortcut
    • Select Guided Access
  3. Test in your app:

    import { isAppLockingAllowed, isAppLocked } from 'expo-mdm';
    
    const guidedAccessEnabled = await isAppLockingAllowed();
    console.log('Guided Access Enabled:', guidedAccessEnabled);
    
    const inGuidedAccess = await isAppLocked();
    console.log('Currently in Guided Access:', inGuidedAccess);
  4. Activate Guided Access:

    • Triple-click the side/home button while in your app
    • Or go to Settings → Guided Access → Start

Note: iOS does not allow programmatic entry/exit of Guided Access for security reasons. The lockApp() and unlockApp() methods will return false on iOS. Users must manually enable/disable Guided Access.

Testing Event Listeners

Both platforms support listening to MDM configuration changes:

import { addEventListener } from 'expo-mdm';

// Listen for configuration changes
const subscription = addEventListener('onManagedAppConfigChange', (event) => {
  console.log('MDM config changed:', event.config);
});

// Listen for lock status changes
const lockSubscription = addEventListener('onAppLockStatusChange', (event) => {
  console.log('Lock status changed:', event.isLocked);
});

// Clean up
subscription.remove();
lockSubscription.remove();

Contributing

We welcome contributions! Please feel free to submit issues, feature requests, or pull requests.

Areas where we need help:

  • Documentation improvements
  • Additional features for both platforms
  • Testing and bug reports
  • Integration examples with different MDM providers

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

If you encounter any issues or have questions, please file an issue on our GitHub repository.