admin管理员组

文章数量:1122832

I’m new to iOS development and currently working on a feature to schedule daily local notifications in my app. Here’s how it’s supposed to work: • Notifications display text from a JSON file. • Users can adjust the time for the notification using a DatePicker in the app settings, but there is a default time set initially. • Notification is scheduled for default time after the user grants permission for notifications.

Everything works as expected except for the very first notification after installing the app. It does not trigger at the default set time. Notifications only start working after the user manually changes the time using the DatePicker in my app settings.

I’m not sure why this happens. I’ve verified that permissions are granted and that scheduling logic runs when the app starts. Is there something I might be missing regarding default values or the notification scheduling?

Any hints or suggestions would be greatly appreciated. Thanks in advance!

My code:

import Foundation
import UserNotifications

class DailyQuoteNotificationManager {
    static let shared = DailyQuoteNotificationManager()
    
    private init() {}
    
    func scheduleDailyQuote() {
        let userDefaults = UserDefaults.standard
        
        // überprüft den aktuellen Berechtigungsstatus füt Benachrichtigungen
        UNUserNotificationCenter.current().getNotificationSettings { settings in
            DispatchQueue.main.async {
                switch settings.authorizationStatus {
                case .authorized:
                    self.scheduleNotification()
                    userDefaults.set(Date(), forKey: "lastScheduledDate")
                case .notDetermined:
                    self.requestNotificationPermission { granted in
                        if granted {
                            self.scheduleNotification()
                            userDefaults.set(Date(), forKey: "lastScheduledDate")
                        } else {
                            print("Notification permission not granted after request.")
                        }
                    }
                default:
                    print("Notification permission not granted or denied.")
                }
            }
        }
    }
    
    private func loadQuotes(from fileName: String) -> [QuranQuoteNotification]? {
        guard let url = Bundle.main.url(forResource: fileName, withExtension: "json") else {
            return nil
        }
        
        do {
            let data = try Data(contentsOf: url)
            let decoder = JSONDecoder()
            let jsonDict = try decoder.decode([String: [QuranQuoteNotification]].self, from: data)
            return jsonDict["quranQuotes"]
        } catch {
            print("Error decoding file: \(fileName).json: \(error)")
            return nil
        }
    }
    
    func getNotificationTime() -> Date {
        let userDefaults = UserDefaults.standard
        return userDefaults.object(forKey: "dailyQuoteNotificationTime") as? Date ?? defaultTime()
    }
    
    func setNotificationTime(_ date: Date) {
        let userDefaults = UserDefaults.standard
        userDefaults.set(date, forKey: "dailyQuoteNotificationTime")
    }
    
    private func defaultTime() -> Date {
        var components = DateComponents()
        components.second = 00
        components.minute = 00
        components.hour = 09
        components.timeZone = TimeZone.current
        return Calendar.current.date(from: components) ?? Date()
    }
    
    private func requestNotificationPermission(completion: @escaping (Bool) -> Void) {
        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            DispatchQueue.main.async {
                if let error = error {
                    print("Error requesting notification permission: \(error.localizedDescription)")
                }
                completion(granted)
            }
        }
    }
    
    private func scheduleNotification() {
        let languageCode = Locale.current.language.languageCode?.identifier ?? "en"
        let jsonFileName = (languageCode == "de") ? "quotes_de" : "quotes_en"
        
        guard let quotes = loadQuotes(from: jsonFileName),
              let randomQuote = quotes.randomElement() else {
            return
        }
        
        let content = UNMutableNotificationContent()
        content.title = (languageCode == "de") ? "Vers des Tages" : "Verse of the Day"
        content.body = randomQuote.quote
        content.sound = .default
        
        let notificationTime = getNotificationTime()
        let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: notificationTime)
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
        let request = UNNotificationRequest(identifier: "dailyQuote", content: content, trigger: trigger)
        let center = UNUserNotificationCenter.current()
        
        center.removePendingNotificationRequests(withIdentifiers: ["dailyQuote"])
        center.add(request) { error in
            if let error = error {
                print("Error scheduling notification: \(error.localizedDescription)")
            } else {
                print("Daily quote notification scheduled for \(notificationTime.formatted()).")
            }
        }
    }
}

My DatePicker:

@State private var dailyVerseNotificationTime = DailyQuoteNotificationManager.shared.getNotificationTime()

DatePicker("Verse of the Day at:", selection: $dailyVerseNotificationTime, displayedComponents: .hourAndMinute)
                        .datePickerStyle(pact)
                        .font(.appFont(16))
                        .frame(height: 46)
                        .padding(.horizontal)
                        .background(.white)
                        .cornerRadius(12)
                        .overlay(
                            RoundedRectangle(cornerRadius: 12)
                                .inset(by: 0.35)
                                .stroke(Color(red: 0.9, green: 0.9, blue: 0.9), lineWidth: 0.7)
                        )
                        .padding(.top, 10)
                        .onChange(of: dailyVerseNotificationTime) {
                            DailyQuoteNotificationManager.shared.setNotificationTime(dailyVerseNotificationTime)
                            DailyQuoteNotificationManager.shared.scheduleDailyQuote()
                            print(dailyVerseNotificationTime)
                        }

I tried and tested through simulator and real device, but notifications only go off after manually changing the time with the date picker.

本文标签: iosDaily local notifications do not work as intendedStack Overflow