Android & iOS
December 17, 2024

Динамическое изменение иконки приложения

Всем привет, дорогие друзья!

Итак, 2024 год подходит к концу. Пришло время подведения итогов, финальных релизов и обновления иконки для праздничного настроения. Стоит отметить, что наша команда не раз задумывалась о динамическом изменении иконки, независимо от релизного поезда. Мы реализовали данный подход, набили шишек и решили поделиться своим опытом.

О чём статья:

Изменение иконки приложения без обновления версии приложения в сторах

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

Гипотеза заключалась в том, что это позволит снизить риски отсутствия обновления иконки перед каким-либо значимым праздником или событием:

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

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

Реализация динамического переключения иконки на iOS

Механизм реализации альтернативных иконок стал доступен с iOS 10.3 и идеально подходит для сезонных акций, тематических обновлений или других целей.

Шаг 1: Подготовка иконок

Для начала подготовьте альтернативные иконки в двух размерах: 120px и

180px. Назовите их следующим образом:

  • IconName@2x для 120px иконки;
  • IconName@3x для 180px иконки.

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

Шаг 2: Настройка Info.plist

Добавьте в ваш Info.plist ключ CFBundleIcons и его под-ключ CFBundleAlternateIcons. Пример конфигурации:

Здесь мы добавили две альтернативные иконки: Winter и Spring. Чтобы обращаться к ним, используйте значение ключа key. Название иконки должно совпадать с именем файла, но без суффиксов @2x и @3x .

Шаг 3: Создание AppIconManager

Для удобной работы создадим синглтон AppIconManager. Пример реализации:

Разберем ключевые моменты:

  1. supportsAlternateIcons — проверяет, поддерживает ли приложение смену иконок;
  2. alternateIconName — возвращает текущую альтернативную иконку;
  3. setAlternateIconName — устанавливает новую иконку, используя название ключа key из Info.plist.

Примечание: Если вы хотите вернуть стандартную иконку, передайте nil в параметр setAlternateIconName.

Шаг 4: Использование AppIconManager

Теперь достаточно одной строки кода, чтобы сменить иконку:

Результат

Как убрать системное уведомление при смене иконки

По умолчанию, iOS уведомляет пользователя о смене иконки. Apple не предоставляет официального способа отключить это сообщение, но есть способ его обойти. Для этого обновим функцию setAppIcon:

ВАЖНО! Почему такой вариант небезопасен?

Не рекомендуем использовать данное решение как минимум по трем причинам:

  1. Данное решение противоречит релизной политике Apple и может быть отклонено тестировщиком на этапе проверки в AppStoreConnect;
  2. Небезопасный вызов метода. unsafeBitCast предполагает, что сигнатура функции совпадает с setAlternateIconName. Если есть расхождение, это может привести к повреждению памяти или сбоям;
  3. Поскольку _setAlternateIconName:completionHandler: не документирован, его поведение может измениться в будущих версиях iOS. Это может привести в лучшем случае к некорректному выполнению функции, в худшем к крашу приложения.

Поэтому используйте это решение на свой страх и риск 😅

Реализация динамического переключения иконки на Android

В Android иконка приложения указывается в файле AndroidManifest.xml и для её переопределения лучше использовать activity-alias, который служит для создания "ссылок" на существующую Activity.

Шаг 1: Подготовка иконок

На данном этапе подготовка иконок происходит аналогично процессу создания иконки приложения по умолчанию, стоит лишь переименовать ресурсы согласно типу альтернативной иконки ic_winter и ic_spring.

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

Шаг 2: Настройка activity-alias в AndroidManifest.xml

Ключевыми атрибутами activity-alias являются:

  • android:name — имя alias-компонента;
  • android:targetActivity — целевая Activity, которую можно открыть через alias;
  • android:enabled — флаг позволяющий управлять состоянием alias;
  • android:icon — задаёт иконку для alias;
  • android:label — задаёт название для alias.

В AndroidManifest.xml связываем alias каждого типа с Activity, которая позволяет открыть приложение:

Шаг 3: Добавим немного красоты

Для удобства на следующем шаге, можно вынести имя alias-компонентов в отдельный файл, создав классы Activity с идентичным именем из AndroidManifest.xml:

После, подготовить enum-класс с типами:

Шаг 4: Измените активный activity-alias с помощью PackageManager

Создаём метод, который включает нужный alias и отключает остальные.

Результат

Подводные камни

Настоятельно рекомендуем заранее продумать и предложить дизайнеру отобразить AlertDialog или BottomSheet по аналогии с iOS, чтобы предупредить пользователя о смене иконки приложения. Это связано с тем, что приложение будет закрыто на Android 13 и выше, несмотря на указанный PackageManager.DONT_KILL_APP.

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

Например, для SingleActivity приложений при смене языка потребуется осуществить пересоздание Activity, тем самым вызвав onStop , что приведёт к уничтожению экземпляра приложения, если иконка не соответствует ожидаемой.

На что опираться для переключения иконки

Здесь возможны различные варианты.

Если в вашей компании существует механизм feature-toggle и соответствующее API - оно может подойти для данной задачи.

Если такого механизма нет, можно обратить внимание на Firebase Remote Config.

На этом наш пост подошёл к концу. Всем праздничного настроения и высокого Crash-free во время выходных. Good coding and happy day!🤘

Полезные ссылки:


Telegram-канал Теплица

Обратная связь