Skip to main content
Battery optimization exemptions allow your app to bypass Doze mode restrictions, enabling more reliable background execution. However, requesting exemptions requires careful consideration of both technical requirements and Google Play policies.

Understanding battery optimizations

By default, all apps are subject to battery optimizations. This means:
  • The system restricts background execution during Doze mode
  • Network access is suspended when the device is idle
  • Wake locks may be ignored
  • Background jobs and alarms are deferred
When an app is exempt from battery optimizations (also called “ignoring battery optimizations”), it can:
  • Access the network during Doze mode
  • Hold partial wake locks that remain effective
  • Execute background work more reliably
  • Receive alarms with less deferral
Battery optimization exemptions were introduced in Android 6.0 (API 23) as part of the Doze mode feature. On earlier Android versions, these APIs are not available and all apps operate without such restrictions.

Checking exemption status

Always check your app’s current exemption status before requesting changes:
import BackgroundGuardian from 'react-native-background-guardian';

const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();

if (isIgnoring) {
  console.log('App is exempt from battery optimizations');
} else {
  console.log('App is subject to battery optimization restrictions');
}
The implementation checks this using the Android PowerManager:
// From BackgroundGuardianModule.kt:225-243
val powerManager = context.getSystemService(Context.POWER_SERVICE) as? PowerManager
val packageName = context.packageName
val isIgnoring = powerManager.isIgnoringBatteryOptimizations(packageName)
On iOS, isIgnoringBatteryOptimizations() always returns true as the concept doesn’t apply in the same way. iOS handles background execution through Background Modes configured in Xcode.

Two methods for requesting exemptions

There are two approaches to guide users toward granting battery optimization exemptions:

Method 1: Direct dialog (restricted)

This method shows a direct “Allow” dialog to the user:
const dialogShown = await BackgroundGuardian.requestBatteryOptimizationExemption();

if (dialogShown) {
  console.log('User was prompted for battery optimization exemption');
}
Pros:
  • User-friendly - single tap to approve
  • Faster user experience
Cons:
  • Requires REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission
  • Subject to strict Google Play policy restrictions
  • Can lead to app rejection if misused
Google Play Policy Requirement:This method uses ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, which requires the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission. Google Play only allows this for specific app categories. See Acceptable use cases below.

Method 2: Settings list (safe)

This method opens the system’s battery optimization settings list:
await BackgroundGuardian.openBatteryOptimizationSettings();
The user must then:
  1. Find your app in the list
  2. Tap on it
  3. Select “Don’t optimize” or “Allow”
Pros:
  • No special permissions required
  • Safe for all apps - no Google Play restrictions
  • No risk of policy violations
Cons:
  • Requires more user steps
  • Some users may struggle to find the app in the list
For most apps, use Method 2 (openBatteryOptimizationSettings) to avoid potential Google Play policy issues. Only use Method 1 if your app clearly falls into an acceptable use case category.

Acceptable use cases

If you use requestBatteryOptimizationExemption(), your app must fall into one of these categories to comply with Google Play policies:

Chat, voice, and video apps

Apps requiring real-time messaging or calls where Firebase Cloud Messaging (FCM) high-priority messages are insufficient.

Examples: WhatsApp, Signal, Zoom

Task automation

Apps that schedule and execute automated actions, macros, or workflows on behalf of the user.

Examples: Tasker, IFTTT, automation tools

Health and fitness tracking

Apps that continuously track health metrics, workouts, or activity data in the background.

Examples: Strava, MyFitnessPal, continuous glucose monitors

Device connection and companion apps

Apps that maintain persistent connections to external devices like smartwatches, IoT devices, or medical equipment.

Examples: Wear OS companion app, smart home controllers

Personal safety apps

Apps providing emergency services, SOS features, or location tracking for personal safety.

Examples: Life360, emergency alert systems

VPN and network tools

Apps that provide VPN services, proxies, or require persistent network connections.

Examples: NordVPN, network monitoring tools

If your app does not fit these categories, do not use requestBatteryOptimizationExemption(). Instead, use openBatteryOptimizationSettings() and instruct the user to manually grant the exemption.Violating Google Play policies can result in:
  • App removal from the Play Store
  • Developer account suspension
  • Loss of user trust

Implementation guide

Complete exemption request flow

Here’s a complete implementation that checks status, requests exemption, and handles the result:
import { useEffect, useState } from 'react';
import { AppState, Alert } from 'react-native';
import BackgroundGuardian from 'react-native-background-guardian';

export function useBatteryOptimization() {
  const [isIgnoring, setIsIgnoring] = useState(false);
  const [isLoading, setIsLoading] = useState(true);

  const checkStatus = async () => {
    const status = await BackgroundGuardian.isIgnoringBatteryOptimizations();
    setIsIgnoring(status);
    setIsLoading(false);
  };

  useEffect(() => {
    checkStatus();

    // Refresh status when app comes to foreground
    const subscription = AppState.addEventListener('change', (state) => {
      if (state === 'active') {
        checkStatus();
      }
    });

    return () => subscription.remove();
  }, []);

  const requestExemption = async () => {
    if (isIgnoring) {
      Alert.alert(
        'Already Optimized',
        'Your app is already exempt from battery optimizations.'
      );
      return;
    }

    Alert.alert(
      'Battery Optimization',
      'To ensure reliable background operation, please allow this app to run in the background.',
      [
        { text: 'Cancel', style: 'cancel' },
        {
          text: 'Continue',
          onPress: async () => {
            // Use the safe method for most apps
            await BackgroundGuardian.openBatteryOptimizationSettings();
          },
        },
      ]
    );
  };

  return {
    isIgnoring,
    isLoading,
    requestExemption,
    checkStatus,
  };
}

