Работа в фоне iOS приложения

Данная статья является вольным переводом из официальной документации. В случае каких то неясностей прошу обратиться к первоисточнику: App Programming Guide for iOS

Когда пользователь не активно пользуется вашим приложением, система перемещает его в состояние background. Для многих приложений, это состояние просто короткая остановка на пути к полному выключению suspended. Приложения в состоянии suspended сохраняют зарят батарей и позволяют системе освободить важные для системы ресурсы для новый приложений требуемых внимания пользователя.

Большинство приложений может быть перенесено в “растянутое” состояние достаточно просто, но есть так же законные основания для продолжения работы в фоновом режиме. Туристическое приложение, возможно, захочет отслеживать позицию человека в течении долгого времени, так что оно может отображать курс накладывая его поверх туристической карты. Музыкальное приложение может нужнаться в продолжении проигрывания музыки даже при блокировке экрана. Другие приложения могут хотеть скачивать данные в фоне, чтобы минимизировать задержку в отображении данных пользователю. Когда вам понадобиться держать ваше приложение запущенным в фоне, iOS поможет вам эффективно сделать это и без “съедания” ресурсов системы и аккумулятора. Методы предлагаемые iOS деляться на три категории:

  • Приложения, которые запускают короткую задачу на переднем планы чтобы запросить время до завершения этой задачи в фоне.
  • Приложения, которые инициируют скачавние на переднем плане могут передавать управление этих загрузок системе, тем самым позволяя приложенияю быть приостановленым или завершенным в то время когда загрузка продолжится.
  • Приложение, которые должны работать в фоне, чтобы поддерживать определнные типы задачь могут объявить о этой поддержке в одном или нескольких режимах фоновых режимах.

Всегда пытайтеть избегать делать какую либо фоновую работу если это не улучшает UX. Приложение может быть перемещено в фон, потому что пользователь запустил другое приложение или потому что пользователь заблокировал устройство и не использовать его в данный моментю В основных ситуациях, пользователь оповещает ваше приложение о том, что не нужно выполнять какую либо работу сейчас. Продолжая работать в таких случаях ваше приложение будеть только разряжать аккумулятор устройства и может вынудить пользователя бросить пользоваться им в целом. Так помня о работе которую вы делаете в фоновом режиме, старайтесь ее избегать когда это возможно.

Запуск задач известной длины

Приложения перемещенные в фон, как ожидается, должны выйти из этого состояния как можно быстрее, так как они могут быть остановлены системой. Если ваше приложение находиться в середине задачи и вам нужно немного дополнительного времени для ее завершения, то вы можете вызвать методы beginBackgroundTaskWithName:expirationHandler: или beginBackgroundTaskWithExpirationHandler:](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instm/UIApplication/beginBackgroundTaskWithExpirationHandler:) объекта UIApplication запросив дополнительное время. Вызов любого из этих методов отстрочит ненадолго закрытие вашего приложения, дав немного дополнительного времени для завершения работы. После завершения этой работы ваше приложение должно вызвать метод endBackgroundTask: дав системе понять, что задача завершена и приложение может быть закрыто.

Каждый вызов методов beginBackgroundTaskWithName:expirationHandler: или beginBackgroundTaskWithExpirationHandler: генерирует уникальный токен для каждой задачи. Когда приложение завершит задачу, он должен вызвать метод endBackgroundTask: с соответствующим токеном дав системе понять, что именно эта задача была завершена. Отказ от вызова этого метода для фоновой задачи приведет к прекращению работы вашего приложения. Если вы предоставили обработчик когда запускали задачу, система вызовет этот обработчик дав вам последний шанс на то, чтобы закончить задачу и избежать выключения.

У вас нет необходимости ждать пока приложение будет перенесено в состояние фоновой работы для обозначения фоновых задач. Более полезным методом разработки является вызов beginBackgroundTaskWithName:expirationHandler:  или  beginBackgroundTaskWithExpirationHandler: до запуска задачи и вызов метода endBackgroundTask: после завершения. Вы можете следить за этим паттерном пока ваше приложение работает на переднем плане.

