Background Modes в iOS: обзор основных модов

от автора

Привет! Я Никита Пешков, iOS-разработчик в Effective. В этой статье я буду говорить об основных модах Background в iOS, но прежде напомню базу. Работа в Background – один из этапов жизненного цикла приложения, представляющего собой в iOS следующую структуру:

Снимок экрана 2024-12-24 в 15.04.24.png

Когда пользователь сворачивает приложение или блокирует экран, система переводит приложение в фоновое состояние. Если приложение не имеет background-состояния, то фоновое состояние оказывается только короткой остановкой на пути к приостановке приложения, когда оперативная память ещё не освобождена, но код уже не выполняется.

Apple разрешила приложениям работать в Background вместе с релизом iOS 4. Cуществует 11 режимов фонового выполнения, которые может поддерживать приложение:

Audio, AirPlay, and Picture in Picture

Этот режим позволяет воспроизводить аудио, делиться видео через AirPlay и воспроизводить их в режиме Picture in picture в фоне. Для воспроизведения аудио и видео в нативном контроллере писать дополнительный код не нужно: эти функции будут работать из коробки.

Снимок экрана 2024-12-16 в 12.46.37.png

Location Updates

Для отслеживания геолокации в iOS нужно предоставить разрешение для приложения. В момент такого запроса отображаются системные окна с текстом, указанным в info plist. Существует два типа разрешений – While in use и Always.

Авторизация While in use позволяет отслеживать геопозицию в Foreground и Background, когда включён индикатор её отслеживания. Приложение может использовать все службы определения местоположения и получать события, даже если пользователь не знает, что приложение запущено. Если приложение не запущено, система запустит его и доставит событие.

Если у приложения есть Always-авторизация, то через некоторое время на его главном экране высветится дополнительный алерт, в котором пользователю предложат переключиться на авторизацию While in use. Об этом необходимо помнить, чтобы ваше приложение внезапно не лишилось необходимой авторизации.

Запросить разрешение на геолокацию можно с помощью такого кода:

private func checkAuthorization() {         switch self.locationManager.authorizationStatus {         case .notDetermined:             self.locationManager.requestWhenInUseAuthorization()             self.locationManager.requestAlwaysAuthorization()         case .restricted:             break         case .denied:             break         case .authorizedAlways:             self.locationManager.startUpdatingLocation()         case .authorizedWhenInUse:             self.locationManager.requestAlwaysAuthorization()             self.locationManager.startUpdatingLocation()         @unknown default:             break         }     } 

Метод для обработки геолокации:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {    if let currentLocation = locations.first {     print(currentLocation)     location = currentLocation     appendPin(location: currentLocation)     updateRegion(location: currentLocation)   } }

Background fetch и Background processing

Background fetch нужен для обновления данных приложения, когда им не пользуются. Время его запуска полностью зависит от системы. На него влияет:

  • Критический низкий заряд батареи: если заряда < 20%, то фоновое выполнение будет приостановлено системой;

  • Режим низкого энергопотребления;

  • Включённая функция фонового обновления приложения;

  • Возможность запускать фоновые задачи есть только у приложений, отражаемых в app switcher;

  • Системные ограничение расхода батареи и времени выполнения для Background-задач;

  • Быстрое выполнение тасков: чем быстрее они выполняются, тем выше шанс на запуск.

C выходом iOS 13 Apple изменила механизм планирования фоновых задач. Система анализирует, как часто и когда пользователь запускает приложение, и планирует выполнение Background Fetch задач так, чтобы при запуске в приложении были свежие данные.

Также они ввели два вида задач: Background App Refresh Tasks для небольших задач (выполняется максимум 30 с) и Background Processing Tasks (выполняется дольше и только когда устройство не используется. Точная длительность неизвестна) для остальных. Для выполнения первых включается режим Background fetch, для вторых – Background processing.

Протестировать такие таски можно только на реальном устройстве, поставив приложение на паузу и прописав в консоль команду:

e -1 objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"TASK_ID"] 

Voice over IP

Опция позволяет принимать VOIP-звонки в фоне с помощью специальных push-уведомлений c типом VoIP.

При получении такого пуша приложение запускается в Background, подключается к службе связи и показывает UI из Callkit.

CallKit гарантирует: приложения, предоставляющие связанные с вызовами услуги, беспрепятственно работают вместе на устройстве пользователя и учитывают такие функции, как «Не беспокоить».

Снимок экрана 2024-12-16 в 13.11.57.png

Яркий пример мода – звонки в Telegram

