permission_handler_package 1.0.2 copy "permission_handler_package: ^1.0.2" to clipboard
permission_handler_package: ^1.0.2 copied to clipboard

A professional Flutter package for handling permissions automatically with Riverpod state management, retry logic, and beautiful UI dialogs.

Permission Handler Package #

pub package Flutter License: MIT Riverpod Google Fonts Permission Handler Code Size

A professional Flutter package for handling permissions automatically with Riverpod state management, retry logic, beautiful UI dialogs, and ScreenUtil responsive design.


Table of Contents #


Features #

Feature Description
Automatic Permission Handling Request and manage permissions seamlessly
Riverpod Integration Reactive state management with Riverpod
Smart Retry Logic Configurable retry attempts with user prompts (max 2 retries default)
Permanent Denial Detection Handles permanently denied permissions with settings redirection
System Settings Navigation One-click redirect to app settings
Beautiful UI Dialogs Customizable, theme-aware permission dialogs
Permission Wrapper Easy-to-use widget wrapper for protected screens
Reactive Permission Builder Real-time permission status updates
Responsive Design Built with ScreenUtil for responsive layouts
Custom Theme Support Integrates with your existing theme
Cross-Platform Fully supports both iOS and Android
Zero Configuration Works out of the box with sensible defaults
Type Safety Full Dart type safety with enum-based permissions
Custom Explanation Dialogs Show custom messages before requesting permissions
Permission Groups Request multiple related permissions at once
Platform-Specific Support Automatically handles iOS/Android differences

Installation #

Add to pubspec.yaml:

dependencies:
  permission_handler_package: ^1.0.0

Then run:

flutter pub get

Required dependencies (auto-included):

permission_handler: ^11.3.0     # Platform permission handling
riverpod: ^2.4.0                # State management
flutter_riverpod: ^2.4.0        # Riverpod for Flutter
flutter_screenutil: ^5.9.0      # Responsive design
google_fonts: ^6.1.0            # Google Fonts support

Platform Configuration #

Android Setup #

Add to android/app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Storage & Media -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

    <!-- Camera -->
    <uses-permission android:name="android.permission.CAMERA" />

    <!-- Location -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <!-- Microphone -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <!-- Contacts -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />

    <!-- Phone & SMS -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />

    <!-- Notifications (Android 13+) -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <!-- Calendar -->
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />

    <!-- Sensors -->
    <uses-permission android:name="android.permission.BODY_SENSORS" />

    <!-- Bluetooth -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- App-specific -->
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <application
        android:requestLegacyExternalStorage="true"
        ...>
    </application>

</manifest>

iOS Setup #

Add to ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos and scan documents</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to save and share images</string>

<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs permission to save photos to your library</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to find nearby places</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access for background updates and notifications</string>

<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access for voice recording and calls</string>

<key>NSContactsUsageDescription</key>
<string>This app needs contact access to share with friends and family</string>

<key>NSCalendarsUsageDescription</key>
<string>This app needs calendar access to schedule events and reminders</string>

<key>NSRemindersUsageDescription</key>
<string>This app needs reminders access to set notifications</string>

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs bluetooth access to connect to nearby devices</string>

<key>NSUserTrackingUsageDescription</key>
<string>This app needs tracking permission to provide personalized ads</string>

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
    <string>fetch</string>
    <string>remote-notification</string>
</array>

Quick Start #

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:permission_handler_package/permission_handler_package.dart';

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 812),
      minTextAdapt: true,
      builder: (context, child) {
        return MaterialApp(
          title: 'Permission Demo',
          theme: ThemeData(primarySwatch: Colors.blue),
          home: const SplashScreen(),
        );
      },
    );
  }
}

class SplashScreen extends ConsumerStatefulWidget {
  const SplashScreen({super.key});

  @override
  ConsumerState<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends ConsumerState<SplashScreen> {
  @override
  void initState() {
    super.initState();
    _initializePermissions();
  }

  Future<void> _initializePermissions() async {
    final actionNotifier = ref.read(permissionActionProvider.notifier);

    final granted = await actionNotifier.initializeRequiredPermissions(
      context: context,
      requiredPermissions: [
        PermissionType.camera,
        PermissionType.storage,
        PermissionType.location,
      ],
      title: 'Welcome to the App',
      message: 'We need these permissions to provide you with the best experience.',
    );

    if (granted && mounted) {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (_) => const HomePage()),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: CircularProgressIndicator()),
    );
  }
}