Листинг 3-1 показывает как можно запустить долго-работающую задачу когда ваше приложение перемещено в фон. В этом примере, происходит запрос к фоновой задаче включая обработчик в случае если задача выполняется слишком долго. Сама задача ставится в очереднь для асинхронного запуска, так что метод applicationDidEnterBackground: может вернутся нормально. Используйте упрощающие блоки кода необходимые для поддержания ссылок на любые важные перменные, таких как идентификатор фоновой задачи. bgTask это переменная класса хранящая ссылку на данную фоновую задачу и инициализируемая в этом методе.

Листинг 3-1 Запуск фоновой задачи в момент выхода

- (void)applicationDidEnterBackground:(UIApplication *)application
{
  bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
      // Clean up any unfinished task business by marking where you
      // stopped or ending the task outright.
      [application endBackgroundTask:bgTask];
      bgTask = UIBackgroundTaskInvalid;
  }];
  // Start the long-running task and return immediately.
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // Do the work associated with the task, preferably in chunks.
      [application endBackgroundTask:bgTask];
      bgTask = UIBackgroundTaskInvalid;
  });
}

Обратите внимание: Всегда предоставляйте перехватчик завершения во время запуска задачи, но если вы хотите знать как много времени займет ваша задача от запуск, возьмите значение поля backgroundTimeRemaining из UIApplication.

В ваших собственных обработчиков завершения, вы можете вставить дополнительный код чтобы закрыть вашу задачу. Тем не менее, любой код вставленый там не должен выполняться слишком долго, потому что как только обработчик вызывается у вас остается не так много времени до завершения работы приложения. По этой причине, выполните лишь минимальную очистку вашего состояния и завершите задачу.

Загрузка данных в фоне

Когда загружаются данные, приложения должны использовать объект NSURLSession для запуска загрузки, так система сможет взять управление процессом загрузки на себя в случае если приложение было выключено. Когда вы настраиваете этот объект для передачи в фоне, система управляет этой передачей в отдельном процессе и оповещает о статусе работы вашему приложениею в обычном случае. Если ваше приложение было выключено, пока продолжалась передача, система продолжит передачу в фоне и запустить ваше приложение (если это уместно) когда передача завершится или одна или более задач требует внимания вашего приложения.

Для поддержки фоновых передач, вы должны настроить ваш объект. Настраивая сессию, вы должны сначала создать объект NSURLSessionConfiguration и выбрать несколько настроек. Вы отправляете конфигурацию в объект в момент инициализации объекта NSURLSession.

Процесс создания объекта конфигурации, который поддерживает фоновые загрузки выглядит следующим образом:

  1. Создание объекта конфигурации используя метод backgroundSessionConfigurationWithIdentifier: объекта NSURLSessionConfiguration.
  2. Выбрать значение sessionSendsLaunchEvents объекта конфигурации в YES.
  3. Если ваше приложение начинает передачу на переднем плане, советуется выбрать значение discretionary в YES.
  4. Настройте любые другие свойства объекта конфигурации в зависимости от обстоятельств.
  5. Используйте объект конфигурации чтобы создать объект NSURLSession.

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

Когда все задачи происходящие в фоновой сесси были завершены, система перезапускает выключеное приложение (предпологается, что свойство sessionSendsLaunchEvents установлено в YES и пользователь не завершил работу приложения самостоятельно) и вызывает приложение с помощью метода application:handleEventsForBackgroundURLSession:completionHandler:. (Система может также перезапустить приложение для выполнения задач аутентификкации и других событий, связанные с вниманием вашего приложения.) В вашем приложении реализация этого метода, происходит с созданием нового NSURLSessionConfiguration и NSURLSession объекта с похожей конфигурацией что и ранее. Система переподключает ваши новый объект сессии на предыдущие задачи и оповещает об их статусе в новый объект сессии.

Реализация долго-работающих задач

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

  • Приложения играющие аудио данные пользователю в фоне, такие как приложения музыкальных плееров
  • Приложения записывающие звук пока находяться в фоне
  • Приложения информирующие пользователя о его локации все время, такие как приложения навигации
  • Приложения поддерживающих VoIP
  • Приложения нуждающиеся в загрзки новых данных регулярно
  • Приложения принимающие постоянное обновления от внешних аксессуаров

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

Объявление ваших фоновых задач

