WIP: Change DailyNotificationReceiver to exported=true for AlarmManager broadcasts
The DailyNotificationReceiver was not being triggered when scheduled alarms fired, preventing notifications from appearing at the scheduled time. Changed android:exported from "false" to "true" to allow AlarmManager broadcasts to reach the receiver, especially when the app is closed or the device is in doze mode. This is a work-in-progress change to diagnose why notifications aren't firing. The receiver should log "DN|RECEIVE_START" when triggered, but we were not seeing these logs even when alarms were scheduled. Next steps: - Test if receiver is now triggered when alarm fires - Verify notifications appear at scheduled time - Consider adding permission check if keeping exported=true for security
This commit is contained in:
@@ -44,15 +44,18 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- Daily Notification Plugin Receivers (must be inside application) -->
|
<!-- Daily Notification Plugin Receivers (must be inside application) -->
|
||||||
|
<!-- DailyNotificationReceiver: Handles alarm-triggered notifications -->
|
||||||
|
<!-- Note: exported="true" allows AlarmManager to trigger this receiver -->
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.timesafari.dailynotification.DailyNotificationReceiver"
|
android:name="com.timesafari.dailynotification.DailyNotificationReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.timesafari.daily.NOTIFICATION" />
|
<action android:name="com.timesafari.daily.NOTIFICATION" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<!-- NotifyReceiver: Handles notification delivery -->
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.timesafari.dailynotification.NotifyReceiver"
|
android:name="com.timesafari.dailynotification.NotifyReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ public class MainActivity extends BridgeActivity {
|
|||||||
registerPlugin(SharedImagePlugin.class);
|
registerPlugin(SharedImagePlugin.class);
|
||||||
|
|
||||||
// Register DailyNotification plugin
|
// Register DailyNotification plugin
|
||||||
// TODO: Uncomment when DailyNotificationPlugin Java class is implemented
|
// Plugin is written in Kotlin but compiles to Java-compatible bytecode
|
||||||
// registerPlugin(com.timesafari.dailynotification.DailyNotificationPlugin.class);
|
registerPlugin(com.timesafari.dailynotification.DailyNotificationPlugin.class);
|
||||||
|
|
||||||
// Initialize SQLite
|
// Initialize SQLite
|
||||||
//registerPlugin(SQLite.class);
|
//registerPlugin(SQLite.class);
|
||||||
|
|||||||
@@ -689,6 +689,30 @@ export default class PushNotificationPermission extends Vue {
|
|||||||
"[PushNotificationPermission] Starting native notification setup",
|
"[PushNotificationPermission] Starting native notification setup",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Import and check plugin availability before using service
|
||||||
|
const { DailyNotification } = await import(
|
||||||
|
"@/plugins/DailyNotificationPlugin"
|
||||||
|
);
|
||||||
|
if (!DailyNotification) {
|
||||||
|
logger.error(
|
||||||
|
"[PushNotificationPermission] DailyNotification plugin not available",
|
||||||
|
);
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "danger",
|
||||||
|
title: NOTIFY_PUSH_SETUP_ERROR.title,
|
||||||
|
text: "DailyNotification plugin is not available. Please rebuild the app.",
|
||||||
|
},
|
||||||
|
PUSH_NOTIFICATION_TIMEOUT_SHORT,
|
||||||
|
);
|
||||||
|
this.callback(false, "", this.messageInput);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
"[PushNotificationPermission] Plugin available, getting service instance",
|
||||||
|
);
|
||||||
const service = NotificationService.getInstance();
|
const service = NotificationService.getInstance();
|
||||||
|
|
||||||
// Request permissions
|
// Request permissions
|
||||||
@@ -741,6 +765,31 @@ export default class PushNotificationPermission extends Vue {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check permissions one more time before scheduling
|
||||||
|
const finalPermissionCheck = await service.checkPermissions();
|
||||||
|
logger.debug(
|
||||||
|
"[PushNotificationPermission] Final permission check before scheduling:",
|
||||||
|
JSON.stringify(finalPermissionCheck, null, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!finalPermissionCheck.granted) {
|
||||||
|
logger.warn(
|
||||||
|
"[PushNotificationPermission] Permissions not fully granted. " +
|
||||||
|
"Notification may not fire. Details:",
|
||||||
|
finalPermissionCheck.details,
|
||||||
|
);
|
||||||
|
// On Android 12+, exact alarms might need to be enabled in system settings
|
||||||
|
if (
|
||||||
|
!finalPermissionCheck.details.exactAlarm &&
|
||||||
|
Capacitor.getPlatform() === "android"
|
||||||
|
) {
|
||||||
|
logger.warn(
|
||||||
|
"[PushNotificationPermission] Exact alarm permission not granted. " +
|
||||||
|
"User may need to enable 'Exact alarms' in Android system settings.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const success = await service.scheduleDailyNotification({
|
const success = await service.scheduleDailyNotification({
|
||||||
time: time24h,
|
time: time24h,
|
||||||
title,
|
title,
|
||||||
@@ -765,6 +814,13 @@ export default class PushNotificationPermission extends Vue {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log final status after scheduling
|
||||||
|
const statusAfterSchedule = await service.getStatus();
|
||||||
|
logger.info(
|
||||||
|
"[PushNotificationPermission] Notification status after scheduling:",
|
||||||
|
JSON.stringify(statusAfterSchedule, null, 2),
|
||||||
|
);
|
||||||
|
|
||||||
// Save to settings
|
// Save to settings
|
||||||
const timeText = this.notificationTimeText;
|
const timeText = this.notificationTimeText;
|
||||||
const settingsToSave: Record<string, string> = {};
|
const settingsToSave: Record<string, string> = {};
|
||||||
@@ -784,13 +840,22 @@ export default class PushNotificationPermission extends Vue {
|
|||||||
settingsToSave,
|
settingsToSave,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Show success message
|
// Check if exact alarm permission is needed (Android 12+)
|
||||||
|
const needsExactAlarmWarning =
|
||||||
|
Capacitor.getPlatform() === "android" &&
|
||||||
|
!finalPermissionCheck.details.exactAlarm;
|
||||||
|
|
||||||
|
// Show success message with optional warning
|
||||||
|
const successMessage = needsExactAlarmWarning
|
||||||
|
? `${NOTIFY_PUSH_SUCCESS.message} Note: If notifications don't appear, enable "Exact alarms" in Android Settings → Apps → TimeSafari → App settings.`
|
||||||
|
: NOTIFY_PUSH_SUCCESS.message;
|
||||||
|
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
type: "success",
|
type: "success",
|
||||||
title: NOTIFY_PUSH_SUCCESS.title,
|
title: NOTIFY_PUSH_SUCCESS.title,
|
||||||
text: NOTIFY_PUSH_SUCCESS.message,
|
text: successMessage,
|
||||||
},
|
},
|
||||||
PUSH_NOTIFICATION_TIMEOUT_LONG,
|
PUSH_NOTIFICATION_TIMEOUT_LONG,
|
||||||
);
|
);
|
||||||
@@ -802,6 +867,14 @@ export default class PushNotificationPermission extends Vue {
|
|||||||
"[PushNotificationPermission] Error in native notification setup:",
|
"[PushNotificationPermission] Error in native notification setup:",
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
|
// Log additional error details for debugging
|
||||||
|
if (error instanceof Error) {
|
||||||
|
logger.error("[PushNotificationPermission] Error details:", {
|
||||||
|
message: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
name: error.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ export class NativeNotificationService implements NotificationServiceInterface {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request notification permissions from the OS
|
||||||
|
* Shows native permission dialog on first call
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Request notification permissions from the OS
|
* Request notification permissions from the OS
|
||||||
* Shows native permission dialog on first call
|
* Shows native permission dialog on first call
|
||||||
@@ -58,31 +62,132 @@ export class NativeNotificationService implements NotificationServiceInterface {
|
|||||||
try {
|
try {
|
||||||
logger.debug("[NativeNotificationService] Requesting permissions");
|
logger.debug("[NativeNotificationService] Requesting permissions");
|
||||||
|
|
||||||
|
// Check if plugin is available
|
||||||
|
if (!DailyNotification) {
|
||||||
|
logger.error(
|
||||||
|
"[NativeNotificationService] DailyNotification plugin is not available. " +
|
||||||
|
"Make sure the plugin is registered in MainActivity.",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the method exists
|
||||||
|
if (
|
||||||
|
typeof DailyNotification.requestNotificationPermissions !== "function"
|
||||||
|
) {
|
||||||
|
logger.error(
|
||||||
|
"[NativeNotificationService] requestNotificationPermissions method not found on plugin. " +
|
||||||
|
"Available methods: " +
|
||||||
|
Object.keys(DailyNotification).join(", "),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Calling requestNotificationPermissions...",
|
||||||
|
);
|
||||||
|
|
||||||
// Use requestNotificationPermissions() which is the method exposed by iOS
|
// Use requestNotificationPermissions() which is the method exposed by iOS
|
||||||
// For Android, this should also work via the plugin bridge
|
// For Android, this should also work via the plugin bridge
|
||||||
const result = await DailyNotification.requestNotificationPermissions();
|
const result = await DailyNotification.requestNotificationPermissions();
|
||||||
|
|
||||||
logger.debug("[NativeNotificationService] Permission result:", result);
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Permission result:",
|
||||||
|
JSON.stringify(result, null, 2),
|
||||||
|
);
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Result type:",
|
||||||
|
typeof result,
|
||||||
|
"Keys:",
|
||||||
|
result ? Object.keys(result) : "null",
|
||||||
|
);
|
||||||
|
|
||||||
// The result may be PermissionStatus (with granted boolean) or PermissionStatusResult
|
// The result is PermissionStatus which has:
|
||||||
// Handle both formats for compatibility
|
// - granted?: boolean
|
||||||
if ("granted" in result && typeof result.granted === "boolean") {
|
// - notifications: PermissionState ("granted" | "denied" | "prompt")
|
||||||
|
// Handle all possible formats for compatibility
|
||||||
|
if (
|
||||||
|
result &&
|
||||||
|
"granted" in result &&
|
||||||
|
typeof result.granted === "boolean"
|
||||||
|
) {
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Using 'granted' field:",
|
||||||
|
result.granted,
|
||||||
|
);
|
||||||
return result.granted;
|
return result.granted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the notifications PermissionState field
|
||||||
|
if (result && "notifications" in result) {
|
||||||
|
const notificationsState = result.notifications;
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Notifications state:",
|
||||||
|
notificationsState,
|
||||||
|
);
|
||||||
|
// PermissionState can be "granted", "denied", or "prompt"
|
||||||
|
if (notificationsState === "granted") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (notificationsState === "denied") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If "prompt", the user hasn't decided yet, so return false
|
||||||
|
if (notificationsState === "prompt") {
|
||||||
|
logger.warn(
|
||||||
|
"[NativeNotificationService] Permission still in prompt state after request",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for PermissionStatusResult format (from checkPermissionStatus)
|
||||||
if (
|
if (
|
||||||
|
result &&
|
||||||
"allPermissionsGranted" in result &&
|
"allPermissionsGranted" in result &&
|
||||||
typeof result.allPermissionsGranted === "boolean"
|
typeof result.allPermissionsGranted === "boolean"
|
||||||
) {
|
) {
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Using 'allPermissionsGranted' field:",
|
||||||
|
result.allPermissionsGranted,
|
||||||
|
);
|
||||||
return result.allPermissionsGranted;
|
return result.allPermissionsGranted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If result is a boolean directly (some plugin versions might return this)
|
||||||
|
if (typeof result === "boolean") {
|
||||||
|
logger.debug("[NativeNotificationService] Result is boolean:", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Fallback: check status after requesting
|
// Fallback: check status after requesting
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Falling back to checkPermissionStatus...",
|
||||||
|
);
|
||||||
const status = await DailyNotification.checkPermissionStatus();
|
const status = await DailyNotification.checkPermissionStatus();
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Status check result:",
|
||||||
|
JSON.stringify(status, null, 2),
|
||||||
|
);
|
||||||
return status.allPermissionsGranted;
|
return status.allPermissionsGranted;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
"[NativeNotificationService] Permission request failed:",
|
"[NativeNotificationService] Permission request failed:",
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
|
// Log additional error details for debugging
|
||||||
|
if (error instanceof Error) {
|
||||||
|
logger.error("[NativeNotificationService] Error details:", {
|
||||||
|
message: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
name: error.name,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.error(
|
||||||
|
"[NativeNotificationService] Non-Error exception:",
|
||||||
|
JSON.stringify(error, null, 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +199,13 @@ export class NativeNotificationService implements NotificationServiceInterface {
|
|||||||
try {
|
try {
|
||||||
const status = await DailyNotification.checkPermissionStatus();
|
const status = await DailyNotification.checkPermissionStatus();
|
||||||
|
|
||||||
|
// Calculate granted status from individual permissions
|
||||||
|
const allGranted =
|
||||||
|
status.allPermissionsGranted ||
|
||||||
|
(status.notificationsEnabled && status.exactAlarmEnabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
granted: status.allPermissionsGranted,
|
granted: allGranted,
|
||||||
details: {
|
details: {
|
||||||
notifications: status.notificationsEnabled,
|
notifications: status.notificationsEnabled,
|
||||||
exactAlarm: status.exactAlarmEnabled,
|
exactAlarm: status.exactAlarmEnabled,
|
||||||
@@ -134,6 +244,41 @@ export class NativeNotificationService implements NotificationServiceInterface {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Note: The notification channel should be created automatically by the plugin
|
||||||
|
// when the notification is delivered. The "Channel does not exist" warning
|
||||||
|
// during permission checks is expected and not a problem - the channel will
|
||||||
|
// be created when the receiver tries to show the notification.
|
||||||
|
|
||||||
|
// Check permissions before scheduling to ensure everything is set up correctly
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Checking permissions before scheduling",
|
||||||
|
);
|
||||||
|
const permissionStatus = await this.checkPermissions();
|
||||||
|
logger.info(
|
||||||
|
"[NativeNotificationService] Permission status:",
|
||||||
|
JSON.stringify(permissionStatus, null, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if permissions are actually granted (all details must be true)
|
||||||
|
const allPermissionsGranted =
|
||||||
|
permissionStatus.details?.notifications &&
|
||||||
|
permissionStatus.details?.exactAlarm &&
|
||||||
|
permissionStatus.details?.backgroundRefresh;
|
||||||
|
|
||||||
|
if (!allPermissionsGranted) {
|
||||||
|
logger.warn(
|
||||||
|
"[NativeNotificationService] Permissions not fully granted. Details:",
|
||||||
|
permissionStatus.details,
|
||||||
|
);
|
||||||
|
// Continue anyway - the plugin might handle permission requests internally
|
||||||
|
// but log a warning for debugging
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] All permissions granted:",
|
||||||
|
permissionStatus.details,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Cancel any existing notification with the same ID before scheduling a new one
|
// Cancel any existing notification with the same ID before scheduling a new one
|
||||||
// This ensures the old notification is removed from iOS notification center
|
// This ensures the old notification is removed from iOS notification center
|
||||||
try {
|
try {
|
||||||
@@ -155,6 +300,48 @@ export class NativeNotificationService implements NotificationServiceInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log current time and scheduled time for debugging
|
||||||
|
const now = new Date();
|
||||||
|
const [hours, minutes] = options.time.split(":").map(Number);
|
||||||
|
const scheduledTime = new Date();
|
||||||
|
scheduledTime.setHours(hours, minutes, 0, 0);
|
||||||
|
|
||||||
|
// If scheduled time is in the past, it should be scheduled for tomorrow
|
||||||
|
if (scheduledTime < now) {
|
||||||
|
scheduledTime.setDate(scheduledTime.getDate() + 1);
|
||||||
|
logger.info(
|
||||||
|
"[NativeNotificationService] Scheduled time is in the past, will schedule for tomorrow:",
|
||||||
|
{
|
||||||
|
requestedTime: options.time,
|
||||||
|
currentTime: now.toISOString(),
|
||||||
|
scheduledFor: scheduledTime.toISOString(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.info("[NativeNotificationService] Scheduling notification:", {
|
||||||
|
requestedTime: options.time,
|
||||||
|
currentTime: now.toISOString(),
|
||||||
|
scheduledFor: scheduledTime.toISOString(),
|
||||||
|
minutesUntilNotification: Math.round(
|
||||||
|
(scheduledTime.getTime() - now.getTime()) / 1000 / 60,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Calling scheduleDailyReminder with options:",
|
||||||
|
{
|
||||||
|
id: this.reminderId,
|
||||||
|
title: options.title,
|
||||||
|
body: options.body,
|
||||||
|
time: options.time,
|
||||||
|
repeatDaily: true,
|
||||||
|
sound: true,
|
||||||
|
vibration: true,
|
||||||
|
priority: options.priority || "normal",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
await DailyNotification.scheduleDailyReminder({
|
await DailyNotification.scheduleDailyReminder({
|
||||||
id: this.reminderId,
|
id: this.reminderId,
|
||||||
title: options.title,
|
title: options.title,
|
||||||
@@ -166,56 +353,91 @@ export class NativeNotificationService implements NotificationServiceInterface {
|
|||||||
priority: options.priority || "normal",
|
priority: options.priority || "normal",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify the notification was actually scheduled
|
logger.info(
|
||||||
logger.debug(
|
"[NativeNotificationService] scheduleDailyReminder call completed successfully",
|
||||||
"[NativeNotificationService] Verifying notification was scheduled",
|
{
|
||||||
|
reminderId: this.reminderId,
|
||||||
|
requestedTime: options.time,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const remindersResult = await DailyNotification.getScheduledReminders();
|
|
||||||
// Handle both array and object with reminders property
|
|
||||||
const reminders = Array.isArray(remindersResult)
|
|
||||||
? remindersResult
|
|
||||||
: (remindersResult as { reminders: typeof remindersResult })
|
|
||||||
.reminders || [];
|
|
||||||
const scheduledReminder = reminders.find((r) => r.id === this.reminderId);
|
|
||||||
|
|
||||||
if (scheduledReminder && scheduledReminder.isScheduled) {
|
// Verify the notification was actually scheduled (if method is available)
|
||||||
// Verify the time matches what we scheduled
|
// Note: getScheduledReminders() is not implemented on Android, so we
|
||||||
if (scheduledReminder.time !== options.time) {
|
// only verify on iOS. On Android, we assume success if no error was thrown.
|
||||||
logger.error(
|
try {
|
||||||
"[NativeNotificationService] Notification time mismatch!",
|
logger.debug(
|
||||||
|
"[NativeNotificationService] Attempting to verify notification was scheduled",
|
||||||
|
);
|
||||||
|
const remindersResult = await DailyNotification.getScheduledReminders();
|
||||||
|
// Handle both array and object with reminders property
|
||||||
|
const reminders = Array.isArray(remindersResult)
|
||||||
|
? remindersResult
|
||||||
|
: (remindersResult as { reminders: typeof remindersResult })
|
||||||
|
.reminders || [];
|
||||||
|
const scheduledReminder = reminders.find(
|
||||||
|
(r) => r.id === this.reminderId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (scheduledReminder && scheduledReminder.isScheduled) {
|
||||||
|
// Verify the time matches what we scheduled
|
||||||
|
if (scheduledReminder.time !== options.time) {
|
||||||
|
logger.error(
|
||||||
|
"[NativeNotificationService] Notification time mismatch!",
|
||||||
|
{
|
||||||
|
scheduled: scheduledReminder.time,
|
||||||
|
requested: options.time,
|
||||||
|
reminderId: this.reminderId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"[NativeNotificationService] Daily notification verified as scheduled:",
|
||||||
{
|
{
|
||||||
scheduled: scheduledReminder.time,
|
id: scheduledReminder.id,
|
||||||
requested: options.time,
|
time: scheduledReminder.time,
|
||||||
reminderId: this.reminderId,
|
requestedTime: options.time,
|
||||||
|
nextTriggerTime: scheduledReminder.nextTriggerTime,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
"[NativeNotificationService] Notification was not found in scheduled reminders after scheduling",
|
||||||
|
{
|
||||||
|
reminderId: this.reminderId,
|
||||||
|
requestedTime: options.time,
|
||||||
|
allReminders: reminders.map((r) => ({
|
||||||
|
id: r.id,
|
||||||
|
time: r.time,
|
||||||
|
isScheduled: r.isScheduled,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// On iOS, if verification fails, return false
|
||||||
|
// On Android, this method isn't available, so we'll fall through to return true
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} catch (verifyError) {
|
||||||
logger.info(
|
// If getScheduledReminders() is not implemented (Android), assume success
|
||||||
"[NativeNotificationService] Daily notification scheduled successfully:",
|
// since scheduleDailyReminder() completed without error
|
||||||
{
|
if (
|
||||||
id: scheduledReminder.id,
|
verifyError instanceof Error &&
|
||||||
time: scheduledReminder.time,
|
verifyError.message.includes("not implemented")
|
||||||
requestedTime: options.time,
|
) {
|
||||||
nextTriggerTime: scheduledReminder.nextTriggerTime,
|
logger.debug(
|
||||||
},
|
"[NativeNotificationService] getScheduledReminders() not available on this platform (expected on Android). " +
|
||||||
|
"Assuming success since scheduleDailyReminder() completed without error.",
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// For other errors, log but still assume success since the schedule call succeeded
|
||||||
|
logger.warn(
|
||||||
|
"[NativeNotificationService] Verification failed, but schedule call succeeded:",
|
||||||
|
verifyError,
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
logger.warn(
|
|
||||||
"[NativeNotificationService] Notification was not found in scheduled reminders after scheduling",
|
|
||||||
{
|
|
||||||
reminderId: this.reminderId,
|
|
||||||
requestedTime: options.time,
|
|
||||||
allReminders: reminders.map((r) => ({
|
|
||||||
id: r.id,
|
|
||||||
time: r.time,
|
|
||||||
isScheduled: r.isScheduled,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("[NativeNotificationService] Schedule failed:", error);
|
logger.error("[NativeNotificationService] Schedule failed:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user