Привет, Хабр! Меня зовут Сергей, и я 3 года работаю Android/iOS разработчиком. Написал с нуля приложение для фитнес-клубов (Google Play/App Store — если интересно, код под NDA, его не могу показать) и дорабатываю малоизвестный банк. За это время накопилось много интересных решений, которые переношу из проекта в проект. Приходилось пробовать разные подходы и создавать своих «Франкенштейнов», поскольку работающего как мне нужно кода и статей найти не удавалось. И так было до тех пор, пока не выкристаллизовались оптимальные для меня варианты. В своих статьях расскажу о них. Кроме того, мне всегда интересно сравнивать подход в iOS и Android в аналогичных вопросах. Надеюсь, мои статьи помогут тем, кто хочет перейти с одной платформы на другую. Любое приложение начинается с загрузки. И как оказалось, экран загрузки совсем не так прост, как кажется. То, что мы там видим — картинку, версию приложения и прочее — совсем не стандартные решения. Поэтому я решил первую статью написать именно об этом. Итак, начнём. Задача: Под iOS и Android сделать экран загрузки, на котором будет показываться версия приложения и логотип. Когда будет готов экран загрузки — автоматизировать увеличение версии при разработке и смену номера релиза при публикации. В качестве логотипа будет картинка из интернета: Реализация: Создадим одинаковое приложение на Android и iOS, имитирующее бросок кубика, и в каждом реализуем экран загрузки. Все приложения сразу делаем с Git-репозиторием — в конце статьи приведу ссылки на репозитории с готовыми приложениями. Дисклеймер: Как установить Xcode и Android Studio и создавать в них приложение, думаю, большинство из вас знает, поэтому не буду описывать это. Но если вдруг не знаете, то вот вам ссылки на соответствующие статьи: Курс по изучению Kotlin и Android Studio с нуля до Junior. #1 Введение. Установка Android Studio  — тут базовые действия по установке Android Studio; Android Studio для NDK под Windows — здесь уже продвинутые настройки Android Studio. Как установить и сделать базовые настройки в Xсode почему-то статей на Хабре не нашёл. Кажется, как это делать очевидно, но если нужна такая статья — пишите в комментариях. Создадим пустое приложение, выбрав при создании Storyboards вместо SwiftUI и в качестве языка — Swift (вариант с Objective-С опустим, так как он морально устарел). Более современный вариант со SwiftUI рассмотрю в следующей статье, а пока продолжим с тем, с чего я начинал. Получился проект, состоящий из следующих файлов: Добавим на главном экране Main.storyboard надпись (Label) и кнопку (Button), при нажатии на которую в надписи будем генерировать число от 1 до 6: ЭКод: Экран запуска тут уже существует. Это LaunchScreen.storyboard, но есть один нюанс — этот экран статический, то есть как данные настроили в Xcode в конструкторе storyboard — так они и будут показаны на экране, без какой-либо возможности управления кодом. Добавим на LaunchScreen наш логотип (через ImageView) и номер версии (через Label), в который пока явно напишем версию 1.2.3. Если запустить приложение, то увидим, что экран загрузки корректно показывается и после загрузки приложения появляется главный экран. Основная задача выполнена и тут начинается самое интересное — автоматизация генерации номера версии из Git. Изменим имя надписи с номером версии, например на APP_VERSION, и потом при сборке по этому имени будем находить надпись и менять текст в ней. Нам номер версии нужен при запуске приложения, поэтому для генерации отлично подойдёт фаза сборки со специально подготовленным для неё скриптом. Создаём новую фазу сборки с запуском скрипта: Пропишем путь к нашему будущему скрипту: Создаём новый файл скрипта. Скрипт я назвал version.sh и поместил его рядом с остальными файлами проекта. В получившийся файл скрипта вставляем следующий код: Далее разберём сам код построчно: В первой строке указываем, где установлен Git. Во второй строке получаем текст из последнего тега Git. В третьей строке считаем, сколько коммитов в Git, исключая мерж-коммиты. Далее идёт блок if else fi, в котором прописывается версия сборки в проекте: точнее в файле Info.plist — в параметре CFBundleVersion. В следующем блоке if else fie прописывается версия релиза в параметре CFBundleShortVersionString файла Info.plist. В предпоследней строке запоминаем путь к LaunchScreen.storyboard. В последней строке заменяем текст в APP_VERSION на номер версии. Если сейчас запустить приложение, то почти наверняка у вас появится ошибка: Почему она вылезает? Причин может быть несколько: Мы забыли дать файлу version.sh права на запуск командой в терминале:sudo chmod 770 version.sh. Для выполнения этой команды нужно через терминал перейти в папку, в которой находится файл version.sh, и после выполнения команды ввести пароль администратора. Возможно, вы положили файл version.sh не в ту папку или не включили её в таргет — перепроверьте все пути в скрипте, в фазе сборки и где лежит сам файл. Также файл LaunchScreen.storyboard может оказаться в подпапке Base.lproj — в этом случае проще исправить путь к нему в version.sh. Скорее всего, у нас нет ни одного тега в Git. Создаём тег в Git, например «1.1», и ещё раз запускаем приложение. Если ни один из перечисленных выше пунктов не помог, то внимательно читаем, что пишется в логах сборки и экспериментируем. Автоматически обновилась версия релиза и сборки, и всё вывелось на экран загрузки: Укажем, что проект будет на UIKit и storyboard: Минус такого подхода — то, что при каждой сборке создаётся копия и изменяется файл LaunchScreen.storyboard, но эти изменения можно отменить — это не баг, а фича. Код проекта под iOS в репозитории: https://github.com/mobile-sergey/HabrVersion_iOS Создадим пустое приложение на Kotlin с интерфейсом на XML и скриптами на Gradle. Более современный вариант с Kotlin Compose и скриптами на Kotlin рассмотрю в следующей статье, а пока продолжим то, с чего я начинал. Для начала создадим пустой проект без Activity: Укажем, что проект будет на Kotlin и Groovy: Добавим в приложение две Activity, добавим их через контекстное меню из галереи: В галерее выберем Empty Views Activity (чтобы у нас были простые Activity на XML): Первая Activity пусть будет MainActivity, с настройками по умолчанию. А в настройках у второй ставим флаг Launcher Activity, чтобы приложение запускалось, начиная с неё: Запустим проект, увидим пустое окно Launch Activity: Добавим текст (TextView) и кнопку (Button) в макет главного окна (activity_main.xml) и в классе MainActivity пропишем код, чтобы надпись изменялась при нажатии кнопки: Осталось сделать экран загрузки и прописать, чтобы он показывался на пару секунд и автоматически переключался на главный экран: Настроим экран запуска: для начала в res/values/themes/themes.xml исправим DarkActionBar на NoActionBar, чтобы не появлялась полоска с названием приложения и Activity занимала весь экран. Добавляем текст (TextView) с номером версии 1.2.3 и картинку (ImageView) в макет экрана загрузки (activity_launch.xml) и в классе LaunchActivity прописываем создание хендлера и его выполнение через указанную задержку с запуском MainActivity. Запустим приложение: сначала покажется экран загрузки приложения, и через 2 секунды откроется основной экран приложения. P.S. Пока готовил это описание, наткнулся на статью на Хабре про создание экранов загрузки, в которой помимо моего описаны ещё 3 варианта создания экрана загрузки: Полное руководство по Splash Screen на Android. Осталась самая малость — научиться автоматически генерировать номер версии и выводить его в LaunchActivity. Для этого нам понадобится написать пару функций в build.gradle (app) и потом их вызвать. В начале файла между plugins {} и android {} добавляем: Это две переменные, в которых хранятся функции: первая генерирует код версии из количества коммитов, не являющихся мержами в Git; вторая генерирует номер релиза из последнего тега в Git. Далее вместо номера сборки и номера релиза в блоке android {} подставляем вызов этих функций: Также прямо под ними можно добавить строчку: Эта строчка будет менять имя выгружаемого файла .apk или .aab. И ещё в конце файла build.gradle после dependencies{} я добавляю: Это нужно для того, чтобы при сборке на вкладке Build видеть номер собираемой версии. И не забываем нажать кнопку Sync Now, чтобы эти изменения применились. Создаём в Git новый тег, например «1.0», и запускаем сборку — видим в Build надпись: Осталось теперь вывести номер версии на экран Launch Activity. Тут всё совсем не очевидно. Надо создать модуль приложения, в котором получим номер версии: Потом в манифесте нужно привязать этот класс к приложению строкой: И чтобы номер версии стал показываться, осталось вывести его в LaunchActivity: Теперь запускаем приложение и видим, что показывается текущая версия: Код проекта под Android в репозитории. Итак, мы посмотрели, что и в iOS, и в Android приходится использовать свои танцы с бубнами, чтобы получить тот результат, который нам нужен. Надеюсь, статья поможет в создании ваших приложений. Буду рад вашим комментариям и идеям. Уверен, что есть и другие решения, которые могут быть и лучше предложенных мной. Если формат сравнения iOS и Android вам понравился, то в следующей статье опишу создание загрузочных экранов на SwiftUI и Kotlin Compose.  Создаю Android/iOS приложения