Поддержка некоторых типов фоновых работ должна быть объявлена в вашим приложении. В Xcode 5 и позних версиях, вы объявляете о поддержке фоновой работы во вкладке Capabilities в насройках проекта. Включание опции фонового режима добавляеет ключ UIBackgroundModes в вашем файле Info.plist. Выберете один или более чекбоксов добавив необходимые опции фоновой работы. Таблица 3-1 описывает фоновые режимы которые вы можете выбрать в Xcode.

Таблица 3-1 Фоновые режимы приложения.

Xcode фоновой режим

UIBackgroundModes значение

Описание

Аудио и AirPlay

audio

Приложение играет аудио данные пользователя или записывает данные в фоне. (Эти данные включают потокове аудио или видео данные используя AirPlay.)

Пользователь должен разрешить приложению использовать пикрафон во время первого использвания; для большей информации читайте Supporting User Privacy.

Обновление локации

location

Приложение информирует пользователя о его положении пока находиться в фоне

IP-телефония

voip

Приложение позволяет пользователю совершать звонки через интернет.

Загрзки Newsstand

newsstand-content

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

Общение с внешними аксессуарами

external-accessory

Приложение работает с аппаратными аксессуарами необходимых в обновлении по расписанию через фреймворк External Accessor.

Использование Bluetooth LE аксессуаров

bluetooth-central

Приложение работает с Bluetooth аксессуарами необходимые в обновлении по расписанию через фреймворк Core Bluetooth.

Дейтвия с Bluetooth LE аксессуарами

bluetooth-peripheral

Приложние поддерживает общение через Bluetooth в режиме переферии через фреймворк Core Bluetooth.

Этот режим используется для запросов пользовательской аутонтификации; для большей информации читайте Supporting User Privacy.

Фоновые приемы

fetch

Приложение регулярно загружает и обрабатывает маленькие размеры информации из интернета.

Удаленные уведомления

remote-notification

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

Каждый из объявленных методов дает системе знать, что ваше приложение должно быть пробуждено или запущено в нужное время чтобы ответить на пришедшие события. Например, приложение начало играть музыку и переходить в фон все еще продолжать работу заполняя выходные буферы аудио. Включение режима Audio говорит системному фреймворку, что он должен принимать callback функции приложения с соответствующими интервалы. Если приложение не выбрало этот режим, любое аудио начавшее играть или записывать будет завершено, когда приложение перейдет в фоновой режим.

Трекинг локации

Есть несколько путей для трекинга локации пользователя в фоне, большинтво из которых на самом деле не требуют неприрывной работы вашего приложения в фоновом режиме:

  • Серсис значительного изменения положения (Рекомендуется)
  • Сервис локации только на переднем плане
  • Сервис локации в фоне

Сервис значительного изменения положения наиболее рекомендуется для приложений которым не нужно высокоточные данные о положении. С этим сервисом, изменения локации генерируются только когда местоположение пользователя существенно изменится; Таким образом это идеально для социальных приложений или приложений, что предостовляют пользователю уведомления полезные для данной местности. Если ваше приложение выключено, когда произошло жто события, система пробутит его в фон чтобы передать изменившееся состояние. Если приложение запустило этот  сервис и было выключено, система перезапустит приложение автоматически, когда придут новые данные о локации. Этот сервис доступен с 4-й версии iOS, и она доступна только на устройствах содержащих модули сотовой связи.

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

Вы включаете поддержку локации из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение location в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Включение этого режима не спасут приложение от возможности быть выключеными, но это говорит системе, что приложение должно быть пробуждено для того чтобы принять новые данные о локации. Таким образом, этот ключ позволяет приложению запускаться в фоне для обработки обновленных данных локации, когда они приходят.

Важно: Вам предлогается использовать стандартные сервисы экономно и использовать сервис значительного изменения локации. Службы локации требуют активного использования радиоаппаратуры iOS устройства. Запуск этого оборудования может непрерывно потреблять значительное количество энергии. Если ваше приложение не нуждается в точном предосталвении положения и непрерывного оповещения, предлогается свести это использование к минимуму.

Для информаии о том как использовать различные сервисы локации обратитесь к Location and Maps Programming Guide.

Проигрывание и Запись звука в фоне

