flutter_macos_permissions 2.0.9
flutter_macos_permissions: ^2.0.9 copied to clipboard
A Flutter plugin for requesting camera, microphone, and notification permissions on macOS.
flutter macos permissions #
A simple Flutter plugin to request Camera, Microphone, Notification ,Location ,FullDiskAccess ,Bluetooth ,Calendar and Screen & system audio recording permissions on macOS.
This plugin provides an easy-to-use API using method channels to handle macOS permissions in your Flutter desktop apps.
Requirements #
- Flutter >= 3.27, Dart >= 3.6
- macOS deployment target >= 10.15
- Supports both CocoaPods and Swift Package Manager for macOS plugin integration
✨ Features #
🎥 Request Camera permission
🎤 Request Microphone permission
🔔 Request Notification permission
🌍 Request Location permission
🅱 Request Bluetooth permission
📅 Request Calendar permission
🖥 Request Screen & system audio recording permission
💾 Check Full Disk Access permission
🔎 Check current permission status
📝 Works with Flutter macOS desktop apps
How to use it ? #
1. Add dependency #
Add this to your package's pubspec.yaml file:
dependencies:
flutter_macos_permissions: <latest_version>
2. Install it You can install packages from the command line: #
with pub :
$ pub get
with Flutter :
$ flutter pub get
3. Import it #
Now in your Dart code, you can use :
import 'package:flutter_macos_permissions/flutter_macos_permissions.dart';
4.How to Use it ? #
Sample app demonstrates how simple the usage of the library actually is.
Using flutter_macos_permissions in your project easy to intregate.
Build permission with FlutterMacosPermissions #
🔹 Request permissions #
- You can request permissions for Camera, Microphone, Notifications ,Location ,Screen & system audio recording ,FullDiskAccess ,Bluetooth and Calendar :
- Every
request*()method returns aFlutterMacosPermissionStatusenum (see "Permission status" section below).
String status = "Idle";
/// Request Permission
void request(String type) async {
FlutterMacosPermissionStatus result = FlutterMacosPermissionStatus.unknown;
try {
switch (type) {
case 'camera':
result = await FlutterMacosPermissions.requestCamera();
break;
case 'microphone':
result = await FlutterMacosPermissions.requestMicrophone();
break;
case 'notification':
result = await FlutterMacosPermissions.requestNotification();
break;
case 'requestLocation':
result = await FlutterMacosPermissions.requestLocation();
break;
case 'requestFullDiskAccess':
result = await FlutterMacosPermissions.requestFullDiskAccess();
break;
case 'requestScreenRecording':
result = await FlutterMacosPermissions.requestScreenRecording();
break;
case 'requestBluetooth':
result = await FlutterMacosPermissions.requestBluetooth();
break;
case 'requestCalendar':
result = await FlutterMacosPermissions.requestCalendar();
break;
}
setState(() {
status = 'Requested $type → ${result.isGranted ? "Granted" : "Denied"} (${result.name})';
});
} catch (e) {
setState(() {
status = 'Error: $e';
});
}
}
Build UI buttons #
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('MacOS Permissions')),
body: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 20),
/// Status Display
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey.shade400,
width: 2, // Border width
),
),
child: Text(status, style: const TextStyle(fontSize: 16)),
),
const SizedBox(height: 20),
/// camera permission and status
permissionCard(
'Camera',
Icons.camera_alt,
() => request('camera'),
() => checkStatus('cameraStatus'),
),
/// microphone permission and status
permissionCard(
'Microphone',
Icons.mic,
() => request('microphone'),
() => checkStatus('microphoneStatus'),
),
/// notification permission and status
permissionCard(
'Notifications',
Icons.notifications,
() => request('notification'),
() => checkStatus('notificationStatus'),
),
/// location permission and status
permissionCard(
'Location',
Icons.location_on,
() => request('requestLocation'),
() => checkStatus('locationStatus'),
),
/// screen recording permission and status
permissionCard(
'Screen & system audio recording',
Icons.screen_share,
() => request('requestScreenRecording'),
() => checkStatus('screenRecordingStatus'),
),
/// full disk access permission and status
permissionCard(
'Full Disk Access',
Icons.folder,
() => request('requestFullDiskAccess'),
() => checkStatus('fullDiskAccessStatus'),
),
/// bluetooth permission and status
permissionCard(
'Bluetooth',
Icons.bluetooth,
() => request('requestBluetooth'),
() => checkStatus('bluetoothStatus'),
),
/// calendar permission and status
permissionCard(
'Calendar',
Icons.calendar_month,
() => request('requestCalendar'),
() => checkStatus('calendarStatus'),
),
],
),
),
);
}
📸 Example #
| without Any Permission | with Camera Permission |
|---|---|
| with Notification Permission | with Location Permission |
|---|---|
| with Bluetooth Permission | with FullDiskAccess Permission |
|---|---|
| with Microphone Permission | Screen & system audio recording Permission |
|---|---|
🔹 Check permission status #
- You can also check the current status without requesting and with requesting.
- Every
*Status()method returns aFlutterMacosPermissionStatusenum value (see "Permission status" section below). *Status()only reads the current OS state — it never shows a system prompt. If it returnsnotDetermined, that means the permission was never requested yet; call the matchingrequest*()method to trigger the actual dialog.
/// Check Permission Status
void checkStatus(String type) async {
FlutterMacosPermissionStatus result = FlutterMacosPermissionStatus.unknown;
try {
switch (type) {
case 'cameraStatus':
result = await FlutterMacosPermissions.cameraStatus();
break;
case 'microphoneStatus':
result = await FlutterMacosPermissions.microphoneStatus();
break;
case 'notificationStatus':
result = await FlutterMacosPermissions.notificationStatus();
break;
case 'locationStatus':
result = await FlutterMacosPermissions.locationStatus();
break;
case 'fullDiskAccessStatus':
result = await FlutterMacosPermissions.fullDiskAccessStatus();
break;
case 'screenRecordingStatus':
result = await FlutterMacosPermissions.screenRecordingStatus();
break;
case 'bluetoothStatus':
result = await FlutterMacosPermissions.bluetoothStatus();
break;
case 'calendarStatus':
result = await FlutterMacosPermissions.calendarStatus();
break;
}
setState(() {
status = 'Status $type → ${result.name}';
});
} catch (e) {
setState(() => status = 'Error: $e');
}
}
Build UI buttons #
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('MacOS Permissions')),
body: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 20),
/// Status Display
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey.shade400,
width: 2, // Border width
),
),
child: Text(status, style: const TextStyle(fontSize: 16)),
),
const SizedBox(height: 20),
/// camera permission and status
permissionCard(
'Camera',
Icons.camera_alt,
() => request('camera'),
() => checkStatus('cameraStatus'),
),
/// microphone permission and status
permissionCard(
'Microphone',
Icons.mic,
() => request('microphone'),
() => checkStatus('microphoneStatus'),
),
/// notification permission and status
permissionCard(
'Notifications',
Icons.notifications,
() => request('notification'),
() => checkStatus('notificationStatus'),
),
/// location permission and status
permissionCard(
'Location',
Icons.location_on,
() => request('requestLocation'),
() => checkStatus('locationStatus'),
),
/// screen recording permission and status
permissionCard(
'Screen & system audio recording',
Icons.screen_share,
() => request('requestScreenRecording'),
() => checkStatus('screenRecordingStatus'),
),
/// full disk access permission and status
permissionCard(
'Full Disk Access',
Icons.folder,
() => request('requestFullDiskAccess'),
() => checkStatus('fullDiskAccessStatus'),
),
/// bluetooth permission and status
permissionCard(
'Bluetooth',
Icons.bluetooth,
() => request('requestBluetooth'),
() => checkStatus('bluetoothStatus'),
),
/// calendar permission and status
permissionCard(
'Calendar',
Icons.calendar_month,
() => request('requestCalendar'),
() => checkStatus('calendarStatus'),
),
],
),
),
);
}
📸 Example #
| Camera Status | Microphone Status | Screen & system audio recording Status |
|---|---|---|
| Notification Status | Location Status |
|---|---|
| Bluetooth Status | FullDiskAccess Status |
|---|---|
📑 Permission Properties #
- The table below shows the available permissions, their method calls, possible enum values, and the System Preferences location that can be opened if the user has denied access.
| Permission | Request Permission | Status Permission | Possible FlutterMacosPermissionStatus Values |
Opens in System Preferences → Privacy & Security |
|---|---|---|---|---|
| Camera | FlutterMacosPermissions.requestCamera() |
FlutterMacosPermissions.cameraStatus() |
authorized, denied, restricted, notDetermined |
Camera |
| Microphone | FlutterMacosPermissions.requestMicrophone() |
FlutterMacosPermissions.microphoneStatus() |
authorized, denied, restricted, notDetermined |
Microphone |
| Notifications | FlutterMacosPermissions.requestNotification() |
FlutterMacosPermissions.notificationStatus() |
authorized, denied, notDetermined, provisional, ephemeral |
Notifications |
| Location | FlutterMacosPermissions.requestLocation() |
FlutterMacosPermissions.locationStatus() |
authorizedAlways, authorizedWhenInUse, denied, restricted, notDetermined |
Location Services |
| Screen & system audio recording | FlutterMacosPermissions.requestScreenRecording() |
FlutterMacosPermissions.screenRecordingStatus() |
authorized, denied |
Screen & system audio recording |
| Bluetooth | FlutterMacosPermissions.requestBluetooth() |
FlutterMacosPermissions.bluetoothStatus() |
authorized, denied, notDetermined, unsupported, unknown |
Bluetooth |
| FullDiskAccess | FlutterMacosPermissions.requestFullDiskAccess() |
FlutterMacosPermissions.fullDiskAccessStatus() |
authorized, denied, notDetermined, unknown |
Full Disk Access |
| Calendar | FlutterMacosPermissions.requestCalendar() |
FlutterMacosPermissions.calendarStatus() |
authorized, denied, restricted, notDetermined, writeOnly |
Calendars |
Calendar requires Info.plist keys. Add
NSCalendarsUsageDescription(pre-macOS 14) and, for macOS 14+,NSCalendarsFullAccessUsageDescription/NSCalendarsWriteOnlyAccessUsageDescriptionto your app'smacos/Runner/Info.plist, or the permission prompt won't appear and the request silently fails.Sandboxed app? If
com.apple.security.app-sandboxistruein yourmacos/Runner/*.entitlementsfiles (the default Flutter macOS template), you also needcom.apple.security.personal-information.calendarsset totruethere — without it the sandbox blocks EventKit outright and the status staysnotDeterminedforever, even after you add the Info.plist keys above.
🔹 Permission status: FlutterMacosPermissionStatus #
- All
request*()/*Status()methods return this enum instead of a rawbool/String, so callers get exhaustiveswitchsupport and no magic-string comparisons. - Values:
authorized,authorizedAlways,authorizedWhenInUse,denied,restricted,notDetermined,provisional,ephemeral,writeOnly,unsupported,unknown. isGrantedistrueforauthorized,authorizedAlways,authorizedWhenInUse,provisional, andwriteOnly.writeOnlyis Calendar-specific: on macOS 14+, an app can be granted write-only calendar access (can create events but not read existing ones) without a full-access prompt.
final status = await FlutterMacosPermissions.fullDiskAccessStatus();
if (status.isGranted) {
// proceed
} else if (status == FlutterMacosPermissionStatus.notDetermined) {
await FlutterMacosPermissions.requestFullDiskAccess();
}
⚠️ Migrating to typed status #
Every request*() and *Status() method now returns Future<FlutterMacosPermissionStatus>
instead of Future<bool> / Future<String>.
// Before
final bool granted = await FlutterMacosPermissions.requestCamera();
final String status = await FlutterMacosPermissions.cameraStatus();
if (status == 'authorized') { ... }
// After
final FlutterMacosPermissionStatus granted = await FlutterMacosPermissions.requestCamera();
final FlutterMacosPermissionStatus status = await FlutterMacosPermissions.cameraStatus();
if (status.isGranted) { ... }
Bugs and Feedback #
We welcome and appreciate any suggestions you may have for improvement. For bugs, questions, and discussions please use the GitHub Issues.
Acknowledgments #
flutter_macos_permissions wraps macOS's native permission APIs (AVFoundation, UserNotifications, CoreLocation, CoreBluetooth, EventKit, and the Screen Recording/Full Disk Access privacy checks) behind a single, simple Dart API so you don't have to write platform channel code by hand.
Contribution #
The DashStack team enthusiastically welcomes contributions and project participation! There are a bunch of things you can do if you want to contribute! The Contributor Guide has all the information you need for everything from reporting bugs to contributing new features.
Credits #
flutter_macos_permissions is owned and maintained by the Dashstack Infotech,Surat.
Follow us for updates and new releases 🚀.