22 KiB
Bedrock Branding Implementation Guide
A comprehensive guide to implementing the Bedrock branding system (app icon and launch screen) in your iOS app.
Table of Contents
- Overview
- What's Included
- Step 1: Create BrandingConfig.swift
- Step 2: Add Launch Screen to App Entry Point
- Step 3: Native Launch Screen Setup
- Step 4: Add Branding Tools to Settings (Optional)
- Step 5: Generate Your App Icon
- Step 6: Add Icon to Xcode Assets
- Configuration Reference
- Complete Example
- Troubleshooting
Overview
The Bedrock branding system provides a fully customizable app icon and launch screen that can be configured for any type of app. All visual elements are configurable through Swift code.
Key Features
- Customizable gradients: Primary and secondary colors for backgrounds
- Configurable icons: Use any SF Symbols for your app identity
- Multiple pattern styles: Dots, grid, radial glow, or no pattern
- Layout flexibility: Icon above title, title above icon, icon only, or title only
- Animated launch: Smooth fade-in animations with configurable timing
- Icon generator: Built-in tool to export 1024×1024 PNG for App Store
What's Included
The branding system consists of these files in Bedrock/Sources/Bedrock/Branding/:
| File | Purpose |
|---|---|
AppIconView.swift |
Renders the app icon design |
LaunchScreenView.swift |
Animated launch screen view |
AppLaunchView.swift |
Wrapper that shows launch screen before main content |
IconGeneratorView.swift |
Development tool to export icon images |
IconRenderer.swift |
Utility to render views to images |
BrandingPreviewView.swift |
Preview tool for icons and launch screens |
Step 1: Create BrandingConfig.swift
Create a new Swift file in your app's Shared/ folder called BrandingConfig.swift. This file defines your app's branding.
Template
//
// BrandingConfig.swift
// YourApp
//
// App-specific branding configurations for icons and launch screens.
//
import SwiftUI
import Bedrock
// MARK: - App Branding Colors
extension Color {
/// Your app's branding colors for icon and launch screen.
enum Branding {
/// Primary gradient color (top/leading).
static let primary = Color(red: 0.3, green: 0.5, blue: 0.8)
/// Secondary gradient color (bottom/trailing).
static let secondary = Color(red: 0.15, green: 0.3, blue: 0.5)
/// Accent color for icons and highlights.
static let accent = Color.white
}
}
// MARK: - App Icon Configuration
extension AppIconConfig {
/// Your app's icon configuration.
static let yourApp = AppIconConfig(
title: "YOUR APP",
subtitle: nil, // Optional: text below icon
iconSymbol: "star.fill", // SF Symbol name
primaryColor: Color.Branding.primary,
secondaryColor: Color.Branding.secondary,
accentColor: Color.Branding.accent
)
}
// MARK: - Launch Screen Configuration
extension LaunchScreenConfig {
/// Your app's launch screen configuration.
static let yourApp = LaunchScreenConfig(
title: "YOUR APP",
tagline: "Your tagline here",
iconSymbols: ["star.fill"],
primaryColor: Color.Branding.primary,
secondaryColor: Color.Branding.secondary,
accentColor: Color.Branding.accent
)
}
Step 2: Add Launch Screen to App Entry Point
Update your @main App struct to wrap your content with AppLaunchView.
Before
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
After
import SwiftUI
import Bedrock
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ZStack {
// Base background matching launch screen - prevents flash
Color.Branding.primary
.ignoresSafeArea()
AppLaunchView(config: .yourApp) {
ContentView()
}
}
}
}
}
What this does:
- Shows an animated launch screen for ~2 seconds
- Fades smoothly into your main content
- Creates a polished, professional app opening experience
Why the ZStack?
The AppLaunchView renders your main content underneath the launch overlay from the start. Without the base Color.Branding.primary layer, the main content's background (often white) can flash briefly before the launch screen covers it. The ZStack ensures the entire window is filled with your brand color from the first frame.
Step 3: Native Launch Screen Setup
⚠️ IMPORTANT
Do NOT rely solely on
INFOPLIST_KEY_UILaunchScreen_BackgroundColor. The generatedUILaunchScreendictionary may be empty, causing iOS to display a white screen before SwiftUI loads. Use aLaunchScreen.storyboardinstead.
To prevent a white/black flash before the SwiftUI launch screen appears, you need to configure the native iOS launch screen to match your branding.
3.1 Create LaunchScreen.storyboard
Create a new file LaunchScreen.storyboard in your app target (e.g., YourApp/Resources/LaunchScreen.storyboard) with your theme's primary surface color as the background.
Template (replace YOUR_RED, YOUR_GREEN, YOUR_BLUE with your Color.Branding.primary RGB values):
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="YOUR_RED" green="YOUR_GREEN" blue="YOUR_BLUE" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
Example for magenta/rose branding (RGB: 0.85, 0.25, 0.45):
<color key="backgroundColor" red="0.85" green="0.25" blue="0.45" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
3.2 Update Build Settings
In your target's build settings, add/update:
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen
Remove these settings if present (they are unreliable):
INFOPLIST_KEY_UILaunchScreen_BackgroundColorINFOPLIST_KEY_UILaunchScreen_BackgroundColorNameINFOPLIST_KEY_UILaunchScreen_Generation
3.3 Match SwiftUI Backgrounds
Ensure all views maintain the same background color for a seamless transition from the native launch screen to SwiftUI:
App Entry Point:
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ZStack {
// Base background matching launch screen - prevents flash
Color.Branding.primary
.ignoresSafeArea()
AppLaunchView(config: .yourApp) {
MainTabView()
}
}
}
}
}
All Root Tab/Screen Views:
struct ContentView: View {
var body: some View {
YourContent()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.Branding.primary.ignoresSafeArea())
}
}
Why Storyboard Over Generated Launch Screen?
The GENERATE_INFOPLIST_FILE = YES setting with INFOPLIST_KEY_UILaunchScreen_BackgroundColor does not reliably populate the UILaunchScreen.UIColorName key in the generated Info.plist. When this happens, iOS falls back to white (or black in dark mode).
A LaunchScreen.storyboard guarantees your color from the first frame because:
- The color is embedded directly in the storyboard file
- No runtime lookup of asset catalog colors is needed
- Works consistently across all iOS versions
Important: After making these changes:
- Clean build (Cmd+Shift+K)
- Delete app from simulator/device
- Build and run again
Step 4: Add Branding Tools to Settings (Optional)
Add debug tools to your settings view for generating and previewing icons during development.
Add to SettingsView
import SwiftUI
import Bedrock
struct SettingsView: View {
var body: some View {
NavigationStack {
List {
// ... your normal settings ...
#if DEBUG
Section("Debug") {
NavigationLink("Icon Generator") {
IconGeneratorView(config: .yourApp, appName: "YourApp")
}
NavigationLink("Branding Preview") {
BrandingPreviewView(
iconConfig: .yourApp,
launchConfig: .yourApp,
appName: "YourApp"
)
}
}
#endif
}
}
}
}
Important: Wrap in #if DEBUG so these tools are excluded from App Store builds.
Step 5: Generate Your App Icon
Using IconGeneratorView (Recommended)
- Build and run your app in DEBUG mode
- Open Settings → Debug section
- Tap "Icon Generator"
- Tap "Generate & Save Icon"
- Wait for confirmation: "✅ Icon saved to Documents folder!"
Retrieve the Icon
On Simulator:
- Open Finder
- Go to:
~/Library/Developer/CoreSimulator/Devices/ - Find your simulator device folder (sorted by date)
- Navigate to:
data/Containers/Data/Application/[YourApp-UUID]/Documents/ - Copy
AppIcon.png
On Physical Device:
- Open Files app on your device
- Navigate to: On My iPhone → YourApp
- Find
AppIcon.png - AirDrop or share to your Mac
Alternative (Xcode):
- Go to Window → Devices and Simulators
- Select your device/simulator
- Find your app → Click ⚙️ gear → Download Container
- Right-click downloaded file → Show Package Contents
- Navigate to
AppData/Documents/and copyAppIcon.png
Step 6: Add Icon to Xcode Assets
- Open your Xcode project
- Navigate to
Assets.xcassets→AppIcon - Drag
AppIcon.pnginto the 1024×1024 slot - Xcode automatically generates all required sizes
Verify:
- Clean build and run
- Check home screen for new icon
- If unchanged, delete app and reinstall
Configuration Reference
AppIconConfig
| Property | Type | Default | Description |
|---|---|---|---|
title |
String |
Required | App name (uppercase recommended) |
subtitle |
String? |
nil |
Optional text below icon |
iconSymbol |
String |
Required | SF Symbol name |
primaryColor |
Color |
Blue | Top-left gradient color |
secondaryColor |
Color |
Dark blue | Bottom-right gradient color |
accentColor |
Color |
Light blue | Icon and text highlight color |
LaunchScreenConfig
| Property | Type | Default | Description |
|---|---|---|---|
title |
String |
Required | App name displayed on launch |
subtitle |
String? |
nil |
Large text (like "PRO" or version) |
tagline |
String? |
nil |
Small text at bottom of screen |
iconSymbols |
[String] |
["star.fill"] |
Array of SF Symbol names |
cornerSymbol |
String? |
nil |
Symbol for corner decorations (nil = none) |
decorativeSymbol |
String? |
"circle.fill" |
Symbol in decorative line (nil = hide line) |
patternStyle |
LaunchPatternStyle |
.dots |
Background pattern style |
layoutStyle |
LaunchLayoutStyle |
.iconAboveTitle |
Content layout arrangement |
primaryColor |
Color |
Blue-gray | Top gradient color |
secondaryColor |
Color |
Dark blue | Bottom gradient color |
accentColor |
Color |
Light blue | Icons and highlights |
titleColor |
Color |
.white |
Title text color |
iconSize |
CGFloat |
48 |
Size of icon symbols |
titleSize |
CGFloat |
42 |
Size of title text |
subtitleSize |
CGFloat |
72 |
Size of subtitle text |
iconSpacing |
CGFloat |
8 |
Spacing between icons |
animationDuration |
Double |
0.6 |
Fade-in animation duration |
showLoadingIndicator |
Bool |
false |
Show spinner at bottom |
LaunchPatternStyle
| Value | Description |
|---|---|
.none |
Clean background, no pattern |
.dots |
Subtle dot pattern (default) |
.grid |
Grid lines pattern |
.radial |
Radial gradient glow from center |
LaunchLayoutStyle
| Value | Description |
|---|---|
.iconAboveTitle |
Icons at top, title below (default) |
.titleAboveIcon |
Title at top, icons below |
.iconOnly |
Only show icons, no text |
.titleOnly |
Only show text, no icons |
Complete Example
Here's a full example for a camera app:
File: YourApp/Shared/BrandingConfig.swift
import SwiftUI
import Bedrock
// MARK: - App Branding Colors
extension Color {
enum Branding {
// Vibrant magenta/rose gradient
static let primary = Color(red: 0.85, green: 0.25, blue: 0.45)
static let secondary = Color(red: 0.45, green: 0.12, blue: 0.35)
static let accent = Color.white
}
}
// MARK: - App Icon Configuration
extension AppIconConfig {
static let myCamera = AppIconConfig(
title: "CAMERA",
subtitle: "PRO",
iconSymbol: "camera.fill",
primaryColor: Color.Branding.primary,
secondaryColor: Color.Branding.secondary,
accentColor: Color.Branding.accent
)
}
// MARK: - Launch Screen Configuration
extension LaunchScreenConfig {
static let myCamera = LaunchScreenConfig(
title: "CAMERA PRO",
tagline: "Capture the Moment",
iconSymbols: ["camera.fill", "sparkles"],
cornerSymbol: "sparkle", // Sparkles in corners
decorativeSymbol: "circle.fill", // Circle in decorative line
patternStyle: .radial, // Radial glow effect
layoutStyle: .iconAboveTitle,
primaryColor: Color.Branding.primary,
secondaryColor: Color.Branding.secondary,
accentColor: Color.Branding.accent,
titleColor: .white,
iconSize: 52,
titleSize: 38,
iconSpacing: 12,
animationDuration: 0.6
)
}
File: YourApp/App/MyCameraApp.swift
import SwiftUI
import Bedrock
@main
struct MyCameraApp: App {
var body: some Scene {
WindowGroup {
ZStack {
// Base background matching launch screen - prevents flash
Color.Branding.primary
.ignoresSafeArea()
AppLaunchView(config: .myCamera) {
ContentView()
}
}
}
}
}
Troubleshooting
White/black flash before launch screen
Cause: iOS system launch screen doesn't match your branding colors, or the generated UILaunchScreen dictionary is not being populated correctly.
Solution:
- Use a
LaunchScreen.storyboardinstead of relying onINFOPLIST_KEY_UILaunchScreen_BackgroundColor(see Step 3) - Wrap
AppLaunchViewin aZStackwithColor.Branding.primaryas the base layer (Step 2) - Ensure the RGB values in the storyboard match exactly with
Color.Branding.primary - Remove any
INFOPLIST_KEY_UILaunchScreen_*settings from your project
Critical: After any launch screen changes:
- Clean build (Cmd+Shift+K)
- Delete app from simulator/device completely
- Quit and restart the simulator
- Build and run fresh
iOS caches the launch screen aggressively.
Generated UILaunchScreen not working
Cause: The INFOPLIST_KEY_UILaunchScreen_BackgroundColor and INFOPLIST_KEY_UILaunchScreen_Generation settings do not reliably populate the UILaunchScreen dictionary in the generated Info.plist.
Solution: Use a LaunchScreen.storyboard instead. This is the only reliable method to ensure your launch screen color appears from the first frame. See Step 3.
Can't find types like AppIconConfig
Solution: Make sure you have import Bedrock at the top of your file.
Launch screen doesn't appear
Solution:
- Verify
AppLaunchViewwraps your content in the App struct - Check that you're using the correct config name (e.g.,
.myCamera) - Ensure the config extension is defined in
BrandingConfig.swift
Icon looks different than preview
Explanation: iOS applies a superellipse mask to all app icons.
Solution: Don't add your own rounded corners—iOS does this automatically.
"Icon saved" but can't find file
Solution:
- Open Files app on device/simulator
- Navigate to: On My iPhone/iPad → [Your App Name]
- If folder doesn't exist, the app may need Files access
Alternative: Use Xcode's Devices and Simulators window to download the app container.
Icon doesn't update in simulator
Solution:
- Clean build folder: Product → Clean Build Folder (Cmd+Shift+K)
- Delete app from simulator
- Rebuild and run
DEBUG section not showing in settings
Solution:
- Ensure you're running a DEBUG build (not Release)
- Check that code is wrapped in
#if DEBUG ... #endif - Verify your settings view is inside a
NavigationStack
Color Palette Ideas
Professional Blue
primaryColor: Color(red: 0.15, green: 0.30, blue: 0.55)
secondaryColor: Color(red: 0.08, green: 0.15, blue: 0.30)
accentColor: .white
Vibrant Pink/Magenta
primaryColor: Color(red: 0.85, green: 0.25, blue: 0.45)
secondaryColor: Color(red: 0.45, green: 0.12, blue: 0.35)
accentColor: .white
Nature Green
primaryColor: Color(red: 0.20, green: 0.55, blue: 0.35)
secondaryColor: Color(red: 0.10, green: 0.30, blue: 0.20)
accentColor: Color(red: 0.85, green: 0.95, blue: 0.85)
Warm Orange/Gold
primaryColor: Color(red: 0.95, green: 0.60, blue: 0.20)
secondaryColor: Color(red: 0.70, green: 0.35, blue: 0.10)
accentColor: .white
Dark/Minimal
primaryColor: Color(red: 0.12, green: 0.12, blue: 0.15)
secondaryColor: .black
accentColor: .white
patternStyle: .none
SF Symbol Recommendations
Photography/Camera
camera.fill,camera.circle.fillphoto.fill,photo.stack.fillsparkles,wand.and.stars
Social/Communication
message.fill,bubble.left.fillperson.fill,person.2.fillheart.fill,star.fill
Productivity
doc.fill,folder.fillcheckmark.circle.fillcalendar,clock.fill
Music/Media
music.note,waveformplay.fill,headphonesmic.fill,speaker.wave.2.fill
Utility
gearshape.fill,wrench.fillmagnifyingglass,location.fillbolt.fill,battery.100
Definitive Best Practices
To ensure every app satisfies the highest quality standards for launch and legibility:
- Launch Screen: Always use the
LaunchScreen.storyboard(Step 3). Info.plist background colors alone are unreliable and cause a white flash. - Base Layer: Wrap your App's root view in a
ZStackwith aColormatching your launch screen as the bottom-most layer. - Color Scheme: If utilizing a dark theme, always apply
.preferredColorScheme(.dark)to your root view to prevent black semantic text colors.
Summary Checklist
Branding Configuration
- Create
BrandingConfig.swiftwith your app's configurations - Define
Color.Branding.primary,.secondary, and.accent - Create
AppIconConfigextension for your app - Create
LaunchScreenConfigextension for your app
Launch Screen Setup
- Create
LaunchScreen.storyboardwith your brand color (Step 3.1) - Add
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreento build settings - Remove any
INFOPLIST_KEY_UILaunchScreen_*settings if present - Verify RGB values in storyboard match
Color.Branding.primaryexactly
SwiftUI Integration
- Add
AppLaunchViewwrapper to your App entry point - Wrap in ZStack with
Color.Branding.primaryas base layer - Add matching background to all root tab/screen views
- Clean build, delete app, and reinstall to test launch screen
App Icon
- (Optional) Add debug section to settings with
IconGeneratorViewandBrandingPreviewView - Build and run in DEBUG mode
- Generate icon using Icon Generator tool
- Retrieve icon PNG from device/simulator
- Add 1024×1024 PNG to
Assets.xcassets/AppIcon - Clean build and reinstall to verify icon
Happy Branding! 🎨✨