External accessory communication

Этот мод позволяет приложению работать с внешним устройством, зарегистрированным в программе MFi (Manufactured For iPhone) в Background-режиме.

Внешние устройства могут подключаться с помощью Bluetooth, Lighting и Type-C. За работу с такими устройствами отвечает фреймворк ExternalAccessory.

Using Bluetooth LE accessories и Acting as a Bluetooth LE accessory

Основная разница этих опций заключается в том, в какой роли Bluetooth-устройства приложение сможет принимать участие.

Using Bluetooth LE accessories позволяет приложению получать данные с Bluetooth-аксессуара. Acting as a Bluetooth LE accessory напротив – посылать данные, то есть быть в роли Bluetooth-аксессуара.

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

Для работы с Bluetooth в приложении также требуется разрешение от пользователя!

Чтобы поиск устройства осуществлялся в Background, нужно указать необходимый идентификатор Bluetooth-сервиса.

let SERVICE_UUID = CBUUID(string: "0000ff0-0000-1000-8000-00805f9b34fb") centralManager.scanForPeripherals( withServices: [SERVICE_UUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey : true] )

Без идентификатора Bluetooth-сервиса поиск не будет проводиться:

centralManager.scanForPeripherals( withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey : true]

Remote notitifications

Remote notitifications позволяет получать различные уведомления для обновления данных приложения.

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

На их обработку даётся 30 секунд, и для получения данных этого достаточно. Однако у таких пушей есть ряд серьёзных недостатков:

  • Низкий приоритет (нет гарантии, что они обработаются);

  • Поступление пушей ограничено: Apple не советует посылать больше 2–3 в час;

  • Система задерживает поступающие сайлент-пуши, при этом новые замещают старые, перезаписывая их;

  • Не будут работать в режиме экономии энергии.

func application( _ application: UlApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],  fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -› Void ){ do{ let data = try await fetchSomeData() if data == nil { completionHandler(.noData) } else { completionHandler(.newData) } }catch{ completionHandler(.failed) } }

Push to talk

В iOS 16 Apple представила новый фреймворк Push to Talk. Он позволяет пользователям отправлять голосовые сообщения в реальном времени, нажимая на кнопку и говоря в микрофон. Грубо говоря, это рация.

Данный фреймворк добавляет новый тип пушей, которые будят приложение и воспроизводят аудио. В заголовке таких пушей указывается тип pushtotalk, а их приоритет равен 10.

curl -v \\ -d '{"activeSpeaker":"The name of the active speaker"}' \\ -H "apns-push-type: pushtotalk" \\ -Н "apns-topic: <The app bundle id>.voip-ptt" \\ -Н "apns-priority: 10" \\ -H "apns-expiration: 0" \\ --http2 \\ --cert <The certificate key name>.pem \\ <https://api.sandbox.push.apple.com/3/device/><token>

Метод, который обрабатывает пуши:

func incomingPushResult(channelManager: PTChannelManager, channelUUID: UUID, pushPayload: [String: Any]) -> PTPushResult { guard let activeSpeaker = pushPayload["activeSpeaker"] as? String else { return .leaveChannel }  let activeSpeakerImage = UIImage(named: "someImage") let participant = PTParticipant(name: activeSpeaker, image: activeSpeakerImage)  return .activeRemoteParticipant(participant) }  func channelManager(_ channelManager: PTChannelManager, didActivate audioSession: AVAudioSession) { // some code }

Этот метод возвращает результаты обработки пуша: leaveChannel, который обозначает освобождение канала, и activeRemoteParticipant, который указывает, что канал занят.

Uses nearby interactions

Nerby Interactions – это специальный фреймворк, который позволяет приложению работать с другими девайсами через UWB.

Ultra Wideband (UWB) – это беспроводная технология передачи данных, которая использует широкий диапазон частот. В связи с этим она обладает высокой точностью в определении расстояний и положения объектов, включая устройства и телефоны.

UWB поддерживает чип U1, имеющийся в ряде устройств Apple. Технология открывает широкий спектр возможностей использования. Например, в игровой индустрии:

developer.apple.com

developer.apple.com

В 2022 Apple добавила возможность использования NearbyInteractions в Background с аксессуарами, заранее сопряжёнными через Bluetooth.

Так кратко можно охарактеризовать моды Background в iOS, механизм работы которых необходимо учитывать разработчику. Если у вас есть дополнения или вопросы, буду рад обсудить их в комментариях.


ссылка на оригинал статьи https://habr.com/ru/articles/871040/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *