requestAlarmPermission method
Request alarm permission
Implementation
@override
Future<String> requestAlarmPermission() async {
debugPrint('Requesting alarm permission');
// Handle alarm permission differently based on platform
if (Platform.isIOS) {
// On iOS, we use notifications for alarms
debugPrint(
'Using notification permission for alarm functionality on iOS',
);
final result = await _invokePermissionMethod(
'requestNotificationPermission',
);
return result;
} else if (Platform.isAndroid) {
try {
final androidVersion = await methodChannel.invokeMethod<int>(
'getAndroidVersion',
);
debugPrint('Android version: $androidVersion');
// Android 12+ has additional restrictions
if (androidVersion != null && androidVersion >= 31) {
debugPrint(
'Android 12+ detected, checking if can schedule exact alarms',
);
// First check if we have a saved permission status
final savedStatus = await methodChannel
.invokeMethod<String>('storage_read', {
'key':
'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
'defaultValue': '',
});
debugPrint('Saved alarm permission status: $savedStatus');
if (savedStatus == 'GRANTED') {
debugPrint('Using saved GRANTED status for alarm permission');
return 'GRANTED';
}
// For Android 12+, check if the app can schedule exact alarms
final canScheduleExactAlarms = await methodChannel.invokeMethod<bool>(
'canScheduleExactAlarms',
);
debugPrint('Can schedule exact alarms: $canScheduleExactAlarms');
if (canScheduleExactAlarms == true) {
// Save the permission status
await methodChannel.invokeMethod<bool>('storage_write', {
'key':
'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
'value': 'GRANTED',
});
return 'GRANTED';
}
// If we can't schedule exact alarms, we need to request the permission
debugPrint('Need to request alarm permission');
// Open the alarm settings immediately
await methodChannel.invokeMethod('openAlarmSettings');
// Show a waiting dialog immediately
if (_context != null) {
// Show a waiting dialog
await showDialog(
context: _context!,
barrierDismissible: false,
builder:
(context) => AlertDialog(
title: const Text('Grant Permission'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: const [
CircularProgressIndicator(),
SizedBox(height: 16),
Text(
'Please tap "Allow" or "Allow precise alarms" on the settings screen.',
),
],
),
actions: [
TextButton(
child: const Text('I\'ve Granted Permission'),
onPressed: () => Navigator.pop(context),
),
],
),
);
} else {
// If no context, just wait a bit longer
await Future.delayed(const Duration(seconds: 5));
}
// Wait a bit more to ensure the permission status is updated
await Future.delayed(const Duration(milliseconds: 500));
// Check if the permission was granted
final checkResult = await methodChannel.invokeMethod<bool>(
'checkAlarmPermissionAfterSettings',
);
debugPrint('Alarm permission after settings: $checkResult');
// Try again if still not granted
if (checkResult != true) {
debugPrint('Permission still not granted, checking again...');
await Future.delayed(const Duration(seconds: 1));
final secondCheck = await methodChannel.invokeMethod<bool>(
'checkAlarmPermissionAfterSettings',
);
debugPrint('Second check result: $secondCheck');
if (secondCheck == true) {
// Save the result as granted
await methodChannel.invokeMethod<bool>('storage_write', {
'key':
'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
'value': 'GRANTED',
});
return 'GRANTED';
}
}
// Save the result
final status = checkResult == true ? 'GRANTED' : 'DENIED';
await methodChannel.invokeMethod<bool>('storage_write', {
'key': 'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
'value': status,
});
return status;
} else {
// For Android 11 and below, no special permission is needed
debugPrint('Android 11 or below, no special alarm permission needed');
// Save the granted status
await methodChannel.invokeMethod<bool>('storage_write', {
'key': 'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
'value': 'GRANTED',
});
return 'GRANTED';
}
} catch (e) {
debugPrint('Error handling alarm permission: $e');
return 'ERROR';
}
}
// Fallback to the native implementation
try {
debugPrint('Using native implementation for alarm permission');
final result = await methodChannel.invokeMethod<dynamic>(
'requestAlarmPermission',
);
debugPrint('Alarm permission result from native: $result');
// If we get a boolean result, convert it to a string status
if (result is bool) {
final status = result ? 'GRANTED' : 'DENIED';
// Save the status
await methodChannel.invokeMethod<bool>('storage_write', {
'key': 'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
'value': status,
});
return status;
}
return 'DENIED';
} catch (e) {
debugPrint('Error requesting alarm permission: $e');
return 'ERROR';
}
}