# Ha IOS Architecture

> Home Assistant iOS project layout, build setup, and the "World" dependency-injection pattern. Use when starting work in the repo, deciding where code lives across targets (App, Shared, Watch, CarPlay, Extensions), accessing dependencies through the global `Current`, or setting up dependencies and code signing.

- Skill: `home-assistant/ha-ios-architecture` (Agent Skill)
- Install (CLI): `npx skillmds@latest add home-assistant/ha-ios-architecture`
- Raw SKILL.md: https://api.skillmd.com/api/skills/home-assistant/ha-ios-architecture/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: home-assistant (https://skillmd.com/u/home-assistant)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/home-assistant/ha-ios-architecture

---


# Architecture & Project Layout

Home Assistant for Apple Platforms is a native Swift companion app for [Home Assistant](https://www.home-assistant.io/) home automation. The primary user interaction is through a `WKWebView` displaying the Home Assistant web frontend, with native features for notifications, sensors, location tracking, widgets, CarPlay, Apple Watch, and more.

- **Language**: Swift 5.8+
- **Platforms**: iOS, watchOS, macOS (Catalyst), CarPlay
- **Build System**: Xcode 26.2+, Swift Package Manager
- **Project**: Open `HomeAssistant.xcodeproj` directly (dependencies are managed via Swift Package Manager)

## Getting Started

### Install Dependencies

```bash
bundle install
```

> Third-party dependencies are managed via Swift Package Manager (SPM) and resolved automatically by Xcode. `bundle install` installs the Ruby tooling (Fastlane) used for linting, testing, and CI.

### Code Signing (for device builds)

Create `Configuration/HomeAssistant.overrides.xcconfig` (git-ignored):

```
DEVELOPMENT_TEAM = YourTeamID
BUNDLE_ID_PREFIX = some.bundle.prefix
```

## Project Structure

```
Sources/
├── App/              # Main iOS app target
├── Shared/           # Shared code across all platforms
├── Watch/            # watchOS-specific code
├── WatchApp/         # watchOS app target
├── MacBridge/        # macOS Catalyst bridge
├── CarPlay/          # CarPlay integration
├── Extensions/       # App Extensions (widgets, notifications, intents)
├── Improv/           # Improv BLE provisioning
├── PushServer/       # Push notification server communication
├── SharedPush/       # Shared push notification handling
├── SharedTesting/    # Shared testing utilities
├── Thread/           # Thread network support
├── Launcher/         # App launcher helper
Tests/
├── App/              # App-level tests
├── Shared/           # Shared module tests
├── UI/               # UI tests
├── Widgets/          # Widget tests
├── Mocks/            # Mock objects for testing
Configuration/        # Xcode build configuration files
fastlane/             # Fastlane automation (build, test, deploy)
Tools/                # Build tools, icon generation
```

## The "World" Pattern (Dependency Injection)

This project uses the **"World" pattern** for dependency injection, inspired by [Point-Free's "How to Control the World"](https://www.pointfree.co/blog/posts/21-how-to-control-the-world). This is the most important architectural concept in the codebase.

### How It Works

A single global `Current` variable of type `AppEnvironment` holds all dependencies as mutable properties:

```swift
// Sources/Shared/Environment/Environment.swift
public var Current: AppEnvironment { ... }

public class AppEnvironment {
    public var date: () -> Date = Date.init
    public var calendar: () -> Calendar = { Calendar.autoupdatingCurrent }
    public var servers: ServerManager = ServerManagerImpl()
    public var clientEventStore: ClientEventStoreProtocol = ClientEventStore()
    // ... many more dependencies
}
```

### Usage in Production Code

Access dependencies through `Current`:

```swift
let now = Current.date()
let server = Current.servers.all.first
Current.Log.info("Something happened")
```

### Usage in Tests

Override dependencies for testing:

```swift
Current.date = { Date(timeIntervalSince1970: 1000000) }
Current.servers = FakeServerManager()
```

### ⚠️ Critical Rule

**Never assign to `Current.*` properties outside of test code.** This is enforced by a custom SwiftLint rule that will fail CI. In production code, only _read_ from `Current`.

### Beta-Only Features

`Current.isTestFlight` is the only supported way to limit a feature to beta builds — no bespoke flags, build settings, or `#if` branches. Every gate must be paired with a draft PR that removes it; see the `ha-ios-workflow-ci` skill for the procedure.

## Additional Resources

- [Home Assistant Developer Docs (Apple)](https://developers.home-assistant.io/docs/apple/)
- [Contributing Guidelines](../../../CONTRIBUTING.md)
- [Point-Free: How to Control the World](https://www.pointfree.co/blog/posts/21-how-to-control-the-world)

