Всем привет! Меня зовут Фируза, я iOS-разработчик в компании SimbirSoft. В этой статье мы попробуем разобраться, как ускорить запуск приложения, а именно:

Статья будет полезна для iOS-разработчиков любого уровня, желающих улучшить производительность своих приложений.

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

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

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

  1. Запуск приложения: пользователь нажимает на иконку приложения.

  2. Создание процесса: операционная система iOS создает процесс для приложения.

  3. Система выполняет функцию main().

Функция main() является входной точкой для приложения, инициализирует начало жизненного цикла приложения и вызывает другие необходимые функции для запуска приложения.

  1. Функция main() вызывает UIApplicationMain(_:_:_:_:), которая создает экземпляр UIApplication и делегата приложения, и устанавливает связь между объектами UIKit и приложением.

  1. UIKit загружает сториборд, если он используется.

  2. UIKit вызывает метод application(_:willFinishLaunchingWithOptions:) в AppDelegate.

  3. UIKit выполняет восстановление состояния, что приводит к выполнению дополнительных методов в делегате приложения и контроллерах представления.

  4. UIKit вызывает метод application(_:didFinishLaunchingWithOptions:) в делегате приложения, что означает, что приложение готово к работе.

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

Этапы запуска приложения в виде схемы:

После запуска приложения система использует AppDelegate или SceneDelegate для отображения пользовательского интерфейса приложения и управления его жизненным циклом.

Как собрать актуальные метрики скорости запуска и отзывчивости приложения?

С появлением предварительного прогрева в iOS 15 функция main() может быть вызвана до касания иконки приложения пользователем, что инициирует начальную последовательность запуска, но делает паузу перед вызовом функции UIApplicationMain. Таким образом iOS может создавать и кэшировать любые структуры низкого уровня, которые требуются для полного запуска.

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

Собрать актуальные метрики скорости запуска и отзывчивости iOS-приложения можно при помощи различных инструментов и методов, описанных ниже:

  1. Использование инструментов Xcode

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

Xcode Organizer помогает узнать, привели ли внесенные оптимизации к повышению производительности.

Чтобы открыть Xcode Organizer, выбираем “Window” -> “Organizer”.

На скриншоте ниже представлена диаграмма анализа скорости запуска приложения:

Отсутствие данных в Xcode Organizer может быть связано с тем, что пороговые значения не публикуются. Данные будут доступны, если каждой версией приложения будут пользоваться несколько тысяч пользователей. Также оно должно быть опубликовано на TestFligh или AppStore.

Инструмент App Launch предназначен для измерения времени запуска приложения. Он предоставляет детальную информацию о времени, затраченном на запуск приложения, и его процессе инициализации.

Чтобы воспользоваться инструментом, необходимо выбрать "Xcode" -> "Open Developer Tool" -> "Instruments" -> "App Launch" и нажать на кнопку "Record" (красная кнопка в левом верхнем углу). Когда приложение запустится, нажать на кнопку "Stop", чтобы завершить запись. После этого будут доступны результаты анализа времени запуска приложения.

2. MetricKit — это фреймворк от Apple, предоставляющий API для сбора и анализа метрик производительности iOS-приложений. Он включен в стандартные библиотеки iOS и доступен, начиная с iOS 13. Показатели могут быть представлены в виде гистограмм, которые фиксируют частоту наблюдаемых значений в течение дня.

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

Система отправляет отчеты о показателях за предыдущие 24 часа один раз в день и немедленно в iOS 15 и более поздних версиях.

Примечание: MetricKit работает только на реальном устройстве iOS и не совместим с симулятором.

Чтобы использовать MetricKit, нужно зарегистрировать MetricKit в объекте MXMetricManager, расширить AppDelegate протоколом MXMetricManagerSubscriber, и реализовать метод didReceive(_:).

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    MXMetricManager.shared.add(self)
    return true
}
extension AppDelegate: MXMetricManagerSubscriber {
    func didReceive(_ payloads: [MXMetricPayload]) {}
}

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

Объект MXMetricPayload содержит свойство applicationLaunchMetrics типа MXAppLaunchMetric, предоставляющее показатели запуска приложения и возобновления работы.

Объект типа MXAppLaunchMetric имеет свойства:

  • histogrammedTimeToFirstDraw – гистограмма интервалов времени, затраченных на запуск приложения.

  • histogrammedApplicationResumeTime – гистограмма интервалов времени, затраченных на возобновление работы приложения из фонового режима.

  • histogrammedOptimizedTimeToFirstDraw(с iOS 15.2) – гистограмма интервалов времени, связанных с предварительным прогревом приложения