Permission Types & Groups #

Complete Permission Types #

Permission Type Display Name Platform Description
PermissionType.camera Camera Both Camera access for photos/videos
PermissionType.storage Storage Both Read/write external storage
PermissionType.photos Photos iOS only Access photo library
PermissionType.videos Videos iOS only Access video library
PermissionType.audio Audio iOS only Access audio/music files
PermissionType.location Location Both Fine and coarse location
PermissionType.locationAlways Location (Always) Both Always location access
PermissionType.locationWhenInUse Location (While Using) Both Location only when app is open
PermissionType.microphone Microphone Both Audio recording access
PermissionType.contacts Contacts Both Read/write contacts
PermissionType.notifications Notifications Both Push notifications
PermissionType.calendar Calendar Both Calendar events access
PermissionType.reminders Reminders iOS only Reminders access
PermissionType.bluetooth Bluetooth Both Bluetooth connectivity
PermissionType.sensors Sensors Both Body sensors / health data
PermissionType.sms SMS Android only Send/receive SMS
PermissionType.phone Phone Android only Make phone calls
PermissionType.appTrackingTransparency App Tracking iOS only App tracking permission
PermissionType.criticalAlerts Critical Alerts iOS only Critical alerts
PermissionType.scheduleExactAlarm Exact Alarms Android only Schedule exact alarms
PermissionType.ignoreBatteryOptimizations Battery Optimization Android only Ignore battery optimization
PermissionType.manageExternalStorage External Storage Android only Manage external storage
PermissionType.systemAlertWindow System Alerts Android only Draw over other apps
PermissionType.requestInstallPackages Install Packages Android only Install unknown apps
PermissionType.accessNotificationPolicy Notification Policy Android only Do Not Disturb access

Permission Groups #

Group Display Name Permissions Included
PermissionGroup.media Media & Files storage, photos, videos, audio
PermissionGroup.communication Communication camera, microphone, contacts
PermissionGroup.locationServices Location Services location, locationAlways, locationWhenInUse
PermissionGroup.calendar Calendar calendar, reminders
PermissionGroup.bluetooth Bluetooth bluetooth
PermissionGroup.sensors Sensors sensors
PermissionGroup.phone Phone phone, sms

Platform Support Matrix #

Permission iOS Android
camera
storage ⚠️ Limited
photos
videos
audio
location
microphone
contacts
notifications
calendar
reminders
bluetooth
sensors
sms
phone

Usage Examples #

1. Request Single Permission #

class CameraButton extends ConsumerWidget {
  const CameraButton({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ElevatedButton(
      onPressed: () async {
        final actionNotifier = ref.read(permissionActionProvider.notifier);
        final result = await actionNotifier.requestSinglePermission(
          PermissionType.camera,
        );

        if (result.isGranted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Camera ready!')),
          );
        }
      },
      child: const Text('Open Camera'),
    );
  }
}

2. Request Permission Group #

class CommunicationButton extends ConsumerWidget {
  const CommunicationButton({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ElevatedButton(
      onPressed: () async {
        final actionNotifier = ref.read(permissionActionProvider.notifier);
        final results = await actionNotifier.requestPermissionGroup(
          PermissionGroup.communication,
        );

        final allGranted = results.values.every((r) => r.isGranted);
        if (allGranted) {
          print('All communication permissions granted!');
        }
      },
      child: const Text('Request Communication Permissions'),
    );
  }
}

3. Permission Wrapper Widget #

class ProtectedScreen extends StatelessWidget {
  const ProtectedScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return PermissionWrapper(
      requiredPermissions: [PermissionType.camera, PermissionType.storage],
      title: 'Permissions Required',
      message: 'This screen needs camera and storage access to function',
      onPermissionsGranted: () => print('Granted!'),
      onPermissionsDenied: () => print('Denied!'),
      child: Scaffold(
        appBar: AppBar(title: const Text('Camera Screen')),
        body: const CameraWidget(),
      ),
    );
  }
}