Приложение проигрывающее или записывающее аудио продолжительно (когда приложение запущено или находиться в фоне) может регистрировать эти задачи для выполенения в фоне. Вы можете включить поддержку аудио из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение audio в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Приложение, что играет аудиоданные в фоне должны играть играть звуковой контент, а не тишину.

Обычными примерами приложений играющих в фоне является:

  • Приложения музыкальных плееров
  • Звукозаписывающие приложения
  • Приложения поддерживающих аудио или видио проигрывание через AirPlay
  • Приложения IP-телефонии

Когда в ключе UIBackgroundModes выбрано значение audio, системный медиа фреймворк атоматически предотвращает закрытие приложения когда оно находится в фоновом режиме. Пока он играет аудио или видео контент или записывает звук, приложение будет запущено в фоне. Тем не менее, если запись или проигрывание остановиться, система выключит приложение.

Вы можете использовать любой из системных аудио фреймоврков для работы со звуком в фоне, и обрабатывать для использования в рамках фреймворка. (Для видео проигрывания через AirPlay, вы можете использовать Media Player  или фреймворк AV Foundation для отображения видео.) Поскольку ваше приложение не может быть приостановлено пока играют медиафайлы, обратная связь работает нормально пока ваше приложение находиться в фоновом режиме. В вашей обратной связи вы должны выполнять работу только два управлением проигрывания. Например, приложение для потокового аудио должно качать данные о музыкальном потоке с сервера и помещать верные куски аудио в воспроизведенеи. Приложение не должны выполнять какие либо посторонние задачи, которые не связаны с воспроизведением.

Потому что более чем одно приложение может поддерживать аудио, система определяет, каким приложениям разрешено играть или записывать аудио в любой момент. Приложение на переднем плане всегда имеет наивысший преоритет для аудио операций. Вполне возможно, что более чем одно фоновое приложение может быть доступно к проиграванию аудио и такие определения основаны на конфигурации каждого объекта аудио сессии приложения. Вы всегда должны конфигурировать ваш объект аудио сессии нашлежащим образом и работать осторожно с фреймворком системы для обработки прерываний и других типов уведомлений связанные с аудио. Для большей информации о конфигурации объекта аудио сессий для работы в фоне читайте в Audio Session Programming Guide.

Реализация приложения с IP-телефонией

Приложение VoIP позволяет пользователю совершать телефонные звоки посредством интернет подключения через сотовую службу устройства. Такое приложение должно постоянно поддерживать интернет соединение с соответсвующей службой так что он может принимать входящие выховы и другие соответствующие данные. Вместо того, чтобы держать VoIP приложение запущеным все время, система позволяет ему быть приостановленным и предоставлять средства для мониторинга сокета для него. Когда взодящий трафик будет определен, система “разбудит” VoIP приложение и вернет ему контроль на сокетом.

Чтобы настроить VoIP приложение, вы должны сделать следующее:

  • Включить поддержку Voice over IP из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение voip в ключ UIBackgroundModes в файле Info.plist вашего приложения.)
  • Настроить один сокет приложения для использования VoIP.
  • До перехова в фоновом режим, вызвать метод setKeepAliveTimeout:handler: для установки обработчика который будет выполняться переодически. Ваше прилжение может использовать его для того чтобы поддерживать связь с сервером.
  • Настроте аудио сессю для обработки передачи к и от активного использования.

Содержание значения voip в ключе UIBackgroundModes дает системе знать, что вашему приложению позволена работа в фоне и необходима работа с сетевыми сокетами. Приложение с этим ключем также перезапускается в фон немедленно после загрузки системы, что позволяет быть сервисам VoIP быть все время доступными.

Большинство приложений VoIP должны быть сконфигурированы как аудио приложение. Теким образом вы должны включить оба значения audio и voip в ключ UIBackgroundModes. Если вы не сделали это, ваше приложение не сможет играть и записывать звук в фоне. Для большей информации о ключе UIBackgroundModes, читайте Information Property List Key Reference.

Для более расширеной информации о шагах реализации VoIP приложения, читайте в Tips for Developing a VoIP App.

Полчение малых количеств данных

