Динамическое изменение иконки приложения
Итак, 2024 год подходит к концу. Пришло время подведения итогов, финальных релизов и обновления иконки для праздничного настроения. Стоит отметить, что наша команда не раз задумывалась о динамическом изменении иконки, независимо от релизного поезда. Мы реализовали данный подход, набили шишек и решили поделиться своим опытом.
- Постановка задачи
- Реализация динамического переключения иконки на iOS
- Реализация динамического переключения иконки на Android
- На что опираться для переключения иконки
Изменение иконки приложения без обновления версии приложения в сторах
С таким заголовком задачи встретилась наша команда в начале спринта. Основная идея состояла в отрыве зависимости от релизного поезда.
Гипотеза заключалась в том, что это позволит снизить риски отсутствия обновления иконки перед каким-либо значимым праздником или событием:
- шанс отмены релиза крайне низкий, но никогда не равен нулю;
- даты старта или завершения релиза могут не подходить для предстоящего события;
- пользователь может не обновлять приложение долгое время и ходить с новогодним дизайном даже летом.
Если вы столкнулись с такой задачей или вас посещала мысль о воплощении такой идеи, но лапки так и не дошли, то делимся своим опытом и шагами для реализации.
Реализация динамического переключения иконки на iOS
Механизм реализации альтернативных иконок стал доступен с iOS 10.3 и идеально подходит для сезонных акций, тематических обновлений или других целей.
Шаг 1: Подготовка иконок
Для начала подготовьте альтернативные иконки в двух размерах: 120px и
180px. Назовите их следующим образом:
Создайте директорию в вашем проекте, где будут хранится файлы изображений.
Шаг 2: Настройка Info.plist
Добавьте в ваш Info.plist ключ CFBundleIcons и его под-ключ CFBundleAlternateIcons. Пример конфигурации:
Здесь мы добавили две альтернативные иконки: Winter и Spring. Чтобы обращаться к ним, используйте значение ключа key. Название иконки должно совпадать с именем файла, но без суффиксов @2x и @3x .
Шаг 3: Создание AppIconManager
Для удобной работы создадим синглтон AppIconManager. Пример реализации:
supportsAlternateIcons— проверяет, поддерживает ли приложение смену иконок;alternateIconName— возвращает текущую альтернативную иконку;setAlternateIconName— устанавливает новую иконку, используя название ключаkeyизInfo.plist.
Примечание: Если вы хотите вернуть стандартную иконку, передайте nil в параметр setAlternateIconName.
Шаг 4: Использование AppIconManager
Теперь достаточно одной строки кода, чтобы сменить иконку:
Результат
Как убрать системное уведомление при смене иконки
По умолчанию, iOS уведомляет пользователя о смене иконки. Apple не предоставляет официального способа отключить это сообщение, но есть способ его обойти. Для этого обновим функцию setAppIcon:
ВАЖНО! Почему такой вариант небезопасен?
Не рекомендуем использовать данное решение как минимум по трем причинам:
- Данное решение противоречит релизной политике Apple и может быть отклонено тестировщиком на этапе проверки в AppStoreConnect;
- Небезопасный вызов метода.
unsafeBitCastпредполагает, что сигнатура функции совпадает сsetAlternateIconName. Если есть расхождение, это может привести к повреждению памяти или сбоям; - Поскольку
_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!🤘
Полезные ссылки:
- Документация по альтернативным иконкам для iOS
- Документация по AndroidManifest.xml
- Документация по activity-alias
- Документация по Firebase Remote Config