4. Reactive Permission Builder #

class CameraFeature extends ConsumerWidget {
  const CameraFeature({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return PermissionBuilder(
      permission: PermissionType.camera,
      builder: (context, isGranted) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              isGranted ? Icons.camera_alt : Icons.camera_alt_outlined,
              size: 80,
              color: isGranted ? Colors.green : Colors.grey,
            ),
            const SizedBox(height: 16),
            Text(
              isGranted ? 'Camera Ready' : 'Camera Permission Required',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            ElevatedButton(
              onPressed: isGranted ? () => _openCamera() : null,
              child: const Text('Take Photo'),
            ),
          ],
        );
      },
    );
  }

  void _openCamera() {}
}

5. Check Permission Status #

class PermissionStatusWidget extends ConsumerWidget {
  const PermissionStatusWidget({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cameraStatus = ref.watch(permissionStatusProvider(PermissionType.camera));

    return cameraStatus.when(
      data: (isGranted) => ListTile(
        leading: Icon(
          isGranted ? Icons.check_circle : Icons.block,
          color: isGranted ? Colors.green : Colors.red,
        ),
        title: const Text('Camera'),
        trailing: Text(isGranted ? 'Granted' : 'Denied'),
      ),
      loading: () => const ListTile(
        leading: CircularProgressIndicator(),
        title: Text('Loading...'),
      ),
      error: (_, __) => const ListTile(
        leading: Icon(Icons.error, color: Colors.red),
        title: Text('Error'),
      ),
    );
  }
}

6. Listen to Permission Changes #

class PermissionListener extends ConsumerStatefulWidget {
  const PermissionListener({super.key});

  @override
  ConsumerState<PermissionListener> createState() => _PermissionListenerState();
}

class _PermissionListenerState extends ConsumerState<PermissionListener> {
  @override
  void initState() {
    super.initState();
    _listenToPermissionChanges();
  }

  void _listenToPermissionChanges() {
    final manager = ref.read(permissionManagerProvider);

    manager.onPermissionChanged.listen((event) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(
              '${event.permission.displayName} permission '
              '${event.result.isGranted ? "granted" : "denied"}',
            ),
            backgroundColor: event.result.isGranted ? Colors.green : Colors.red,
          ),
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) => Container();
}

7. Custom Explanation Dialog #

class CustomPermissionExample extends ConsumerStatefulWidget {
  const CustomPermissionExample({super.key});

  @override
  ConsumerState<CustomPermissionExample> createState() =>
      _CustomPermissionExampleState();
}

class _CustomPermissionExampleState
    extends ConsumerState<CustomPermissionExample> {
  @override
  void initState() {
    super.initState();
    _setupPermissionCallbacks();
  }

  void _setupPermissionCallbacks() {
    final actionNotifier = ref.read(permissionActionProvider.notifier);

    actionNotifier.setPermissionExplanationCallback((permission) async {
      return await showDialog<bool>(
            context: context,
            barrierDismissible: false,
            builder: (context) => AlertDialog(
              title: Text('Why do we need ${permission.displayName}?'),
              content: Text(permission.description),
              actions: [
                TextButton(
                  onPressed: () => Navigator.pop(context, false),
                  child: const Text('Not Now'),
                ),
                ElevatedButton(
                  onPressed: () => Navigator.pop(context, true),
                  child: const Text('Allow'),
                ),
              ],
            ),
          ) ??
          false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Custom Permission')),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            final actionNotifier = ref.read(permissionActionProvider.notifier);
            await actionNotifier.requestSinglePermission(PermissionType.camera);
          },
          child: const Text('Request Camera with Explanation'),
        ),
      ),
    );
  }
}

8. Multiple Permissions with Groups #

class MultiplePermissionsScreen extends ConsumerWidget {
  const MultiplePermissionsScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: const Text('Multiple Permissions')),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            final actionNotifier = ref.read(permissionActionProvider.notifier);

            final granted = await actionNotifier.initializeRequiredPermissions(
              context: context,
              requiredPermissions: [
                PermissionType.camera,
                PermissionType.microphone,
              ],
              requiredGroups: [
                PermissionGroup.locationServices,
                PermissionGroup.media,
              ],
              title: 'Permissions Required',
              message: 'This app needs various permissions to function properly.',
            );

            if (granted && context.mounted) {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(content: Text('All permissions granted!')),
              );
            }
          },
          child: const Text('Request All Permissions'),
        ),
      ),
    );
  }
}

