A native iOS app for real-time Boston MBTA subway and light rail arrivals, smart commute planning, and proactive notifications — so you never miss your train.
Real-Time Arrivals
- Live predictions merged with published schedule data — predictions take priority, schedules fill gaps
- Destination-based direction filtering (not just inbound/outbound) to handle multi-destination stops like Arlington
- Auto-refresh every 30 seconds with smart rate limiting to avoid duplicate API calls
- Pull-to-refresh with manual rate limiting (30s cooldown)
- Sibling stop ID joining — queries all platform stop IDs at a station so both directions show up at surface-level Green Line stops
Locate Nearest Station
- One-tap GPS-based station finding using CoreLocation
- Optimized API usage: fetches all subway/light rail stops in a single request (
filter[route_type]=0,1) instead of looping per-route, staying well under the MBTA API's unauthenticated rate limit
Smart Commute Planning
- Save daily commutes with route, stop, direction, arrival deadline, and active days
- Automatic leave-by time calculation based on total travel time
- Commute card on the home screen shows minutes until you need to leave, with the recommended train highlighted
- Train selection logic: picks the 2 trains before and 1 train after your deadline so you can see your options
Proactive Notifications
- Schedules notifications up to 7 days in advance using MBTA schedule data
- Embeds actual train departure times directly into notification content — notifications work even when the app is completely closed
- When the app is open, live predictions upgrade the notification with more accurate times
- Personalized greetings based on time of day and user name
- Background task scheduling targets notification times for timely refresh
Home Screen & Lock Screen Widgets
- 5 widget sizes: small, medium, large (home screen), circular, rectangular (lock screen)
- Shared data via App Groups between main app and widget extension
- Interactive widget intents for refresh and "near me" actions
- Rate-limited refresh coordination between app and widget to prevent duplicate API calls
Favorites & Persistence
- Save and load favorite route/stop combinations
- Remembers last selected route and stop across app launches
- Onboarding flow with name input and notification permission request
The app uses MVVM with SwiftUI and is organized into four layers:
MBTALive/
├── Models — Data types (TrainArrival, Commute, Favorite, predictions/schedules)
├── Services — API client, location, notifications, background tasks, persistence
├── ViewModel — TrainViewModel (main state management)
└── Views — SwiftUI screens, reusable components, widgets
Key design decisions:
MBTAServicemerges predictions + schedules concurrently usingasync let, deduplicating by trip IDTrainViewModelmanages all app state with@Publishedproperties and handles lifecycle (foreground/background)SharedDataManageruses App Groups (UserDefaults(suiteName:)) for widget data sharingCommuteEngineis a pure calculation layer — no side effects, fully testableNotificationManagerpre-fetches schedule data and bakes train times into notification content at schedule time
- iOS 17.0+
- Xcode 15+
- No API key required (the MBTA API is free and unauthenticated for low-volume use, with a rate limit of 20 requests/minute)
-
Clone the repository
git clone https://github.com/yourusername/MBTALive.git
-
Open
MBTALive.xcodeprojin Xcode -
Update the App Group identifier in
SharedDataManager.swiftif using a different team/bundle ID:private let appGroupIdentifier = "group.com.yourname.mbtalive"
Make sure the same identifier is set in both the main app and widget extension entitlements.
-
Build and run on a device (widgets and location require a physical device)
The app uses the MBTA V3 API with no authentication required. Key endpoints:
| Endpoint | Purpose |
|---|---|
/routes?filter[type]=0,1 |
All subway & light rail routes |
/stops?filter[route]=<id> |
Stops for a specific route |
/stops?filter[route_type]=0,1 |
All subway/light rail stops (used for nearest station) |
/predictions?filter[stop]=<id>&filter[route]=<id>&include=trip |
Real-time predictions with headsigns |
/schedules?filter[stop]=<id>&filter[route]=<id>&include=trip |
Published timetable |
MBTALive/
├── MBTALiveApp.swift App entry, lifecycle, deep links, background tasks
├── MainTabView.swift Tab bar (Arrivals, Commutes, Settings)
├── ContentView.swift Main arrivals screen with station picker and commute card
├── ArrivalRowView.swift Individual train arrival row
├── CommuteCardView.swift Smart commute countdown card
├── CommuteListView.swift Saved commutes list
├── CommuteDetailView.swift Commute detail with train times
├── AddCommuteView.swift Multi-step commute creation wizard
├── FavoritesView.swift Saved favorites list
├── OnboardingView.swift First-launch onboarding flow
├── SettingsView.swift User preferences and notification management
├── TrainViewModel.swift Central state management
├── MBTAService.swift MBTA API client
├── MBTAModels.swift API response models and TrainArrival
├── MBTAColors.swift Official MBTA route colors and badge styling
├── CommuteModel.swift Commute data model with Weekday enum
├── CommuteEngine.swift Pure commute plan calculation
├── CommuteManager.swift Commute CRUD persistence
├── Favorite.swift Favorite data model
├── UserSettingsManager.swift Route/stop/favorites persistence
├── LocationManager.swift CoreLocation wrapper
├── NotificationManager.swift Local notification scheduling (7-day lookahead)
├── BackgroundTaskManager.swift BGTaskScheduler for background refresh
└── SharedDataManager.swift App Group data sharing for widgets
MBTAWidget/
├── MBTAWidget.swift Widget views (small, medium, large, lock screen)
├── MBTAWidgetBundle.swift Widget bundle registration
├── MBTAWidgetControl.swift Control widget
├── MBTAWidgetLiveActivity.swift Live Activity (placeholder)
├── RefreshArrivalsIntent.swift Interactive refresh intent
└── NearMeIntent.swift Interactive near-me intent
MIT