Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions androidApp/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/alerts_channel" />
<meta-data
android:name="firebase_messaging_installation_id_enabled"
android:value="true" />
<service
android:name=".notification.MBTAGoMessagingService"
android:exported="false">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import com.mbta.tid.mbta_app.android.state.getGlobalData
import com.mbta.tid.mbta_app.android.state.subscribeToAlerts
import com.mbta.tid.mbta_app.android.util.ManageErrorBannerBackgrounding
import com.mbta.tid.mbta_app.android.util.SettingsCache
import com.mbta.tid.mbta_app.android.util.fcmToken
import com.mbta.tid.mbta_app.android.util.fcmInstallationId
import com.mbta.tid.mbta_app.cache.ScheduleCache
import com.mbta.tid.mbta_app.model.FeaturePromo
import com.mbta.tid.mbta_app.model.OnboardingScreen
Expand Down Expand Up @@ -105,8 +105,8 @@ fun ContentView(
val pendingFeaturePromos = viewModel.pendingFeaturePromos.collectAsState().value
val currentLocale = stringResource(R.string.current_locale)

LaunchedEffect(fcmToken, notificationsEnabled) {
fcmToken?.let {
LaunchedEffect(fcmInstallationId, notificationsEnabled) {
fcmInstallationId?.let {
val favorites = favoritesUsecases.getRouteStopDirectionFavorites()
val subscriptions = SubscriptionRequest.fromFavorites(favorites, includeAccessibility)
subscriptionsRepository.updateSubscriptions(
Expand All @@ -118,7 +118,9 @@ fun ContentView(
}
}

LaunchedEffect(fcmToken, globalResponse) { favoritesViewModel.clearStaleFavorites(fcmToken) }
LaunchedEffect(fcmInstallationId, globalResponse) {
favoritesViewModel.clearStaleFavorites(fcmInstallationId)
}

val locationDataManager = rememberLocationDataManager()
val mapViewportState = rememberMapViewportState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import com.google.firebase.analytics.analytics
import com.google.firebase.messaging.FirebaseMessaging
import com.mbta.tid.mbta_app.android.analytics.AnalyticsProvider
import com.mbta.tid.mbta_app.android.util.LocalLocationClient
import com.mbta.tid.mbta_app.android.util.fcmToken
import com.mbta.tid.mbta_app.initializeSentry
import com.mbta.tid.mbta_app.routes.DeepLinkState
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -54,7 +53,7 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initSentry()
getFCMToken()
getFCMInstallationId()
handleIntent(intent)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
enableEdgeToEdge()
Expand Down Expand Up @@ -83,7 +82,7 @@ class MainActivity : ComponentActivity() {
}
}

private fun getFCMToken() {
FirebaseMessaging.getInstance().token.addOnSuccessListener { fcmToken = it }
private fun getFCMInstallationId() {
FirebaseMessaging.getInstance().register()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,13 @@ import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.mbta.tid.mbta_app.android.MainActivity
import com.mbta.tid.mbta_app.android.R
import com.mbta.tid.mbta_app.android.util.fcmToken
import com.mbta.tid.mbta_app.android.util.fcmInstallationId
import kotlin.random.Random

class MBTAGoMessagingService : FirebaseMessagingService() {

/**
* If you want to target single devices or create device groups, you'll need this token. Because
* the token could be rotated after initial startup, it is strongly recommended to retrieve the
* latest updated registration token. If you need it any other time:
* `FirebaseMessaging.getInstance().token.addOnCompleteListener {...}`
*/
override fun onNewToken(token: String) {
super.onNewToken(token)
fcmToken = token
override fun onRegistered(installationId: String) {
super.onRegistered(installationId)
fcmInstallationId = installationId
}

// if a notification is sent when the app is in the foreground, we have to create the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import com.mbta.tid.mbta_app.android.favorites.NoFavoritesView
import com.mbta.tid.mbta_app.android.util.IsLoadingSheetContents
import com.mbta.tid.mbta_app.android.util.SettingsCache
import com.mbta.tid.mbta_app.android.util.Typography
import com.mbta.tid.mbta_app.android.util.fcmToken
import com.mbta.tid.mbta_app.android.util.fcmInstallationId
import com.mbta.tid.mbta_app.android.util.getLabels
import com.mbta.tid.mbta_app.android.util.key
import com.mbta.tid.mbta_app.android.util.modifiers.haloContainer
Expand Down Expand Up @@ -157,7 +157,7 @@ fun EditFavoritesPage(
mapOf(deletedFavorite to null),
EditFavoritesContext.Favorites,
deletedFavorite.direction,
fcmToken,
fcmInstallationId,
currentLocale,
)

Expand All @@ -173,7 +173,7 @@ fun EditFavoritesPage(
mapOf(deletedFavorite to deletedSettings),
EditFavoritesContext.Favorites,
deletedFavorite.direction,
fcmToken,
fcmInstallationId,
currentLocale,
)
toastViewModel.hideToast()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import com.mbta.tid.mbta_app.android.more.MoreButton
import com.mbta.tid.mbta_app.android.more.MoreSectionView
import com.mbta.tid.mbta_app.android.util.SettingsCache
import com.mbta.tid.mbta_app.android.util.Typography
import com.mbta.tid.mbta_app.android.util.fcmToken
import com.mbta.tid.mbta_app.android.util.fcmInstallationId
import com.mbta.tid.mbta_app.android.util.key
import com.mbta.tid.mbta_app.android.util.modifiers.haloContainer
import com.mbta.tid.mbta_app.model.Dependency
Expand Down Expand Up @@ -133,7 +133,7 @@ fun MorePage(
when (setting) {
Settings.StationAccessibility -> {
if (notificationsEnabled) {
fcmToken?.let {
fcmInstallationId?.let {
viewModel.updateAccessibility(
it,
newValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import com.mbta.tid.mbta_app.android.favorites.NotificationSettingsWidget
import com.mbta.tid.mbta_app.android.state.getGlobalData
import com.mbta.tid.mbta_app.android.util.SettingsCache
import com.mbta.tid.mbta_app.android.util.Typography
import com.mbta.tid.mbta_app.android.util.fcmToken
import com.mbta.tid.mbta_app.android.util.fcmInstallationId
import com.mbta.tid.mbta_app.android.util.getLabels
import com.mbta.tid.mbta_app.android.util.key
import com.mbta.tid.mbta_app.android.util.notificationPermissionState
Expand Down Expand Up @@ -153,7 +153,7 @@ fun SaveFavoritePage(
update,
context,
selectedDirection,
fcmToken,
fcmInstallationId,
currentLocale,
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mbta.tid.mbta_app.android.util

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue

/** Set in MBTAGoMessagingService or retrieved on app launch in MainActivity */
var fcmInstallationId: String? by mutableStateOf(null)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fun manageFavorites(favoritesUseCases: FavoritesUsecases = koinInject()): Manage
newValues,
context,
defaultDirection,
if (notificationsEnabled) fcmToken else null,
if (notificationsEnabled) fcmInstallationId else null,
currentLocale,
)
}
Expand Down
14 changes: 7 additions & 7 deletions iosApp/iosApp/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct ContentView: View {
@EnvironmentObject var viewportProvider: ViewportProvider

@ObservedObject var contentVM: ContentViewModel
@ObservedObject var fcmTokenContainer = FcmTokenContainer.shared
@ObservedObject var fcmInstallationIdContainer = FcmInstallationIdContainer.shared
@ObservedObject var notificationDeepLinkOwner = AppDelegate.notificationDeepLinkOwner

@State private var contentHeight: CGFloat = UIScreen.current?.bounds.height ?? 0
Expand Down Expand Up @@ -109,16 +109,16 @@ struct ContentView: View {
}
.alerts($alerts)
.global($globalData, errorKey: ErrorKey(sheets: [], id: "ContentView"))
.handleFcmTokenSubscriptions(
fcmToken: fcmTokenContainer.token,
.handleFcmInstallationIdSubscriptions(
fcmInstallationId: fcmInstallationIdContainer.installationId,
includeAccessibility: includeAccessibility,
notificationsEnabled: notificationsFlag
)
.onChange(of: fcmTokenContainer.token) { token in
favoritesVM.clearStaleFavorites(fcmToken: token)
.onChange(of: fcmInstallationIdContainer.installationId) { installationId in
favoritesVM.clearStaleFavorites(fcmInstallationId: installationId)
}
.onChange(of: globalData) { _ in
favoritesVM.clearStaleFavorites(fcmToken: fcmTokenContainer.token)
favoritesVM.clearStaleFavorites(fcmInstallationId: fcmInstallationIdContainer.installationId)
}
.onChange(of: contentVM.defaultTab) { newTab in
// if we aren't on an entrypoint, then the default tab may have loaded after
Expand Down Expand Up @@ -663,7 +663,7 @@ struct ContentView: View {
updatedFavorites: favorites,
context: context,
defaultDirection: selectedDirection,
fcmToken: fcmTokenContainer.token,
fcmInstallationId: fcmInstallationIdContainer.installationId,
)
},
navCallbacks: navCallbacks,
Expand Down
2 changes: 2 additions & 0 deletions iosApp/iosApp/GoogleService-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FirebaseMessagingInstallationIdEnabled</key>
<true/>
<key>GCM_SENDER_ID</key>
<string>304904690247</string>
<key>PLIST_VERSION</key>
Expand Down
12 changes: 3 additions & 9 deletions iosApp/iosApp/IOSApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele

func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().token { token, error in

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question(non-blocking): What does the new code do here since it doesn't use the token? Is didRegisterForRemoteNotificationsWithDeviceToken hit if the device token isn't used anymore?

I am least familiar with how piece is set up, but it seems like the most obviously not 1-for-1 change, so figured I'd highlight it to learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deviceToken here is the APNs token we get from iOS, and we still need to pass that to FCM so it can deliver messages correctly.

if let error {
print("Error fetching FCM registration token: \(error)")
} else if let token {
FcmTokenContainer.shared.token = token
}
}
Messaging.messaging().register(completion: { _ in })
}

func application(
Expand All @@ -61,8 +55,8 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
completionHandler(.noData)
}

func messaging(_: Messaging, didReceiveRegistrationToken token: String?) {
FcmTokenContainer.shared.token = token
func messaging(_: Messaging, didReceiveRegistration installationId: String?) {
FcmInstallationIdContainer.shared.installationId = installationId
}

func userNotificationCenter(
Expand Down
2 changes: 2 additions & 0 deletions iosApp/iosApp/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FirebaseMessagingInstallationIdEnabled</key>
<true/>
<key>FirebaseAutomaticScreenReportingEnabled</key>
<false/>
<key>FirebaseAppDelegateProxyEnabled</key>
Expand Down
6 changes: 3 additions & 3 deletions iosApp/iosApp/Pages/Favorites/EditFavoritesPage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct EditFavoritesPage: View {
let toastVM: IToastViewModel
let globalRepository: IGlobalRepository = RepositoryDI().global

@ObservedObject var fcmTokenContainer = FcmTokenContainer.shared
@ObservedObject var fcmInstallationIdContainer = FcmInstallationIdContainer.shared
@EnvironmentObject var settingsCache: SettingsCache

var groupByStop: Bool { settingsCache.get(.favoritesByStop) }
Expand All @@ -36,7 +36,7 @@ struct EditFavoritesPage: View {
updatedFavorites: [rsd: nil],
context: .favorites,
defaultDirection: rsd.direction,
fcmToken: fcmTokenContainer.token,
fcmInstallationId: fcmInstallationIdContainer.installationId,
)

let labels = rsd.getLabels(globalResponse)
Expand Down Expand Up @@ -70,7 +70,7 @@ struct EditFavoritesPage: View {
updatedFavorites: [rsd: settings],
context: .favorites,
defaultDirection: rsd.direction,
fcmToken: fcmTokenContainer.token,
fcmInstallationId: fcmInstallationIdContainer.installationId,
)
}
),
Expand Down
7 changes: 4 additions & 3 deletions iosApp/iosApp/Pages/More/MorePage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct MorePage: View {
@State var showingBuildNumber = false
@State private var path = NavigationPath()

@ObservedObject var fcmTokenContainer = FcmTokenContainer.shared
@ObservedObject var fcmInstallationIdContainer = FcmInstallationIdContainer.shared
@EnvironmentObject var settingsCache: SettingsCache

private let translation = NSLocalizedString("key/current_locale", comment: "")
Expand Down Expand Up @@ -87,9 +87,10 @@ struct MorePage: View {
onChangeSetting: { setting, newValue in
switch setting {
case .stationAccessibility:
if settingsCache.get(.notifications), let fcmToken = fcmTokenContainer.token {
if settingsCache.get(.notifications),
let fcmInstallationId = fcmInstallationIdContainer.installationId {
viewModel.updateAccessibility(
fcmToken: fcmToken,
fcmInstallationId: fcmInstallationId,
includeAccessibility: newValue,
locale: NSLocalizedString("key/current_locale", comment: "")
)
Expand Down
4 changes: 2 additions & 2 deletions iosApp/iosApp/Pages/RouteDetails/RouteStopListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ struct RouteStopListContentView<RightSideContent: View>: View {
@State var displayedToast: ToastViewModel.Toast?
@State var firstTimeToast: ToastViewModel.Toast?

@ObservedObject var fcmTokenContainer = FcmTokenContainer.shared
@ObservedObject var fcmInstallationIdContainer = FcmInstallationIdContainer.shared
@EnvironmentObject var settingsCache: SettingsCache

let inspection = Inspection<Self>()
Expand Down Expand Up @@ -484,7 +484,7 @@ struct RouteStopListContentView<RightSideContent: View>: View {
updatedFavorites: updatedValues,
context: editContext,
defaultDirection: selectedDirection,
fcmToken: fcmTokenContainer.token,
fcmInstallationId: fcmInstallationIdContainer.installationId,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct StopDetailsFilteredView: View {
@State var inSaveFavoritesFlow = false
@State var alertSummaries: [String: AlertSummary?] = [:]

@ObservedObject var fcmTokenContainer = FcmTokenContainer.shared
@ObservedObject var fcmInstallationIdContainer = FcmInstallationIdContainer.shared

@EnvironmentObject var settingsCache: SettingsCache

Expand Down Expand Up @@ -294,7 +294,7 @@ struct StopDetailsFilteredView: View {
updatedFavorites: updatedValues,
context: .stopDetails,
defaultDirection: routeStopDirection.direction,
fcmToken: fcmTokenContainer.token,
fcmInstallationId: fcmInstallationIdContainer.installationId,
)
},
onClose: { inSaveFavoritesFlow = false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ extension FavoritesUsecases {
newValues: [RouteStopDirection: FavoriteSettings?],
context: EditFavoritesContext,
defaultDirection: Int32,
fcmToken: String?,
fcmInstallationId: String?,
) async throws {
try await __updateRouteStopDirections(
newValues: newValues as [RouteStopDirection: Any],
context: context,
defaultDirection: .init(int: defaultDirection),
fcmToken: fcmToken,
fcmInstallationId: fcmInstallationId,
locale: NSLocalizedString("key/current_locale", comment: ""),
)
}
Expand Down
14 changes: 14 additions & 0 deletions iosApp/iosApp/Utils/FcmInstallationIdContainer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// FcmInstallationIdContainer.swift
// iosApp
//
// Created by esimon on 11/28/25.
// Copyright © 2025 MBTA. All rights reserved.
//

import SwiftUI

class FcmInstallationIdContainer: ObservableObject {
static let shared = FcmInstallationIdContainer()
@Published var installationId: String?
}
14 changes: 0 additions & 14 deletions iosApp/iosApp/Utils/FcmTokenContainer.swift

This file was deleted.

Loading
Loading