Как уникализировать несколько приложений-конвертеров валют по дизайну и коду, сохранив сходство
Что проверяют
Умеете ли вы строить white-label: одна кодовая база, несколько приложений с разным лицом. И понимаете ли, где кончается инженерия и начинается риск отказа в App Store по правилу 4.3 про спам и дубли. Следом обычно спрашивают, как вы разведёте конфигурацию таргетов и чем приложения будут отличаться по сути.
Как отвечать
Технический каркас:
- общее ядро в Swift Package: сетевой слой, модели курсов, кеш, форматирование валют через
NumberFormatterилиFormatStyle. Приложения зависят от пакета и не копируют код; - таргеты и схемы: у каждого приложения свой таргет со своим bundle id,
Info.plist, каталогом ассетов и иконкой. Различия в параметрах выносятся в.xcconfig, а не в#ifпо всему коду; - тема как зависимость: структура с цветами, шрифтами, радиусами и отступами. В SwiftUI её удобно передавать через
EnvironmentValues, в UIKit внедрять через координатор. Экраны читают токены, а не захардкоженные значения; - флаги возможностей: конфигурация приложения включает модули: история, графики, офлайн-режим, уведомления о курсе. Отличие собирается из модулей, а не форком;
- разные источники данных: протокол вроде
RatesProviderс несколькими реализациями, если приложения работают с разными API.
Затем честно про ревью. Правило 4.3 прямо советует не выпускать несколько вариантов одного приложения под разными bundle id, и перекраска такой вопрос не решает. Сильный ответ звучит так: общий код это нормально, но у каждого приложения должна быть своя аудитория и свой сценарий, например конвертер для путешественников с офлайн-курсами и инструмент для бухгалтера с историей и экспортом. Если отличия только в цвете, разумнее одно приложение с темами.
Где спотыкаются
Копируют репозиторий под каждое приложение. Через полгода исправление бага приходится делать трижды, а версии расходятся.
Предлагают «уникализировать» переименованием классов и перестановкой экранов. Ревью оценивает продукт целиком, а не имена в бинарнике.
Размазывают различия через #if APP_A по всему коду. Каждый новый вариант умножает ветки, и без сборки всех таргетов на CI никто не знает, что сломалось.