StanfordSpezi / SpeziScheduler

Scheduler Module for the Stanford Spezi Ecosystem
https://swiftpackageindex.com/StanfordSpezi/SpeziScheduler/documentation/
MIT License
4 stars 3 forks source link

Missing/Double Local Notifications #25

Closed mjoerke closed 1 year ago

mjoerke commented 1 year ago

Description

As part of an ongoing study (HPDS), study participants reported two separate bugs pertaining to survey notifications:

  1. After installing an app update on TestFlight, the app stopped sending survey notifications. This issue could be resolved by fully uninstalling the previous app build before installing the update through TestFlight.
  2. After about 2 weeks, the app would sometime send double notifications for every survey. This did not happen for all users, and it also appears to have returned back to single notifications after some time.

Our app sends 4 notifications per day, so the ~2 week delay corresponds roughly to the 64 local notification limit.

Reproduction

  1. We were able to reproduce this bug by pushing an identical new build to TestFlight and updating the application without uninstalling the previous version.
  2. This bug is difficult to reproduce and seems to be non-deterministic. One might be able to reproduce this and shorten the 2 week window by creating a test application that schedules 64 notifications each day.

Apologies that I'm not able to offer more exact reproducibility guidelines. I'm happy to help set up small testing applications to diagnose these issues.

Expected behavior

The app should send exactly one notification for each scheduled survey. The app should also continue to send notifications after it is updated (possibly automatically in the background) on TestFlight.

Additional context

Here is the relevant code for our app's survey scheduling:

extension HPDSScheduler {
    /// Creates a default instance of the ``HPDSScheduler`` by scheduling the tasks listed below.
    convenience init() {
        self.init(
            tasks: [
                Task(
                    title: String(localized: "MORNING_SURVEY_TITLE"),
                    description: String(localized: "MORNING_SURVEY_DESCRIPTION"),
                    schedule: Schedule(
                        start: Calendar.current.startOfDay(for: Date()),
                        repetition: .matching(.init(hour: 17, minute: 00)), // Every Day between 8-11 AM
                        end: .numberOfEvents(356)
                    ),
                    notifications: true,
                    context: HPDSTaskContext.questionnaire(Bundle.main.questionnaire(withName: "morning-en-US"))
                ),
                Task(
                    title: String(localized: "MID_DAY_SURVEY_TITLE"),
                    description: String(localized: "MID_DAY_SURVEY_DESCRIPTION"),
                    schedule: Schedule(
                        start: Calendar.current.startOfDay(for: Date()),
                        repetition: .matching(.init(hour: 17, minute: 00)), // Every Day at 11-14 PM
                        end: .numberOfEvents(356)
                    ),
                    notifications: true,
                    context: HPDSTaskContext.questionnaire(Bundle.main.questionnaire(withName: "mid-day-en-US"))
                ),
                Task(
                    title: String(localized: "AFTERNOON_SURVEY_TITLE"),
                    description: String(localized: "AFTERNOON_SURVEY_DESCRIPTION"),
                    schedule: Schedule(
                        start: Calendar.current.startOfDay(for: Date()),
                        repetition: .matching(.init(hour: 17, minute: 00)), // Every Day at 14-17 PM
                        end: .numberOfEvents(356)
                    ),
                    notifications: true,
                    context: HPDSTaskContext.questionnaire(Bundle.main.questionnaire(withName: "afternoon-en-US"))
                ),
                Task(
                    title: String(localized: "END_OF_THE_DAY_SURVEY_TITLE"),
                    description: String(localized: "END_OF_THE_DAY_SURVEY_DESCRIPTION"),
                    schedule: Schedule(
                        start: Calendar.current.startOfDay(for: Date()),
                        repetition: .matching(.init(hour: 17, minute: 00)), // Every Day at 17:00 PM
                        end: .numberOfEvents(356)
                    ),
                    notifications: true,
                    context: HPDSTaskContext.questionnaire(Bundle.main.questionnaire(withName: "end-of-day-en-US"))
                )
            ]
        )
    }
}

Code of Conduct

PSchmiedmayer commented 1 year ago

@mjoerke #28 should have addressed the problems described in this issue. Please let us know if you ca somehow reproduce this in one of your applications 👍

mjoerke commented 1 year ago

Thank you @PSchmiedmayer!! We will update this in our application and distribute it for testing 👍