9. Check Group Permission Status #

class GroupStatusWidget extends ConsumerWidget {
  const GroupStatusWidget({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final mediaGroupStatus =
        ref.watch(permissionGroupStatusProvider(PermissionGroup.media));

    return mediaGroupStatus.when(
      data: (allGranted) => Card(
        child: ListTile(
          leading: Icon(
            allGranted ? Icons.check_circle : Icons.warning,
            color: allGranted ? Colors.green : Colors.orange,
          ),
          title: const Text('Media Permissions'),
          subtitle: Text(allGranted ? 'All granted' : 'Some permissions missing'),
          trailing: allGranted
              ? const Icon(Icons.check, color: Colors.green)
              : ElevatedButton(
                  onPressed: () => _requestMediaPermissions(ref),
                  child: const Text('Grant All'),
                ),
        ),
      ),
      loading: () => const Card(child: ListTile(title: Text('Loading...'))),
      error: (_, __) => const Card(child: ListTile(title: Text('Error'))),
    );
  }

  Future<void> _requestMediaPermissions(WidgetRef ref) async {
    final actionNotifier = ref.read(permissionActionProvider.notifier);
    await actionNotifier.requestPermissionGroup(PermissionGroup.media);
    ref.invalidate(permissionGroupStatusProvider(PermissionGroup.media));
  }
}

10. Conditional UI Based on Permissions #

class ConditionalUI extends ConsumerWidget {
  const ConditionalUI({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cameraGranted =
        ref.watch(permissionStatusProvider(PermissionType.camera));
    final microphoneGranted =
        ref.watch(permissionStatusProvider(PermissionType.microphone));

    return Column(
      children: [
        if (cameraGranted.value == true)
          const CameraWidget()
        else
          const PermissionRequestCard(permission: PermissionType.camera),
        if (microphoneGranted.value == true)
          const MicrophoneWidget()
        else
          const PermissionRequestCard(permission: PermissionType.microphone),
      ],
    );
  }
}

API Reference #

PermissionActionNotifier Methods #

Method Parameters Returns Description
initializeRequiredPermissions() context, requiredPermissions, requiredGroups?, showInitialScreen?, title?, message? Future<bool> Initialize and request all required permissions
requestSinglePermission() permission Future<PermissionResult> Request a single permission
requestPermissionGroup() group, showExplanation? Future<Map<PermissionType, PermissionResult>> Request all permissions in a group
setPermissionExplanationCallback() callback void Set custom explanation callback for permissions
setGroupExplanationCallback() callback void Set custom explanation callback for groups
reset() void Reset permission state

PermissionManager Methods #

Method Parameters Returns Description
checkPermissionsStatus() List<PermissionType> Future<Map<PermissionType, PermissionResult>> Check status of multiple permissions
requestPermission() PermissionType Future<PermissionResult> Request a single permission
requestPermissions() List<PermissionType> Future<Map<PermissionType, PermissionResult>> Request multiple permissions
requestPermissionWithExplanation() PermissionType, showExplanation? Future<PermissionResult> Request with optional explanation dialog
requestPermissionGroup() PermissionGroup, showExplanation? Future<Map<PermissionType, PermissionResult>> Request a permission group
openAppSettings() Future<void> Open app settings page
isPermissionGranted() PermissionType Future<bool> Check if a permission is granted
isPermissionPermanentlyDenied() PermissionType Future<bool> Check if permanently denied
checkGroupPermissionsStatus() List<PermissionGroup> Future<Map<PermissionGroup, bool>> Check group permissions status
isGroupSupported() PermissionGroup bool Check if group is supported on platform
getPlatformNote() PermissionType String Get platform-specific note
clearCache() PermissionType void Clear cache for a specific permission
clearAllCache() void Clear all cached permission results
dispose() void Dispose the manager

PermissionResult Properties #

Property Type Description
permission PermissionType The permission type
isGranted bool Whether permission is granted
isPermanentlyDenied bool Whether permanently denied
status PermissionStatus Raw permission status
timestamp DateTime When the result was created
isDenied bool Whether permission is denied
isLimited bool Whether permission is limited (iOS)
isRestricted bool Whether permission is restricted (iOS)

PermissionGroup Properties #

Property Type Description
displayName String User-friendly group name
icon String Emoji icon for the group
permissions List<PermissionType> All permissions in the group

Widgets #

Widget Purpose
PermissionWrapper Wraps widgets that require permissions before rendering
PermissionBuilder Rebuilds UI reactively based on permission status
PermissionInitialDialog Dialog shown on initial permission request
PermissionDeniedDialog Dialog shown when a permission is denied
PermissionPermanentDialog Dialog shown when a permission is permanently denied

Providers #

Provider Type Description
permissionManagerProvider Provider<PermissionManager> Provides PermissionManager instance
permissionStateProvider ChangeNotifierProvider<PermissionNotifier> Provides permission state
permissionActionProvider StateNotifierProvider<PermissionActionNotifier, AsyncValue<void>> Provides permission actions
permissionStatusProvider FutureProvider.family<bool, PermissionType> Watches a single permission status
permissionsStatusProvider FutureProvider.family<Map<PermissionType, bool>, List<PermissionType>> Watches multiple permissions
permissionGroupStatusProvider FutureProvider.family<bool, PermissionGroup> Watches group permission status

Customization #

Custom Theme Integration #

ThemeData myTheme() {
  return ThemeData(
    colorScheme: const ColorScheme.light(
      primary: Colors.blue,
      error: Colors.red,
      surface: Colors.white,
    ),
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      ),
    ),
  );
}