Приложения, которые должны иногда проверять о содержании новых данных, могут просить систему переодически буить их для инициирования получения этих данных. Поддержка этого режима включается из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение fetch в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Включение этого режима не гарантирует, что система даст вашему приложению время чтобы получить данные в фоне. Система должна балансировать нужды приложений в получении контента и системы. После оценки этой информации, система дает время приложению, когда на это есть возможность.

Когда возникает хорошая возможность, ситема пробуждает или запускает ваше приложение из фона и вызывает объявленый метод application:performFetchWithCompletionHandler:. Используйте этот метод чтобы проверить о присутствии новых данных и инициирования операции загрузки контента. Как вы только закончите загрузку новых данных, вы должны вызвать предоставленый обработчик, передавая результат, говоря о том, что данные были приняты. выполнение этого блока говорит системе о том, что он может переместить ваше приложение обратно в приостановленое состояяние и оценить это энергопотребление. Приложение, которогое скачивает малые куски данных быстро и точно отвечает когда они были загружены, скорее всего получит время для выполения в будущем, чем те приложения которые занимают много времени, чтобы загрузить содержимое или получают проблемы с доступом и не загружают ничего.

При загрузке любых данных, рекомендуется использовать класс NSURLSession для инициализации и управлением вашими загрузками. Для большей информации о том, как использовать класс управления задачами выгрузки и загрузки, смотрите URL Loading System Programming Guide.

Использование push-уведомлений для запуска загрузки.

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

Поддержка этого режима включается из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение remote-notification в ключ UIBackgroundModes в файле Info.plist вашего приложения.)

Чтобы включить операцию загрузки для push-уведомлений, уведомление должно содержать значение 1 в ключе content-available. Кгда ключ предосталвен, система “будит” приложение для работы в фоне (или запускает в фон) и вызывает объявленный метод application:didReceiveRemoteNotification:fetchCompletionHandler:. Ваша реализация этого метода должна загружать удаленные данные и интегрировать их в приложение.

При загрузке любых данных, рекомендуется использовать класс NSURLSession для инициализации и управлением вашими загрузками. Для большей информации о том, как использовать класс управления задачами выгрузки и загрузки, смотрите URL Loading System Programming Guide.

Загрузка данных Newsstand в фоне

Приложение Newsstand, которое загружает новый журнал или газету может зарегестрировать загрузку в фоне. Поддержка этого режима включается из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение newsstand-content в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Когда этот ключ предоставлен, система запускает ваше приложение, если оно все еще не запущено, чтобы запустить загрузку нового выпуска.

Когда вы используйте Newsstand Kit для старта скачивания, система принимает процесс загрузки на себя для вашего приложения. Система продолжить процесс загруски когда ваше приложение будет приостановлено или выключено. Когда процесс загрузки завершится, система передаст файл в sandbox приложения и оповестит ваше приложение. Если ваше приложение не запущено, это уведомление “разбудит” его и даст шанс обработать свежескаченный файл. Если произойдут какие либо ошибки в процессе загрузки, ваше приложение будет запущено для их обработки.

Для большей информации о том как использовать загруку данных с помощью фрейворка  Newsstand Kit, читайте NewsstandKit Framework Reference.

Общение с внешними аксессуарами

Приложения работающие вс внешнему аксессуарами могут запросить свое “пробужение” если аксессуар поддерживает обновление, когда приложение приостановлено. Эта поддержка важна для некоторых типов аксессуаров, что обеспечивает данными через постоянные интервалы, такие как мониторы сердечного ритма. Поддержка этого режима включается из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение external-accessory в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Когда этот режим включен, фреймворк внешних аксессуаров не закрывает активные сессии с аксессуаром. (В iOS 4 и ранее, эти сессии закрываются автоматически если приложение было приостановлено.) Когда новые данные приходят из аксессуара, фремворк открывает ваше приложение чтобы оно обработало полученые данные. Система так же может “пробудить” ваше приложение для обработки подключения и отключения аксессуара.

