Case study · Apple ecosystem

HeyWeather

A weather app built once and shipped four times: one Swift codebase spanning iPhone, Apple Watch, macOS, and visionOS, with widgets and Live Activities off its own data pipeline.

Role
Lead iOS Engineer (Contract) · GCO Apps
Platform
iPhone · Apple Watch · macOS · visionOS
Stack
Swift · SwiftUI · WidgetKit · ActivityKit
Scale
4 platforms · 1 shared Swift codebase
Overview

Four platforms, one codebase.

HeyWeather ships across iPhone, Apple Watch, macOS, and visionOS from a single Swift codebase. Shared domain logic and a shared data pipeline sit underneath, with platform-native UI on top of each. I led the engagement for GCO Apps as a contract Lead iOS Engineer: the cross-platform architecture, and the WidgetKit widgets, Live Activities, and Dynamic Island integrations built on top of the app's own data pipeline.

The problem

A weather app is judged by four completely different surfaces at once: a full app on iPhone, a glanceable complication on the Watch, a menu-bar-adjacent presence on macOS, and a spatial one on visionOS. Building each natively from scratch would mean four codebases quietly drifting apart on the same underlying forecast. The brief was to reach all four platforms without paying for four separate implementations of the same product.

Constraints

  • Four platforms, one small contract team — no capacity to hand-roll separate business logic per target.
  • Genuinely different presentation idioms. A Watch complication, a macOS window, and a visionOS surface don't share a UI model. Sharing stopped at domain logic; the UI on each platform stayed native.
  • WidgetKit and ActivityKit's own rules. Widgets, Live Activities, and Dynamic Island each impose refresh and lifecycle constraints the shared pipeline has to respect no matter which platform is asking.
  • A contract engagement. The codebase had to be legible enough for GCO Apps' own team to take over after handoff. That mattered more than how quickly I alone could build it.
Architecture

The pipeline behind every surface.

Domain logic and the data pipeline live in a shared Swift layer. Every platform target, and every system surface built on top of it, reads from the same place.

HeyWeather architecture: four platform UI layers (iPhone, Apple Watch, macOS, visionOS) sit on a shared Swift core of domain models and a data pipeline, which also drives WidgetKit widgets and ActivityKit Live Activities and Dynamic Island. PLATFORM UI iPhone app Apple Watch macOS visionOS SHARED SWIFT CORE Domain models Data pipeline SYSTEM SURFACES WidgetKit widgets Live Activities · Dynamic Island
Every platform target and every system surface reads from the same domain models and data pipeline. A forecast bug has exactly one place it can live.
Engineering decisions

What stayed shared, what stayed native.

01

Shared core, native UI on each platform

Domain models and the data pipeline live in a shared Swift layer; every platform target builds its own UI on top in its own idiom. The boundary sits between domain logic and presentation. There's no single UI stretched across four radically different interaction models.

02

Widgets and Live Activities read the app's real pipeline

WidgetKit widgets and ActivityKit's Live Activities and Dynamic Island integrations consume the same data pipeline the app itself uses. There's no simplified, parallel source that could quietly drift from what the app actually shows.

03

Handoff shaped the architecture

As a contract engagement, the architecture was shaped so GCO Apps' own team could pick up ownership cleanly after delivery — a different bar than optimizing purely for one engineer's solo velocity.

Trade-offs

What sharing a core actually costs.

A shared core over four native implementations

One place to fix a forecast bug, with consistent behavior guaranteed across every platform instead of merely hoped for.

The cost

The boundary between shared logic and platform UI needs constant discipline. It's easy for a platform-specific shortcut to start leaking into code every other target depends on.

Widgets sharing the app's real pipeline

What a widget or Live Activity shows always matches what the app itself would show, with no separate source of truth to fall out of sync.

The cost

The shared pipeline has to respect WidgetKit's and ActivityKit's stricter memory and refresh budgets even when it's running inside the main app rather than inside an extension.

Handoff-ready architecture over solo velocity

The client's own team could take over ownership cleanly once the contract ended.

The cost

Slower to build than fully undocumented, move-fast solo iteration would have been. Legibility for a future owner was a real, paid-for requirement, not a nice-to-have.

Technical challenges

Four platforms don't share an interaction model.

Finding where sharing actually stops

The genuinely hard design question wasn't the data pipeline: it was deciding exactly where the shared layer ends and platform-specific presentation begins, without over-abstracting UI that legitimately differs between a Watch complication and a visionOS window.

Building against a moving platform surface

Live Activities and Dynamic Island were still relatively new system surfaces during this engagement, with real refresh and update constraints imposed by the OS rather than the app.

Designing for a handoff that hadn't happened yet

Structuring a contract build so a client team could take over ownership meant writing the shared core for a future reader. That's a different discipline than optimizing purely for one engineer's solo speed.

Reach

What one codebase covered.

4
Apple platforms
iPhone, Apple Watch, macOS, and visionOS, shipped from the same Swift codebase.
1
Shared data pipeline
The same pipeline feeds the app, its widgets, and its Live Activities and Dynamic Island.
2023–24
Contract engagement
Lead iOS Engineer for GCO Apps, architecture through handoff.
Privacy considerations

A weather app still touches location.

Any weather app has to treat location as sensitive by default. On this engagement, that meant relying on platform-provided location APIs rather than a custom location pipeline, and keeping the widget and Live Activity surfaces reading from the same on-device data path as the app. No separate collection point was introduced purely for a system extension. Deeper backend-side privacy specifics belonged to GCO Apps and aren't mine to publish here.

Engineering journal

A contract, phase by phase.

2023 · Kickoff

Engagement starts, core architecture first

Joined GCO Apps as contract Lead iOS Engineer, and began with the shared Swift core (domain models and the data pipeline) before touching any platform-specific UI.

2023 · Build

iPhone and Apple Watch ship first

The primary app and Watch complications were the first two surfaces built against the shared core, establishing the domain/UI boundary every later platform would follow.

2024 · Extension

macOS and visionOS join

Extended the same shared core to macOS and visionOS: new presentation layers, no changes to the underlying domain logic.

2024 · Build

WidgetKit, Live Activities, Dynamic Island

Delivered widgets and ActivityKit-based Live Activities and Dynamic Island integrations, wired to the app's own data pipeline rather than a simplified feed.

2024 · Handoff

Engagement closes

Delivered the codebase structured for GCO Apps' own team to own going forward. That was the contract's explicit success condition.

Lessons learned

What four platforms taught.

  • Share logic, not interaction models. The temptation to abstract UI across platforms is real; the platforms that make it worth resisting are the ones with genuinely different idioms. A Watch complication was never going to be a small iPhone screen.
  • System surfaces should never have their own data source. A widget that reads a "simplified" feed instead of the app's real pipeline is a drift bug waiting to happen.
  • Handoff is a requirement, not a courtesy. Building for a future owner changes real decisions: naming, boundaries, documentation, made well before anything ships.
Outcome

Four platforms, delivered and handed off.

HeyWeather shipped across iPhone, Apple Watch, macOS, and visionOS from one Swift codebase between 2023 and 2024, with WidgetKit widgets and ActivityKit Live Activities and Dynamic Island integrations built on the app's own data pipeline rather than a separate feed. The engagement closed with the architecture handed to GCO Apps' own team — the measure of success for a contract like this one.