MTA Helper is a SwiftUI application that surfaces nearby New York City subway stations, real-time train arrivals, and active MTA service alerts. The app combines the rider's current location with GTFS real-time feeds published by the MTA to present a dashboard of the closest stations, per-line countdowns, and alerts that impact each stop.
- Location-aware station discovery – The app requests the rider's current location, handles the various Core Location authorization flows, and continuously updates as permission changes.【F:mtahelper/mtahelper/Services/LocationService.swift†L24-L102】 Nearby stations are identified with a configurable radius and fallbacks when no stops are in range.
- Real-time arrivals – The
RealtimeServicedownloads the appropriate GTFS feeds for the lines that serve the nearby stations, parses the protobuf payload, and returns the next arrivals per line. - Service alert integration – Current subway alerts are fetched, decoded, and merged into the station and line presentation so riders can see relevant advisories alongside countdowns.
- Polished SwiftUI dashboard – The main view renders station cards, line rows, refresh affordances, and empty states tailored to the data phase, with auto-refresh and relative timestamp updates managed by the view model.
MTAHelper/
└── mtahelper/
├── Models/ // Station and alert domain types
├── Resources/ // Bundled station metadata JSON files
├── Services/ // Networking, location, and repository layers
├── Utilities/ // GTFS protobuf decoder & appearance helpers
├── ViewModels/ // Presentation logic for the dashboard
└── Views/ // SwiftUI screens and components
Key components include:
StationRepositoryfor loading bundled station metadata and resolving stop IDs to parent stations.RealtimeServicefor selecting the required MTA GTFS feeds per line and gathering the next arrivals.AlertServicefor retrieving the subway alerts feed and normalizing it intoServiceAlertmodels.SubwayDashboardViewModelfor orchestrating location lookup, data fetches, periodic refreshes, and error handling.SubwayDashboardViewfor the SwiftUI presentation of cards, line rows, and alert summaries.
The app relies on two categories of data:
- Bundled reference data – Static JSON files (
subway_stations.jsonandstop_parent.json) are packaged with the app to describe station metadata and stop-to-parent-station relationships. - Live MTA feeds – Real-time subway arrivals are loaded from the MTA GTFS endpoints selected per line, and service alerts are fetched from the MTA alerts feed.
Note: The MTA GTFS endpoints require a developer API key supplied via the
x-api-keyheader. You can set this globally by configuringURLSessionConfiguration.default.httpAdditionalHeadersearly in the app lifecycle or by injecting a customURLSessionintoRealtimeServiceandAlertServicethat adds the header to each request.
-
Prerequisites
- Xcode 15 or later with the latest iOS SDK.
- An MTA developer API key (https://api.mta.info/).
-
Configure API access
- Add the
x-api-keyheader with your key before the first network request. One option is to customizeURLSessionConfiguration.defaultinmtahelperAppor to provide your ownURLSessioninstance when constructing the services.
- Add the
-
Run the app
- Open
mtahelper.xcodeprojin Xcode. - Select the
mtahelpertarget and configure your signing team if building for a device. - Build and run on an iOS simulator or a location-capable device. Grant “While Using” location access when prompted so nearby stations can be discovered.
- Open
SubwayDashboardViewModelexposes amaximumDistanceproperty that can be tweaked to expand or restrict the search radius during debugging.- The view model schedules an automatic refresh every 60 seconds. You can adjust this cadence inside
startAutoRefresh()if you need more or less frequent updates. - The GTFS parser is self-contained in
GTFSRealtimeParser.swiftif you need to extend support for other feed entities or additional fields.
The app only requests precise location while in use to calculate nearby stations. If the user denies permission, an explanatory message is displayed and the dashboard remains accessible, though without localized arrivals.【