Любое приложение, поддерживающее фоновую обработку обновлений аксессуара должны следовать нескольким основным указаниям:

  • Приложение должно предосталять интерфейс, позволяющий пользователям запустить и остановить получение данных с устройства. Интерфейс должен открывать и закрывать сессию с аксессуаром.
  • После пробуждения, у приложения есть порядка 10 секунд, чтобы обработать данные. В идеале оно должно обрабатывать данные как можно быстрее и позволить приостановить себя снова. Тем не менее, если нужно больше времени, приложение может использовать метод beginBackgroundTaskWithExpirationHandler: запрашивающий дополнительное время, делать это надо только в самых необходимых случаях.
Общение с Bluetooth акусессуарами

Приложения которые работают с Bluetooth переферии могут запросить “пробудить” себя если переферия поставит обновления когда ваше приложение приостановлено. Эта поддержка важна для Bluetooth-LE  аксессурах, которые постовляет данные через постоянные промежутки времени, такие как Bluetooth мониторы сердцебиения. Поддержка этого режима включается из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение bluetooth-central в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Когда вы включите этот режим, фрейворк Core Bluetooth будет оставлять активной сессию для общения с переферией. Ко всему прочему, новые данные пришедшие из переферии вынудят систему запустить ваше приложение в фоновом режиме для обработки принимаемых данных. Система так же “разбудит” ваше приложение для обработки ситуаций подключения и отключения аксессуара.

В iOS 6 приложение также может работать в переферийном режиме с Bluetooth аксессуарами. Поддержка этого режима включается из раздела Background modes во вкладке Capabilities вашего проекта Xcode. (Вы также можете включить поддержку вставив значение bluetooth-peripheral в ключ UIBackgroundModes в файле Info.plist вашего приложения.) Включение этого режима заставит фремворк Core Bluetooth “пробуждать” ваше приложение в фоне, чтобы обработать принимаемые запросы. Приложение включаемое для этих событий должно обработать данные как можно быстрее и вернуться в в приостановленное состояние опять.

Любое приложение, поддерживающее фоновую обработку обновлений Bluetooth аксессуара должны следовать нескольким основным указаниям:

  • Приложение должно предосталять интерфейс, позволяющий пользователям запустить и остановить получение данных с Bluetooth устройства. Интерфейс должен открывать и закрывать сессию с аксессуаром.
  • После пробуждения, у приложения есть порядка 10 секунд, чтобы обработать данные. В идеале оно должно обрабатывать данные как можно быстрее и позволить приостановить себя снова. Тем не менее, если нужно больше времени, приложение может использовать метод beginBackgroundTaskWithExpirationHandler: запрашивающий дополнительное время, делать это надо только в самых необходимых случаях.
Привелечение внимания пользователя из фонового режима

Уведомления это вариант для приложения, находящимся в приостановленом состояни, фоновом или выключеным, привлечь внимание пользователя. Приложение может использовать локальный уведомления для всполывающих окон, играния звуков, бейдеж на иконке приложения или комбинации всех. Например, приложение будильника может использовать локальные уведомления для проигрывания звонка будильника и отображать всплывающее окно для выключения будильника. Когда уведомление досталвено мользователю, пользователь может вернуть приложение на передний план. (Если приложение уже запущено в переднем плане, локальные уведомления доставляются тихо приложению, а не пользователю.)

Расписание может отправлять локальные уведомления, создав объект класса UILocalNotification, настроить параметры уведомления и запланировать его используя методы класса UIApplication. Объект локального уведомления содержит информацию о типе уведомления (звук, окно или бейдж) и времени (когда совершить). Методы класса UIApplication предоставляют опцию для поставки уведомления немедленно или в определенное время.

Листинг 3-2 показывает пример который планирует единичный будильник используя дату и время указанную пользователем. Этот пример настраивает только один будильник на время и отменяет его после создания нового будильника. (Ваше собственное приложение может создать не более 128 уведомлений в любое время, любое может быть настроено и повторяться с определенным интервалом.) Бульник содержит окно уведомления и звуковой файл, что играет если приложение не запущено или находиться в фоне. Если приложение активно и запущено в переднем плане, приложение объявляет метод application:didReceiveLocalNotification: вызываемым внутри.

Листинг 3-2 Планирование уведомления будильника