MaterialApp(
  theme: myTheme(),
  home: const PermissionWrapper(
    requiredPermissions: [PermissionType.camera],
    child: MyHomePage(),
  ),
);

Custom Loading Widget #

PermissionWrapper(
  requiredPermissions: [PermissionType.camera],
  loadingWidget: const Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        CircularProgressIndicator(),
        SizedBox(height: 16),
        Text('Loading permissions...'),
      ],
    ),
  ),
  child: const YourWidget(),
);

Custom Denied Widget #

PermissionWrapper(
  requiredPermissions: [PermissionType.camera],
  permissionDeniedWidget: Scaffold(
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Icon(Icons.block, size: 80, color: Colors.red),
          const SizedBox(height: 16),
          const Text('Camera Permission Required'),
          const SizedBox(height: 16),
          ElevatedButton(
            onPressed: () {},
            child: const Text('Open Settings'),
          ),
        ],
      ),
    ),
  ),
  child: const YourWidget(),
);

Cheatsheet #

One-line permission requests:

// Single permission
final result = await ref.read(permissionActionProvider.notifier)
    .requestSinglePermission(PermissionType.camera);

// Permission group
final results = await ref.read(permissionActionProvider.notifier)
    .requestPermissionGroup(PermissionGroup.communication);

// Initialize multiple permissions
final granted = await ref.read(permissionActionProvider.notifier)
    .initializeRequiredPermissions(
      context: context,
      requiredPermissions: [PermissionType.camera, PermissionType.microphone],
    );

Permission status checks:

// Watch single permission reactively
final isGranted = ref.watch(permissionStatusProvider(PermissionType.camera)).value ?? false;

// Watch group permission reactively
final groupGranted = ref.watch(permissionGroupStatusProvider(PermissionGroup.media)).value ?? false;

// Manual async check
final manager = ref.read(permissionManagerProvider);
final isGranted = await manager.isPermissionGranted(PermissionType.camera);

Quick widget wrappers:

// Wrapper for protected screens
PermissionWrapper(
  requiredPermissions: [PermissionType.camera],
  child: YourWidget(),
)

// Reactive builder
PermissionBuilder(
  permission: PermissionType.camera,
  builder: (context, isGranted) => YourWidget(isGranted),
)

Platform-specific handling:

import 'dart:io';

if (Platform.isIOS) {
  await actionNotifier.requestSinglePermission(PermissionType.photos);
} else {
  await actionNotifier.requestSinglePermission(PermissionType.storage);
}

