Розробка White-Label мобільної програми
White-label мобільна програма — це єдина кодова база, що компілюється в кілька незалежних продуктів для різних клієнтів, брендів чи ринків. Кожен екземпляр має свій Bundle ID, іконку, кольорову схему, набір функцій та іноді власний backend. Розробники працюють з одним репозиторієм.
Складність не в самій ідеї — а в тому, щоб з першого дня закласти архітектуру, яка не перетворится в спагеті з if (tenantId == "brand_a") через півроку.
Архітектурні рішення
Product Flavors (Android) та Schemes/Targets (iOS)
Базовий механізм платформ — Build Flavors на Android та Xcodeconfig/Targets на iOS — дозволяє менявти ресурси, строкові константи та флаги компілятора без змін коду.
Android: product flavors
// app/build.gradle.kts
android {
flavorDimensions += "tenant"
productFlavors {
create("brandA") {
dimension = "tenant"
applicationId = "com.brandA.app"
resValue("string", "app_name", "Brand A")
buildConfigField("String", "API_BASE_URL", "\"https://api.brand-a.com\"")
buildConfigField("String", "TENANT_ID", "\"brand_a\"")
}
}
}
Ресурси (іконки, кольори, строки) переопреділяються через директорії:
app/src/brandA/res/drawable/ic_launcher.png
app/src/main/res/... ← спільні ресурси
iOS: Xcodeconfig + Multiple Targets
Кожен клієнт — окремий Target у проекті Xcode, який розділяє код з основним target:
MyApp.xcodeproj
├── Targets
│ ├── BrandA ← Bundle ID: com.brandA.app
│ └── Shared Code ← спільний Swift Package
├── BrandA/
│ ├── Assets.xcassets ← іконки, кольори бренда
│ └── Config.xcconfig ← API URL, feature flags
Feature Flags per Tenant
Різні клієнти часто мають різний набір функцій. Флаги в xcconfig/BuildConfig визначають, що компілюється:
if (BuildConfig.FEATURE_PREMIUM_ENABLED) {
setupPremiumFeatures()
}
Для динамічних флагів (змінюваних без перекомпіляції) — Firebase Remote Config з проектом per tenant або єдиний проект з tenant-specific параметрами.
Theming Engine
Кольори, шрифти, розміри — завантажуємо з Theme-конфігу, не хардкодимо:
data class TenantTheme(
val primaryColor: Color,
val fontFamily: String,
val logoResId: Int
)
object ThemeProvider {
fun getTheme(tenantId: String): TenantTheme = when (tenantId) {
"brand_a" -> TenantTheme(
primaryColor = Color(0xFF1A73E8),
fontFamily = "Roboto",
logoResId = R.drawable.logo_brand_a
)
else -> defaultTheme
}
}
CI/CD для множини артефактів
Кожен push в main повинен собирати все tenant-сборки. На GitHub Actions:
strategy:
matrix:
flavor: [brandA, brandB]
steps:
- name: Build APK for ${{ matrix.flavor }}
run: ./gradlew assemble${{ matrix.flavor }}Release
Кожен flavor деплоїться в окремий Play Store аккаунт або в один аккаунт з різними Package Names.
Організація репозиторію
repo/
├── app/ ← Android app module
│ └── src/
│ ├── main/ ← спільний код
│ ├── brandA/ ← ресурси Brand A
│ └── brandB/ ← ресурси Brand B
├── core/ ← shared business logic
├── features/ ← feature modules
└── tenants/
├── brand-a.properties
└── brand-b.properties
Монорепо з чіткими границями між спільним кодом та tenant-специфічним. Ні один tenant-специфічний файл не повинен попасти в main/ або core/.
Типичні помилки при розробці white-label
Tenant logic в бізнес-коді. if (tenantId == "brand_a") showSpecialButton() в ViewModel — це шлях до хаосу. Правильно: tenant-специфічне поведення через DI або конфігураційний об'єкт, який інжектится зовні.
Shared strings з захардкоженими брендами. strings.xml з текстом «Добро пожаловать в Brand A» у common-директорії. Все що містить ім'я бренда — тільки в tenant-директорії.
Єдиний firebase project для всіх tenants. Firebase Crashlytics та Analytics путають крэші та події різних клієнтів. У кожного tenant — свій google-services.json.
Відсутність автотестів для кожного flavor. Unit-тести проходять, але в конкретному flavor не компілюється — тому що flavor переопределив ресурс, який тест використовує. Тести гоняємо для кожного flavor у CI.
Процес роботи
Аудит та проектування — аналіз вимог всіх tenants: спільний функціонал, різниці, плановане кількість клієнтів. Вибір стратегії.
Базова архітектура — настройка flavors/targets, ThemeProvider, FeatureFlags, CI pipeline.
Розробка по модулях — feature modules з інверсією залежностей, щоб tenant міг включити або виключити будь-який модуль.
Onboarding нового tenant — шаблон конфігураційних файлів + чеклист: icons, colors, API URL, Firebase project, App Store/Play Store account.
Ориєнтири по срокам
MVP white-label приложення з 2–3 tenants на одній платформі (iOS або Android) — 8–14 тижнів залежно від складності функціоналу. Кросплатформенна реалізація на Flutter або React Native з підтримкою 5+ tenants та повним CI/CD — 16–24 тижні. Вартість розраховується індивідуально.