- (void)scheduleAlarmForDate:(NSDate*)theDate
{
  UIApplication* app = [UIApplication sharedApplication];
  NSArray*    oldNotifications = [app scheduledLocalNotifications];
  // Clear out the old notification before scheduling a new one.
  if ([oldNotifications count] > 0)
      [app cancelAllLocalNotifications];
  // Create a new notification.
  UILocalNotification* alarm = [[UILocalNotification alloc] init];
  if (alarm)
  {
      alarm.fireDate = theDate;
      alarm.timeZone = [NSTimeZone defaultTimeZone];
      alarm.repeatInterval = 0;
      alarm.soundName = @"alarmsound.caf";
      alarm.alertBody = @"Time to wake up!";
      [app scheduleLocalNotification:alarm];
  }
}

Звуковой файл используется с локальными уведомления имеет такие же требования, что и push-уведомления. Пользовательские звукове файлы должны находиться в основном пакете приложения и поддерживать один из следующих фарматов: Linear PCM, MA4, µ-Law, или a-Law. Вы можете так же определеить костанта UILocalNotificationDefaultSoundName для проигрывание указанных пользователем звука уведомления на устройстве. Когда уведомление отправлено и играет звук, система может включить вибрацию на устройстве, если оно ее поддерживает.

Вы можете отменить запланированное уведомление или получить списко уведомлений используя методы класса UIApplication. Для большей информации о этих методах, смотрите UIApplication Class Reference. Для большей информации о конфигурации локальных уведомлений, смотрите Local and Remote Notification Programming Guide.

Когда ваше приложение будет запущено фоне

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

Для навигационных приложений:

  • Система приняла новые данные о локации, встречается когда приложение соответсвующим образом
  • Усройстов вошло или вышло из зарегестрированного региона. (Регионы могут быть географическими регионами или регионами iBeacon)
  • Для аудиоприложений, фреймворк аудио нуждается в обработке некоторых данных приложением. (Аудиоприложение содержит то, что играет аудио или использует микрофон)

Для Bluetooth приложений:

  • Приложения играющие роль центрального приемника данных с подключенной переферии.
  • Приложения игращего роль переферии и получающего команды с подключенного центрального устройства.

Для приложений качающих данные в фоне:

  • Push-уведомления прибывшие приложения и данные уведомления содержат ключ content-available со значением 1.
  • Система “пробуждает” приложение в моменты когда начинается загрузка новых данных.
  • Для приложений качающих данные в фоне с использованием класса NSURLSession, все задачи связанные с этим объектом сессии либо при успешном завершении, либо при ошибке
  • Загрузка запущеная Newsstand приложением.

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