Custom explanation callbacks:

actionNotifier.setPermissionExplanationCallback((permission) async {
  return await showMyCustomDialog();
});

actionNotifier.setGroupExplanationCallback((group) async {
  return await showMyGroupDialog();
});

Quick check and request:

final manager = ref.read(permissionManagerProvider);
final hasPermission = await manager.isPermissionGranted(PermissionType.camera);

if (!hasPermission) {
  final result = await manager.requestPermission(PermissionType.camera);
  if (result.isGranted) {
    // Proceed
  }
}

Listen to permission changes:

ref.listen(permissionStateProvider, (previous, next) {
  if (next.isPermissionGranted(PermissionType.camera)) {
    print('Camera permission granted!');
  }
});

Common permission combinations:

// Camera app
requiredPermissions: [PermissionType.camera, PermissionType.storage]

// Voice recorder
requiredPermissions: [PermissionType.microphone, PermissionType.storage]

// Navigation app
requiredGroups: [PermissionGroup.locationServices]

// Social media
requiredGroups: [PermissionGroup.communication, PermissionGroup.media]

// Health app
requiredPermissions: [PermissionType.sensors]

Troubleshooting #

Permission dialog not showing

Ensure permissions are declared in your platform-specific files — AndroidManifest.xml for Android, Info.plist for iOS.

Permanently denied not detected

Clear app data or reinstall to reset permission state.

# Android
adb uninstall com.yourapp.package

# iOS — delete and reinstall the app from the device

Riverpod provider not found

Wrap your app root with ProviderScope:

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

ScreenUtil errors

Initialize ScreenUtilInit at the top of your widget tree:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 812),
      builder: (context, child) => MaterialApp(home: child),
      child: const HomePage(),
    );
  }
}

Memory leaks

Dispose PermissionManager when done:

@override
void dispose() {
  ref.read(permissionManagerProvider).dispose();
  super.dispose();
}

FAQ #

Q: How do I request permissions on app startup?

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _requestPermissions();
  });
}

Future<void> _requestPermissions() async {
  final notifier = ref.read(permissionActionProvider.notifier);
  await notifier.initializeRequiredPermissions(
    context: context,
    requiredPermissions: [PermissionType.camera, PermissionType.storage],
  );
}

Q: How do I handle multiple permissions independently?

final cameraStatus  = ref.watch(permissionStatusProvider(PermissionType.camera));
final storageStatus = ref.watch(permissionStatusProvider(PermissionType.storage));
// Each provider updates independently

Q: Can I use this without Riverpod?

Yes, use PermissionManager directly:

final manager = PermissionManager();
final granted = await manager.isPermissionGranted(PermissionType.camera);

Q: How do I test permissions in development?

// In your test setup
await Permission.camera.request();

Q: Does this work with Flutter Web?

No. This package targets mobile platforms (iOS and Android) only.

Q: How do I reset permission state?

ref.read(permissionActionProvider.notifier).reset();

Q: How do I open app settings manually?

final manager = ref.read(permissionManagerProvider);
await manager.openAppSettings();

Q: How do I check if a permission group is supported on the current platform?

final manager = ref.read(permissionManagerProvider);
final isSupported = manager.isGroupSupported(PermissionGroup.media);

Q: How do I clear the permission cache?

final manager = ref.read(permissionManagerProvider);
manager.clearCache(PermissionType.camera); // Clear specific permission
manager.clearAllCache();                   // Clear all

Q: How do I get platform-specific notes for a permission?

final manager = ref.read(permissionManagerProvider);
final note = manager.getPlatformNote(PermissionType.photos);
if (note.isNotEmpty) {
  print(note); // e.g. "iOS requires separate permission for photos"
}

License #

MIT License — see LICENSE for details.


Contributing #

Pull requests and issues are welcome! Please see CONTRIBUTING.md for guidelines.


Support #


Made with ❤️ for the Flutter community

0
likes
0
points
341
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

A professional Flutter package for handling permissions automatically with Riverpod state management, retry logic, and beautiful UI dialogs.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_riverpod, flutter_screenutil, google_fonts, permission_handler, riverpod

More

Packages that depend on permission_handler_package

Packages that implement permission_handler_package