Дамп данных, связанных с MXAppLaunchMetric, выглядит так:

bucketStart — это начальное значение интервала, bucketEnd — конечное значение интервала, а bucketCount – количество наблюдаемых выборок, попадающих в сегмент.

Расчет скалярного значения, которое представляет собой среднее значение, происходит по следующей формуле:

Какие тактики применить, чтобы ускорить старт и отзывчивость запуска?

Ускорение старта и повышение отзывчивости приложения — это важные аспекты улучшения пользовательского опыта. Вот несколько тактик, которые можно применить для достижения этой цели:

  1. Оптимизация изображений:

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

Для сжатия изображений без потери качества можно рассмотреть формат изображений HEIF.

HEIF (High Efficiency Image Format) это современный формат файлов изображений, который разработан для эффективного сжатия изображений с минимальной потерей качества. Преимущество данного формата в небольшом размере файла.

Также в каталоге ассетов можно настроить сжатие для каждого изображения отдельно или для всей группы изображений одновременно.

  • Lossless – сжатие без потерь, размер не меняется.

  • Automatic – автоматическое сжатие с потерями.

  • GPU Smallest Size – сжатие с потерями, наименьший размер изображения.

  • GPU Best Quality – сжатие с потерями, с наилучшим качеством изображения.

  1. Предварительная загрузка данных:

Если приложение зависит от удаленных данных, необходимо предварительно загружать их, когда это возможно.

  1. Уменьшение сложности интерфейса:

Упрощение стартового экрана за счет сокращения количества элементов интерфейса и упрощения иерархии представлений может значительно ускорить загрузку приложения и улучшить впечатление от приложения.

Также уменьшение сложности анимации и использование более простых эффектов помогут ускорить загрузку и старт приложения. 

  1. Кэширование:

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

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

  1. Оптимизация зависимостей:

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

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

Если при подключении зависимостей через менеджер CocoaPods прописать в Podfile:

use_frameworks!:linkage => :static

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

Скорость запуска приложения при подключении зависимостей динамически (2,60s):

Скорость запуска приложения при подключении зависимостей статически (543,91ms):

Swift Package Manager (SPM) по умолчанию включает зависимости статически.

  1. Анализ производительности:

Использование инструментов анализа производительности для выявления узких мест и оптимизации работы приложения.

  1. Оптимизация кода:

Оптимизация алгоритмов и структур данных для улучшения производительности.

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

Заключение

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

Спасибо за внимание!  

Больше полезных материалов для mobile-разработчиков мы также публикуем в наших соцсетях – ВК и Telegram.

Комментарии (5)


  1. prika148
    19.03.2024 12:01

    Со временем я всё меньше программирую и всё больше общаюсь с менеджерами.
    Но это - последняя капля: текст заголовка и КДПВ понял как "Как запустить IT проект в виде ios приложения в минимальные сроки" - думал, что здесь будет про подбор команды, ускорение модерации в сторе и тому подобное
    Надо что-то менять в своей жизни ((


    1. mobileSimbirSoft Автор
      19.03.2024 12:01

      Что называется, если нужен был знак, то это он)


  1. kotovsky_art
    19.03.2024 12:01

    Чёт какой-то бессвязный компот. Тут тебе и запуск сторибордов (кого-нибудь ещё интересует жизненный цикл сторибордов?). Тут и метрикКит, которым если автор пользовалась, то знала что органайзере хрен дождешься данных от него. В трёх строках смешались Pods и SPM. Heif как формат данных зачем-то вплели, никто и никогда не будет его использовать для ресурсов, общих с вебом или андроидом. Статья ради статьи. Если б не интернет, который всё стерпит, было б жалко бумагу


    1. mobileSimbirSoft Автор
      19.03.2024 12:01

      MetricKit дополняет XCode Organizer, предоставляя программный способ получения данных, чтобы мы могли управлять ими по своему усмотрению, например, отправляя на сервер. Если в XCode Organizer отсутствовали данные, то возможно из-за того, что приложением пользуется недостаточное количество пользователей.

      Сейчас всё ещё существует достаточное количество приложений с использованием сторибордов. Да, HEIF действительно редко используется, но полезно знать о такой возможности оптимизации, так как выбор способа реализации связан с требованиями проекта.


      1. kotovsky_art
        19.03.2024 12:01

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