Будте ответственны с фоновыми приложениями.

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

  • Не делайте какие либо OpenGL ES запросы из вашего кода. Нельзя создавать объект EAGLContext или вызывать команды рисования OpenGL ES в любом вифе работы в фоне. Использование этих вызывов приведет к выключению вашего приложения немедленно. Приложение должно также обеспечить, чтобы все ранее представлвеные команды завершились до перехода в фоновой режим. Для получения большей информации, смотрите Implementing a Multitasking-aware OpenGL ES Application в OpenGL ES Programming Guide for iOS.
  • Отменяйте любые Bonjour-сервисы перед приостановкой. Когда ваше приложение перемещено в фон, и познее останавливается, вы должны отменить регистрацию в Bonjour и закрыть прослушивание сокетов связанных с каким либо сетевым сервисом. Приостановленное приложение не может отвечать на входящие запросы в любом случае. Закрытие этих сервисов позвляет им быть доступными, когда на самом деле это не так. Если вы не закроете сервисы Bonjour самостоятельно, система закроет эти сервисы автоматически, когда ваше приложение будет приостановлено.
  • Будте готовы получать ошибки соединений в ваших сетевых сокетах. Система может выключать сокет соединения, когда ваше приложение было приостановлено по некоторым причинам. Пока код основанный на сокетах готов для всех типов ошибок сети, таких как потеря сигнала или сетевой передачи, это не должно привести к каким либо проблемам. Когда ваше приложение возвращается, если оно сталкнется с ошибкой при использовании сокета, то ему будет довольно просто восстановить соединение.
  • Сохраняйте состояние вашего приложение прежде чем перейти в фон. При нехватке памяти, фоновое приложение может быть удалено из памяти для освобождения места. Приостановленные приложения удаляются первым, и не оповещают об этом приложение. Как результат, приложени должны воспользоваться инструментом сохранения состояния в iOS 6 и познее, чтобы сохранить состояние интерфейса на диск. ДЛя информации о поддержки этой функции, смотрите Preserving Your App’s Visual Appearance Across Launches.
  • Удаляйте жесткие ссылки на ненужные объекты при перемещении в фон. Если ваше приложение занимает много места в кеше объектов (например картинок), удалите все жесткие ссылки на эти объекты перед перемещением в фон. Для большей информации, смотрите Reduce Your Memory Footprint.
  • Останавливаетй использование общих ресурсов системы перед приостановкой. Приложения, которые взаимодействуют с общими ресурсами системы, таких как Адресная Книга или база данных Календаря должны остановить это использование перед приостановкой. Приоритет для таких ресрсов всегда предосталвяется приложениям на переднем плане. Когда ваше приложение приостановлено и будет использовать общие ресурсы, то оно будет выключено.
  • Избегайте обновления ваших окон и Views. Потому что окна и view вашего приложения не видны, когда ваше приложение находится в фоне, вы должны избегать их обновления. Исключением являются те случаи, когда вам нужно обновить данные в окне прежде чем совершится снимок вашего приложения.
  • Отвечайте уведомления о подключении и выключении от внешних аксессуаров. Для приложений, которые общаются с внешними аксессуарами, система автоматически отправляет уведомления отключения, когда сообщение перемещено в фон. Приложение должно регистрировать эти уведомления и использовать это для закрытия сессии аксессуара. Когда приложение перемещается из фона в передний план, соответствующее уведомление подключения отправляется, давая приложению возможность воссоздать подключение. Для получения большей информации, смотрите External Accessory Programming Topics.
  • Очищайте ресурсы для активных алертов при переходе в фон. Для того чтобы сохранять контекст при переключении между приложениями, система не освобождает автоматически списки action (UIActionSheet) или view алертов (UIAlertView), когда ваше приложение пермещено в фон. Например, вы можете отменить список action или view алертов программно или сохранить информацию достаточную чтобы восстановить view позже (В случае когда ваше приложение было выключено).
  • Удаляйте конфеденциальную информацию из view прежде чем перейти в фон. Когда приложение перемещено в фон, система может сделать снимок окна приложения, которое представляется короткое время при переходе в ваше приложение обратно. Перед возвращаением из вашего applicationDidEnterBackground: метода, вы должны скрыть или “замылить” пароли и другую персональную информацию которая может быть захвачена с помощью снимка.
  • Делайте минимальную работаю пока работаете в фоне. Время выполнения предостовляемое в фоне более длительное чем время выполнения на переднем плане. Приложения выполняющиее слишком долгую работу в фоне могут быть отключены системой.

Если вы реализовываете аудио приложение или любое другой тип приложения, которому разрешено запускататься в фоне, ваше приложение отвечает на пришедшие запросы в обчном порядке. Другими словами, система может уведомить ваше приложение о недостатке памяти, когда они происходят. И в ситуации, когда сисема должна выключить приложение и сонободить еще больше памяти,  приложение вызывает объявленный метод applicationWillTerminate: чтобы выполнить какую либо финальную работу перед выключением.

Отказ от работы в фоне

Если вы не хотите запускать ваше приложение в фоне, то можете добавить ключ UIApplicationExitsOnSuspend (со значением YES) в вашем файле Info.plist. Когда приложение работает в этом режиме, то его циклы not-running, inactive, и active состояния никогда не попадают в состояния фона или приостановки. Когда пользователь нажимает на кнопку Home, приложение выключается. вызывая метод applicationWillTerminate: объявленный в вашем приложении давая примерно 5 секунд на очистку и выход, прежде чем завершится и перевестись в состояние not-running.

Опция отказа от работы в фоне может быть предпочтителен в некоторых условиях. В частности, если работа в фоне значительно усложняет ваше приложение. Кроме того, если ваше приложение потребляет большие объемы памяти и не может легко освободить ее, то система убьет ваше приложение быстро в любом случае, чтобы освободить место для других приложений. Таким образом может пренести пользу, чтобы сохранить время разработки.

Для большей информации о ключах содержащихся в файле Info.plist, читайте Information Property List Key Reference.