Home > Developer Guide > Guides > iOS Firebase Setup
iOS Firebase Setup Guide
Purpose: Configure Firebase for iOS development and understand the initialization patterns used in the app
Context: Documented during iOS Phase 2 build error resolution (PR #278)
Impact: Proper Firebase setup prevents runtime crashes and enables Firestore functionality
Overview
The Archery Apprentice iOS app uses Firebase Firestore for backend data storage. This guide covers:
- Required files and configuration
- Firebase initialization patterns
- Error handling approaches
- Development workflow considerations
Prerequisites
- Xcode installed
- CocoaPods or Swift Package Manager configured
- Access to Firebase project (or ability to create one)
- iOS app bundle ID configured
Required Files
1. GoogleService-Info.plist
Purpose: Contains Firebase project configuration (API keys, project ID, bundle ID mappings)
Location: iosApp/ArcheryApprentice/GoogleService-Info.plist
Why It’s Not in the Repository:
- Contains sensitive Firebase configuration
- Gitignored for security (
.gitignoreentry:GoogleService-Info.plist) - Each developer may use different Firebase projects (dev/staging/prod)
How to Obtain:
- Go to Firebase Console
- Select your project (or create a new one)
- Navigate to Project Settings → General
- Scroll to “Your apps” section
- Click on iOS app (or add iOS app if not exists)
- Download
GoogleService-Info.plist
How to Add to Xcode:
- Download
GoogleService-Info.plist - Open Xcode project:
iosApp/ArcheryApprentice/ArcheryApprentice.xcworkspace - Drag
GoogleService-Info.plistinto Xcode project navigator - Ensure “Copy items if needed” is checked
- Ensure target “ArcheryApprentice” is selected
- Build and run
2. Firebase SDK Dependencies
Already Configured in the project via CocoaPods/SPM:
FirebaseCore- Core Firebase functionalityFirebaseFirestore- Cloud Firestore databaseFirebaseAuth- User authentication
No additional installation needed - these are managed by the build system.
Firebase Initialization Pattern
The app uses a graceful initialization pattern that prevents crashes when Firebase is not configured.
App Entry Point (ArcheryApprenticeApp.swift)
import SwiftUI
import FirebaseCore
@main
struct ArcheryApprenticeApp: App {
init() {
// Attempt to configure Firebase if not already configured
if FirebaseApp.app() == nil {
FirebaseApp.configure()
}
}
var body: some Scene {
WindowGroup {
// Check if Firebase is available before showing main UI
if FirebaseApp.app() != nil {
ContentView()
} else {
// Show configuration instructions instead of crashing
VStack(spacing: 20) {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 60))
.foregroundColor(.orange)
Text("Firebase Configuration Required")
.font(.title)
.fontWeight(.bold)
Text("To use tournament features, add GoogleService-Info.plist to the Xcode project:")
.multilineTextAlignment(.center)
.padding(.horizontal)
VStack(alignment: .leading, spacing: 8) {
Text("1. Download GoogleService-Info.plist from Firebase Console")
Text("2. Drag the file into Xcode project navigator")
Text("3. Ensure 'Copy items if needed' is checked")
Text("4. Rebuild and run the app")
}
.font(.subheadline)
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(8)
}
.padding()
}
}
}
}Key Points:
- ✅ Uses
if/elseinstead ofguard/returnto allow WindowGroup to render - ✅ App launches successfully even without Firebase
- ✅ Shows clear error message with setup instructions
- ✅ No crashes, graceful degradation
ViewModel Firebase Availability Checks
Each ViewModel that uses Firestore should check Firebase availability before attempting queries.
Pattern:
import FirebaseCore
import FirebaseFirestore
import FirebaseAuth
@MainActor
class TournamentListViewModel: ObservableObject {
@Published var tournaments: [Tournament] = []
@Published var isLoading: Bool = false
@Published var errorMessage: String? = nil
func loadTournaments() {
// Check Firebase availability first
guard FirebaseApp.app() != nil else {
self.errorMessage = "Firebase not configured. Add GoogleService-Info.plist to project."
self.isLoading = false
return
}
// Firebase is available, proceed with query
isLoading = true
errorMessage = nil
let db = Firestore.firestore()
db.collection("tournaments")
.getDocuments { [weak self] (snapshot, error) in
// Handle query results...
}
}
}Applied in:
TournamentListViewModel.swift- Tournament list loadingTournamentDetailViewModel.swift- Tournament detail loading, join/leave operations
Benefits:
- Prevents crashes when Firebase not configured
- Provides clear user feedback
- Allows development without Firebase (mocking, UI testing)
- Graceful error handling
Development Workflow
Scenario 1: First Time Setup
# 1. Clone repository
git clone https://github.com/blamechris/archery-apprentice.git
cd archery-apprentice
# 2. Build shared KMP framework
./gradlew :shared:domain:podGenIOS
# 3. Install iOS dependencies
cd iosApp/ArcheryApprentice
pod install # or Swift Package Manager resolve
# 4. Open Xcode workspace
open ArcheryApprentice.xcworkspace
# 5. Add GoogleService-Info.plist
# - Download from Firebase Console
# - Drag into Xcode project
# - Ensure "Copy items if needed" is checked
# 6. Build and run
# - Select target device/simulator
# - Cmd+R to build and runScenario 2: Working Without Firebase
If you want to work on UI features without Firebase:
Option A: App shows configuration message
- Firebase check fails gracefully
- App shows setup instructions
- Can still test non-Firebase features
Option B: Use mock data
- Create mock ViewModels with hardcoded data
- Swap in ContentView for testing
- No Firebase calls attempted
Common Issues & Solutions
Issue 1: “Firebase not configured” at Runtime
Symptom: App shows Firebase configuration required message
Cause: Missing GoogleService-Info.plist
Solution:
- Download
GoogleService-Info.plistfrom Firebase Console - Add to Xcode project (drag and drop)
- Ensure “Copy items if needed” is checked
- Rebuild app
Issue 2: Build Succeeds But Crashes on Launch
Symptom: App builds successfully but crashes immediately when running
Cause: Firebase SDK not initialized, or initialization logic uses guard/return preventing WindowGroup from rendering
Solution: Verify ArcheryApprenticeApp.swift uses the pattern shown above:
// ✅ CORRECT - Uses if/else
if FirebaseApp.app() != nil {
ContentView()
} else {
// Show error message
}
// ❌ WRONG - Uses guard/return
guard FirebaseApp.app() != nil else {
return AnyView(Text("Error")) // WindowGroup never reached
}Issue 3: Firebase Queries Return Empty Results
Symptom: App runs, Firebase configured, but queries return no data
Possible Causes:
- Wrong Firebase project: Using dev project but querying prod data (or vice versa)
- Firestore rules: Security rules preventing read access
- Collection names: Querying wrong collection name
- Network connectivity: Device/simulator can’t reach Firebase
Debugging:
// Add logging to see what's happening
func loadTournaments() {
guard FirebaseApp.app() != nil else { return }
let db = Firestore.firestore()
print("Firebase project ID: \(FirebaseApp.app()?.options.projectID ?? "unknown")")
db.collection("tournaments")
.getDocuments { (snapshot, error) in
if let error = error {
print("Firestore error: \(error.localizedDescription)")
} else {
print("Retrieved \(snapshot?.documents.count ?? 0) documents")
}
}
}Issue 4: Multiple Firebase Apps Configured
Symptom: Warning “Firebase app named __FIRAPP_DEFAULT already exists”
Cause: FirebaseApp.configure() called multiple times
Solution: Check before configuring (already implemented):
init() {
if FirebaseApp.app() == nil {
FirebaseApp.configure()
}
}Security Considerations
GoogleService-Info.plist
DO NOT:
- ❌ Commit
GoogleService-Info.plistto git - ❌ Share the file publicly
- ❌ Use production Firebase config in development
DO:
- ✅ Keep file in
.gitignore - ✅ Use separate Firebase projects for dev/staging/prod
- ✅ Rotate API keys if accidentally exposed
- ✅ Configure Firestore security rules appropriately
Firestore Security Rules
Production Security Rules (example):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Tournaments: public read, authenticated write
match /tournaments/{tournamentId} {
allow read: if true;
allow create: if request.auth != null;
allow update, delete: if request.auth.uid == resource.data.createdBy;
}
}
}Development Security Rules (more permissive for testing):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// WARNING: Only use for development!
match /{document=**} {
allow read, write: if true;
}
}
}Testing Firebase Integration
Manual Testing Checklist
- App launches without Firebase configured (shows error message)
- App launches with Firebase configured (shows ContentView)
- TournamentListView loads tournaments from Firestore
- TournamentDetailView displays tournament details
- Join tournament operation succeeds
- Leave tournament operation succeeds
- Error messages display correctly when Firebase unavailable
Automated Testing (Future Enhancement)
Consider adding:
- Unit tests with mock Firebase SDK
- Integration tests with Firebase emulator
- UI tests with stubbed network responses
Related Documentation
Session Documentation:
- 2025-11-18-ios-phase2-build-fixes - Session where Firebase initialization issues were discovered and fixed
Architecture Documentation:
- week-28-ios-firebase-integration - Overall iOS Firebase integration architecture
- week-17-ios-viewmodels - iOS ViewModel patterns
Interop Documentation:
- kotlin-swift-interop - Type conversion patterns for Firebase data
External Resources:
- Firebase iOS Setup - Official Firebase iOS documentation
- Firestore iOS Guide - Getting started with Firestore on iOS
Summary
Firebase setup for iOS requires:
- ✅
GoogleService-Info.plistadded to Xcode project - ✅ Graceful initialization in
ArcheryApprenticeApp.swift - ✅ Firebase availability checks in ViewModels
- ✅ Proper error handling throughout
The app is designed to work gracefully without Firebase, showing clear setup instructions instead of crashing. This allows development to continue even when Firebase is not configured.
Last Updated: 2025-11-18 Related PR: #278 (iOS Phase 2 build error fixes)