fluxy_permissions
Permission management plugin for the Fluxy framework, providing a unified API for handling device permissions across iOS and Android platforms.
Installation
Add this to your package's pubspec.yaml file:
dependencies:
fluxy_permissions: ^1.0.0
Usage
First, ensure you have Fluxy initialized and the permissions plugin registered:
import 'package:fluxy/fluxy.dart';
void main() async {
await Fluxy.init();
Fluxy.autoRegister(); // Registers all available plugins including permissions
runApp(MyApp());
}
Basic Permission Management
import 'package:fluxy/fluxy.dart';
class PermissionService {
// Request single permission
Future<bool> requestCameraPermission() async {
try {
final status = await Fx.permissions.request(FluxyPermission.camera);
if (status == FluxyPermissionStatus.granted) {
Fx.toast.success('Camera permission granted');
return true;
} else {
Fx.toast.error('Camera permission denied');
return false;
}
} catch (e) {
Fx.toast.error('Permission request failed: $e');
return false;
}
}
// Check permission status
Future<bool> checkPermission(FluxyPermission permission) async {
try {
final status = await Fx.permissions.statusOf(permission);
return status == FluxyPermissionStatus.granted;
} catch (e) {
Fx.toast.error('Permission check failed: $e');
return false;
}
}
// Request multiple permissions
Future<Map<FluxyPermission, FluxyPermissionStatus>> requestMultiplePermissions() async {
try {
final results = await Fx.permissions.requestAll([
FluxyPermission.camera,
FluxyPermission.microphone,
FluxyPermission.storage,
FluxyPermission.location,
]);
// Check results
for (final entry in results.entries) {
final permission = entry.key;
final status = entry.value;
if (status == FluxyPermissionStatus.granted) {
Fx.toast.success('${permission.toString()} granted');
} else {
Fx.toast.error('${permission.toString()} denied');
}
}
return results;
} catch (e) {
Fx.toast.error('Multiple permission request failed: $e');
return {};
}
}
}
Permission Status Monitoring
class PermissionMonitor {
// Listen to permission status changes
void startPermissionMonitoring() {
Fx.permissions.statusChanges.listen((permissionChange) {
final permission = permissionChange.permission;
final status = permissionChange.status;
switch (status) {
case FluxyPermissionStatus.granted:
Fx.toast.success('${permission.toString()} granted');
break;
case FluxyPermissionStatus.denied:
Fx.toast.warning('${permission.toString()} denied');
break;
case FluxyPermissionStatus.permanentlyDenied:
Fx.toast.error('${permission.toString()} permanently denied');
_showSettingsDialog();
break;
case FluxyPermissionStatus.restricted:
Fx.toast.error('${permission.toString()} restricted');
break;
}
});
}
// Show settings dialog for permanently denied permissions
void _showSettingsDialog() {
Fx.dialog.confirm(
'Permission Required',
'This permission is required for the app to function properly. Please enable it in settings.',
onConfirm: () => Fx.permissions.openSettings(),
confirmText: 'Open Settings',
cancelText: 'Cancel',
);
}
}
Advanced Permission Handling
class AdvancedPermissionService {
// Request permission with rationale
Future<bool> requestWithRationale(FluxyPermission permission, String rationale) async {
try {
// Check if permission is already granted
final status = await Fx.permissions.statusOf(permission);
if (status == FluxyPermissionStatus.granted) {
return true;
}
// Show rationale dialog
final shouldProceed = await Fx.dialog.confirm(
'Permission Required',
rationale,
confirmText: 'Grant Permission',
cancelText: 'Cancel',
);
if (!shouldProceed) {
return false;
}
// Request permission
final newStatus = await Fx.permissions.request(permission);
return newStatus == FluxyPermissionStatus.granted;
} catch (e) {
Fx.toast.error('Permission request failed: $e');
return false;
}
}
// Handle permanently denied permissions
Future<bool> handlePermanentlyDenied(FluxyPermission permission) async {
try {
final status = await Fx.permissions.statusOf(permission);
if (status == FluxyPermissionStatus.permanentlyDenied) {
final shouldOpenSettings = await Fx.dialog.confirm(
'Permission Permanently Denied',
'This permission was permanently denied. Please enable it in app settings.',
confirmText: 'Open Settings',
cancelText: 'Cancel',
);
if (shouldOpenSettings) {
await Fx.permissions.openSettings();
return true;
}
}
return false;
} catch (e) {
Fx.toast.error('Failed to handle permanently denied permission: $e');
return false;
}
}
}
Permission Utilities
class PermissionUtils {
// Check if any permissions are granted
Future<bool> hasAnyPermission(List<FluxyPermission> permissions) async {
for (final permission in permissions) {
final status = await Fx.permissions.statusOf(permission);
if (status == FluxyPermissionStatus.granted) {
return true;
}
}
return false;
}
// Check if all permissions are granted
Future<bool> hasAllPermissions(List<FluxyPermission> permissions) async {
for (final permission in permissions) {
final status = await Fx.permissions.statusOf(permission);
if (status != FluxyPermissionStatus.granted) {
return false;
}
}
return true;
}
// Get denied permissions
Future<List<FluxyPermission>> getDeniedPermissions(List<FluxyPermission> permissions) async {
final denied = <FluxyPermission>[];
for (final permission in permissions) {
final status = await Fx.permissions.statusOf(permission);
if (status != FluxyPermissionStatus.granted) {
denied.add(permission);
}
}
return denied;
}
}
Features
- Unified API: Single interface for all platform permissions
- Batch Requests: Request multiple permissions at once
- Status Monitoring: Real-time permission status changes
- Cross-Platform: Works on both iOS and Android
- Error Handling: Comprehensive error handling with specific error types
- User-Friendly: Built-in dialogs and toast notifications
- Settings Integration: Direct access to app settings for permanently denied permissions
- Permission Types: Support for all common device permissions
API Reference
Methods
request(FluxyPermission)- Request a single permissionrequestAll(List<FluxyPermission>)- Request multiple permissionsstatusOf(FluxyPermission)- Get current status of a permissionisGranted(FluxyPermission)- Check if permission is grantedopenSettings()- Open app settingsshouldShowRationale(FluxyPermission)- Check if rationale should be shown
Properties
statusChanges- Stream of permission status changes
Permission Types
FluxyPermission.camera- Camera accessFluxyPermission.microphone- Microphone accessFluxyPermission.storage- Storage accessFluxyPermission.location- Location accessFluxyPermission.photos- Photo library accessFluxyPermission.contacts- Contacts accessFluxyPermission.notifications- Push notificationsFluxyPermission.phone- Phone accessFluxyPermission.sms- SMS accessFluxyPermission.calendar- Calendar access
Permission Status
FluxyPermissionStatus.granted- Permission grantedFluxyPermissionStatus.denied- Permission deniedFluxyPermissionStatus.permanentlyDenied- Permission permanently deniedFluxyPermissionStatus.restricted- Permission restrictedFluxyPermissionStatus.limited- Permission limited (iOS 14+)
Error Handling
The permissions plugin provides comprehensive error handling:
try {
await Fx.permissions.request(FluxyPermission.camera);
} on PermissionException catch (e) {
// Handle specific permission errors
switch (e.type) {
case PermissionErrorType.disabled:
Fx.toast.error('Permission service is disabled');
break;
case PermissionErrorType.denied:
Fx.toast.error('Permission was denied');
break;
case PermissionErrorType.permanentlyDenied:
Fx.toast.error('Permission was permanently denied');
break;
case PermissionErrorType.restricted:
Fx.toast.error('Permission is restricted');
break;
default:
Fx.toast.error('Permission error: $e');
}
} catch (e) {
Fx.toast.error('Unexpected permission error: $e');
}
Platform Configuration
Android
Add the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
iOS
Add the following permissions to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to record audio</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to provide location-based features</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to select images</string>
Security Considerations
- All permission requests require explicit user consent
- Permission status is monitored in real-time
- Sensitive permissions require additional user confirmation
- No unauthorized background permission access
- Proper handling of permanently denied permissions
License
This package is licensed under the MIT License. See the LICENSE file for details.