For apps with acceptable use cases

If your app qualifies for the direct dialog method:
const requestExemption = async () => {
  const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();
  
  if (isIgnoring) {
    return true; // Already exempt
  }

  // Show explanation first
  Alert.alert(
    'Background Access Required',
    'This app needs to run in the background to deliver real-time messages. ' +
    'Please allow battery optimization exemption in the next dialog.',
    [
      { text: 'Cancel', style: 'cancel' },
      {
        text: 'Continue',
        onPress: async () => {
          // Use direct dialog for qualifying apps
          const shown = await BackgroundGuardian.requestBatteryOptimizationExemption();
          
          if (!shown) {
            // Fallback to settings list if dialog fails
            await BackgroundGuardian.openBatteryOptimizationSettings();
          }
        },
      },
    ]
  );
};

Permissions required

The library automatically includes the necessary permission in its Android manifest:
<!-- From the library's AndroidManifest.xml -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
This permission is automatically merged into your app’s manifest during the build process. No additional configuration is needed.
The REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission is not a runtime permission and doesn’t require user approval. However, its usage is monitored by Google Play’s policy enforcement.

Testing exemption behavior

You can verify that battery optimization exemptions work correctly:

1. Check initial state

const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();
console.log('Initial exemption status:', isIgnoring);

2. Request exemption

await BackgroundGuardian.openBatteryOptimizationSettings();
// User grants exemption in settings

3. Verify change after returning to app

// Use AppState to detect when user returns
AppState.addEventListener('change', async (state) => {
  if (state === 'active') {
    const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();
    console.log('Updated exemption status:', isIgnoring);
  }
});

4. Test Doze behavior

With exemption granted, test that your app works during Doze:
# Force device into Doze mode
adb shell dumpsys battery unplug
adb shell dumpsys deviceidle force-idle

# Your app should maintain network access and wake locks

Limitations and caveats

1. Exemption doesn’t override Power Save mode

Battery optimization exemptions only affect Doze mode. Power Save (Battery Saver) mode applies system-wide restrictions to all apps, regardless of exemption status:
const isIgnoringOptimization = await BackgroundGuardian.isIgnoringBatteryOptimizations();
const isPowerSave = await BackgroundGuardian.isPowerSaveMode();

if (isIgnoringOptimization && isPowerSave) {
  console.warn('Exempt from Doze but affected by Power Save mode');
}
See the Doze and App Standby page for more details on the difference.

2. OEM restrictions still apply

Standard Android battery optimization exemptions don’t prevent OEM-specific battery management from killing your app. Manufacturers like Xiaomi, Huawei, and Samsung have additional battery optimization layers:
const manufacturer = await BackgroundGuardian.getDeviceManufacturer();

if (['xiaomi', 'huawei', 'oppo', 'vivo'].includes(manufacturer?.toLowerCase() ?? '')) {
  // Also need to handle OEM-specific settings
  await BackgroundGuardian.openOEMSettings();
}
See the OEM Restrictions page for comprehensive guidance.

3. User can revoke exemption

Users can manually revoke battery optimization exemptions at any time through Settings. Always check status before critical operations:
async function performCriticalTask() {
  const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();
  
  if (!isIgnoring) {
    Alert.alert(
      'Background Access Disabled',
      'Battery optimization exemption was revoked. Re-enable for reliable operation?',
      [
        { text: 'Not Now', style: 'cancel' },
        { text: 'Enable', onPress: () => requestExemption() },
      ]
    );
    return;
  }
  
  // Proceed with task
  await doBackgroundWork();
}

4. Android version differences

Battery optimization behavior varies across Android versions:
Android VersionBehavior
< 6.0 (API 23)No battery optimizations exist; all apps run freely
6.0 - 8.1 (API 23-27)Basic Doze mode with maintenance windows
9.0+ (API 28+)App Standby Buckets introduce additional restrictions
12.0+ (API 31+)Stricter alarm and job scheduling limitations

Best practices

1. Request exemptions only when necessary

Don’t request exemptions during onboarding. Wait until the user activates a feature that requires background execution:
async function enableBackgroundSync() {
  // User opted into background sync - NOW request exemption
  const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();
  
  if (!isIgnoring) {
    await requestExemptionWithExplanation();
  }
  
  // Enable the feature
  await startBackgroundSync();
}

2. Provide clear user education

Always explain why you need the exemption before requesting it:
Alert.alert(
  'Enable Background Sync',
  'To keep your data up-to-date while the app is closed, we need permission to run in the background. ' +
  'This ensures you receive timely updates.',
  [
    { text: 'Not Now', style: 'cancel' },
    { text: 'Enable', onPress: () => requestExemption() },
  ]
);

3. Handle denial gracefully

If the user declines the exemption, provide degraded but functional service:
const isIgnoring = await BackgroundGuardian.isIgnoringBatteryOptimizations();

if (!isIgnoring) {
  // Fallback to foreground-only sync
  console.log('Background sync disabled; using foreground-only mode');
  setupForegroundSync();
} else {
  setupBackgroundSync();
}

4. Monitor status changes

Track exemption status throughout the app lifecycle:
import { useEffect, useState } from 'react';
import { AppState } from 'react-native';

export function useExemptionStatus() {
  const [isIgnoring, setIsIgnoring] = useState(false);

  useEffect(() => {
    const checkStatus = async () => {
      const status = await BackgroundGuardian.isIgnoringBatteryOptimizations();
      setIsIgnoring(status);
    };

    checkStatus();

    const subscription = AppState.addEventListener('change', (state) => {
      if (state === 'active') {
        checkStatus();
      }
    });

    return () => subscription.remove();
  }, []);

  return isIgnoring;
}