Подтвердить что ты не робот

Настройка календарных событий/предупреждений в iOS EventKit?

Я пишу свое первое приложение для iOS (я устал пропустить напоминания о событиях и хочу иметь напоминание о правилах, которое, например, для определенных календарей и определенных людей, будет звонить другим, более громким тоном, 10, 5 и за 0 минут до события)

Первая часть - получить доступ к календарю, и благодаря это отличная демонстрация, у меня есть такой вид. Получил приложение, работающее на моем iPhone, и я вижу события в календаре.

(ну, первая часть состоит в том, чтобы вычислить быстрый и общий базовый IOS, над которым я все еще работаю)

Вторая часть - это то, где я хотел спросить, прежде чем тратить часы на исследования. У меня осталось две задачи

  • либо фоновая задача для периодической проверки календаря для новых/обновленных событий, либо возможность программно подписываться на какую-либо шину событий на любые обновления календаря (новые события, изменения событий)

  • уведомления о расписании в определенный момент времени (возможно, я буду использовать это: Как настроить локальное уведомление для следующего сценария?

Как выполнить # 1?

4b9b3361

Ответ 1

Я не думаю, что это можно выполнить без изменения дизайна.

Приложения обычно не работают в фоновом режиме, и за пределами особых случаев, когда Apple разрешает (voip, музыку, местоположение и т.д.), ваше приложение будет приостановлено. Существует API обновления фона, но он недостаточно надежный.

Обратите внимание, что уведомления EKEventStoreChangedNotification хороши только при запуске вашего процесса. Если ваш процесс умирает (из-за давления памяти, перезагрузки устройства, пользователя, убивающего приложение и т.д.), Вы не будете уведомлены об изменениях при запуске приложения, и вам все равно придется перебирать встречи и искать изменения, поэтому вам нужно разработать свой собственный механизм для итерации базы данных EventKit (возможно, в течение определенного периода времени).

Если это личное приложение, вы можете сделать некоторые трюки, чтобы продолжить работать в фоновом режиме, например, играть в музыкальный файл без звука, API-интерфейс voip файла, местоположение и т.д.). Все эти методы помогут вашему приложению работать в фоновом режиме, но принесут ущерб работе от батареи и не будут одобрены Apple после отправки. Один из способов обеспечить согласованную фоновое выполнение - это заставить службу push-уведомлений установить тихий push, чтобы периодически запускать приложение и позволять ему выполнять свою логику. Это может привести к запуску приложения, если оно было убито в фоновом режиме (но не если пользователь его убил).

Ответ 2

Существует ограничение на действия, которые приложение может выполнять в фоновом режиме. Фоновая выборка обычно включает сбор информации из внешнего источника, чтобы ваше приложение могло обновляться после возвращения пользователя.

Обновление фона

Когда включено, iOS контролирует шаблоны использования, чтобы определить, когда извлекать новые данные. Вы не можете решить, когда выдается фоновый выбор, и он не должен использоваться для критических обновлений. В вашем проекте приложение может получать новые события календаря, когда система считает, что это подходящее время. Вы можете реализовать Background Fetch следующим образом:

  • Установите флажок "Фоновая выборка" в разделе "Возможности" вашего приложения.

  • Добавьте в application(_:didFinishLaunchingWithOptions:) следующее:

    UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
    
  • Наконец, выполните эту функцию в AppDelegate.

    func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // Perform calendar updates here
    }
    

Если вы можете скомпрометировать ручное обновление обновлений, лучше всего использовать обновление фона. На данный момент невозможно вручную запросить фоновое обновление.

Ответ 3

Чтобы проверить базу данных календаря на изменения, есть уведомление:

EKEventStoreChanged

Отправляется всякий раз, когда в базу данных календаря вносятся изменения, включая добавление, удаление и изменение событий или напоминаний. Индивидуальные изменения не описаны. Когда вы получите это уведомление, вы должны восстановить все объекты EKEvent и EKReminder, к которым вы обращались, поскольку они считаются устаревшими. Если вы активно редактируете событие и не хотите его переназначать, если это абсолютно необходимо, вы можете вызвать метод обновления на нем. Если метод возвращает true, вам не нужно восстанавливать событие.

Добавить наблюдателя:

NotificationCenter.default.addObserver(self, selector: #selector(storeChanged), name: .EKEventStoreChanged, object: eventStore)

и реализовать метод обработки уведомления

func storeChanged(_ notification: Notification) {}

Ответ 4

Чтобы достичь # 1 либо фоновой задачи, чтобы периодически проверять календарь для новых/обновленных событий, либо возможность программно подписываться на какую-либо шину событий, любые обновления календаря (новые события, изменения событий)

Вы можете сделать следующее.

Прежде всего, чтобы проверить новое/обновленное событие календаря, нам не нужно запускать какие-либо фоновые задачи.

Мы можем получить обновление для событий календаря с помощью уведомления .EKEventStoreChanged, как указано в методе viewWillAppear.

NotificationCenter.default.addObserver(self, selector: #selector(eventStoreChanged:), name: .EKEventStoreChanged, object: eventStore)

Изменить изменения событий календаря (новые/обновленные) EKEventStore, как показано ниже.

func eventStoreChanged(_ notification: Notification) {
    let ekEventStore: EKEventStore? = notification.object
    let now = Date()
    let offsetComponents = DateComponents()
    offsetComponents.day = 0
    offsetComponents.month = 4
    offsetComponents.year = 0
    let endDate: Date? = Calendar.current.date(byAddingComponents: offsetComponents, to: now, options: [])
    let ekEventStoreChangedObjectIDArray: [Any]? = (notification.userInfo?["EKEventStoreChangedObjectIDsUserInfoKey"] as? [Any])
    let predicate: NSPredicate? = ekEventStore?.predicateForEvents(withStartDate: now, endDate: endDate, calendars: nil)
    // Loop through all events in range
    ekEventStore?.enumerateEvents(matchingPredicate: predicate, usingBlock: {(_ ekEvent: EKEvent, _ stop: Bool) -> Void in
        // Check this event against each ekObjectID in notification
        (ekEventStoreChangedObjectIDArray as NSArray).enumerateObjects(usingBlock: {(_ ekEventStoreChangedObjectID: String, _ idx: Int, _ stop: Bool) -> Void in
            let ekObjectID: NSObject? = (ekEvent as? NSManagedObject)?.objectID
            if ekEventStoreChangedObjectID.isEqual(ekObjectID) {
                // EKEvent object is the object which is changed.
                stop = true
            }
        })
    })
}

Поэтому всякий раз, когда есть какие-либо изменения в событии (добавление/обновление/удаление), мы можем получать обновления.

Кроме того, при создании любого события вы получаете eventIdentifier из EKEvent объекта.

let eventStore : EKEventStore = EKEventStore()
eventStore.requestAccess(to: .event) { (granted, error) in

    if (granted) && (error == nil) {
        print("granted \(granted)")
        print("error \(error)")

        let event:EKEvent = EKEvent(eventStore: eventStore)

        event.title = "Event"
        event.startDate = Date()
        event.endDate = Date()
        event.calendar = eventStore.defaultCalendarForNewEvents
        do {
            try eventStore.save(event, span: .thisEvent)
        } catch let error as NSError {
            print("failed to save event with error : \(error)")
        }
        print("Saved Event id : \(event.eventIdentifier)")
    }
    else{

        print("failed to save event with error : \(error) or access not granted")
    }
}

И получите событие, используя следующий метод.

let event:EKEvent = eventStore?.event(withIdentifier: eventIdentifier)

Пожалуйста, дайте мне знать, если вам нужно больше разъяснений.

Ответ 5

Нет, в данный момент нет возможности создать профессиональную и функциональную фоновую задачу для календаря iOS (версия Apple Swift 3.1).

Состояние фона iOS очень ограничено (есть много причин, чтобы сохранить время автономной работы и т.д.), а "текущий режим календаря" еще не существует в настоящий момент (вы можете взгляните на официальный Фоновые режимы для приложений, доступные официальным документам Apple, Таблица 3-1). Всегда предлагайте мобильное устройство со всеми физическими ограничениями, а не с Linux-сервером, но для календаря нам тоже не повезло.

Другими словами система не передает новые изменения календаря в фоновом состоянии в ваше приложение, и вы никогда не получите надежное напоминание с использованием официального календаря приложений iOS.

Вы можете сделать фоновое задание, используя EKEventStoreChanged, но что произойдет, когда ваше приложение находится в "приостановленном состоянии"? Вы всегда проходите через фоновое состояние, чтобы говорить с вашим приложением, и, как видите, нет вариантов для внесения изменений в календари.

Нельзя также создать собственное приложение для календаря (поэтому без использования официального приложения для календаря), потому что вы всегда должны сопровождать фоновое состояние на внешний сервер (удаленные уведомления могут быть идеей..): предположим, что у вас нет связи/интернет, поэтому ваше push-уведомление прибывает позже. В этом случае ваше напоминание не знает, что у вас назначена конкретная встреча за это время, и вас могут предупредить слишком поздно, и это может означать полное бедствие.