Skip to content

Commit

Permalink
FCM Tokens (#91)
Browse files Browse the repository at this point in the history
# FCM Tokens

## ♻️ Current situation & Problem
Firebase Cloud Messaging expects FCM Tokens for notifications instead of
APNS tokens.

## ⚙️ Release Notes 
*Add a bullet point list summary of the feature and possible migration
guides if this is a breaking change so this section can be added to the
release notes.*
*Include code snippets that provide examples of the feature implemented
or links to the documentation if it appends or changes the public
interface.*


## 📚 Documentation
*Please ensure that you properly document any additions in conformance
to [Spezi Documentation
Guide](https://github.com/StanfordSpezi/.github/blob/main/DOCUMENTATIONGUIDE.md).*
*You can use this section to describe your solution, but we encourage
contributors to document your reasoning and changes using in-line
documentation.*


## ✅ Testing
*Please ensure that the PR meets the testing requirements set by CodeCov
and that new functionality is appropriately tested.*
*This section describes important information about the tests and why
some elements might not be testable.*


### Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
pauljohanneskraft authored Sep 17, 2024
1 parent c8cf7ae commit c740a4f
Show file tree
Hide file tree
Showing 18 changed files with 120 additions and 154 deletions.
12 changes: 8 additions & 4 deletions ENGAGEHF.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@
4DBDD3462BBFAE2D001FB0CA /* InvitationCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DBDD3452BBFAE2D001FB0CA /* InvitationCodeView.swift */; };
4DBDD3482BC073EF001FB0CA /* FirebaseFunctions in Frameworks */ = {isa = PBXBuildFile; productRef = 4DBDD3472BC073EF001FB0CA /* FirebaseFunctions */; };
4DBE86DD2C7F9BBF0003390B /* MobilePlatform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DBE86DC2C7F9BBF0003390B /* MobilePlatform.swift */; };
4DBE86E02C7FAF6E0003390B /* Data+HexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DBE86DF2C7FAF6E0003390B /* Data+HexString.swift */; };
4DC0F6712C34818B0025AB13 /* HKSample+GetDoubleValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DC0F6702C34818B0025AB13 /* HKSample+GetDoubleValues.swift */; };
4DC0F67A2C34AD620025AB13 /* VitalsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DC0F6792C34AD620025AB13 /* VitalsList.swift */; };
4DC0F6842C34B66F0025AB13 /* ResolutionPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DC0F6832C34B66F0025AB13 /* ResolutionPicker.swift */; };
Expand Down Expand Up @@ -201,6 +200,7 @@
9733CFC62A8066DE001B7ABC /* SpeziOnboarding in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8029EDD91D004B9AB4 /* SpeziOnboarding */; };
9739A0C62AD7B5730084BEA5 /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 9739A0C52AD7B5730084BEA5 /* FirebaseStorage */; };
97D73D6A2AD860AD00B47FA0 /* SpeziFirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 97D73D692AD860AD00B47FA0 /* SpeziFirebaseStorage */; };
9B0723AB2C8F6AE700D901E5 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 9B0723AA2C8F6AE700D901E5 /* FirebaseMessaging */; };
9B1864882C9226E90042AC81 /* AccountDetails+Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B1864872C9226E90042AC81 /* AccountDetails+Key.swift */; };
9B18648B2C9227040042AC81 /* AccountNotifications+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B18648A2C9227040042AC81 /* AccountNotifications+Extras.swift */; };
9B1864942C9276C40042AC81 /* AuthFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B1864932C9276C40042AC81 /* AuthFlow.swift */; };
Expand Down Expand Up @@ -373,7 +373,6 @@
4DBDD3432BBFAD64001FB0CA /* InvitationCodeError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitationCodeError.swift; sourceTree = "<group>"; };
4DBDD3452BBFAE2D001FB0CA /* InvitationCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitationCodeView.swift; sourceTree = "<group>"; };
4DBE86DC2C7F9BBF0003390B /* MobilePlatform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobilePlatform.swift; sourceTree = "<group>"; };
4DBE86DF2C7FAF6E0003390B /* Data+HexString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+HexString.swift"; sourceTree = "<group>"; };
4DC0F6702C34818B0025AB13 /* HKSample+GetDoubleValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HKSample+GetDoubleValues.swift"; sourceTree = "<group>"; };
4DC0F6792C34AD620025AB13 /* VitalsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VitalsList.swift; sourceTree = "<group>"; };
4DC0F6832C34B66F0025AB13 /* ResolutionPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResolutionPicker.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -444,6 +443,7 @@
4D49AB022BC9D50400C77310 /* SpeziBluetooth in Frameworks */,
56E708352BB06B7100B08F0A /* SpeziLicense in Frameworks */,
2FE5DC8A29EDD972004B9AB4 /* SpeziLocalStorage in Frameworks */,
9B0723AB2C8F6AE700D901E5 /* FirebaseMessaging in Frameworks */,
2FE5DC8C29EDD972004B9AB4 /* SpeziSecureStorage in Frameworks */,
A9623C042C17A3F500189BA1 /* SpeziOmron in Frameworks */,
2FE5DC7529EDD8E6004B9AB4 /* SpeziFirebaseAccount in Frameworks */,
Expand Down Expand Up @@ -693,7 +693,6 @@
children = (
4D8CE0FA2C753A4600560327 /* NotificationManager.swift */,
4D8CE0FB2C753A4600560327 /* NotificationRegistrationSchema.swift */,
4DBE86DF2C7FAF6E0003390B /* Data+HexString.swift */,
);
path = NotificationManager;
sourceTree = "<group>";
Expand Down Expand Up @@ -1177,6 +1176,7 @@
A977DD532C25E2DA00A2A8E5 /* SpeziDevices */,
A977DD552C25E2DA00A2A8E5 /* SpeziDevicesUI */,
A977DD5C2C26279E00A2A8E5 /* SpeziBluetoothServices */,
9B0723AA2C8F6AE700D901E5 /* FirebaseMessaging */,
);
productName = ENGAGEHF;
productReference = 653A254D283387FE005D4D48 /* ENGAGEHF.app */;
Expand Down Expand Up @@ -1349,7 +1349,6 @@
4D734AC02C5C58CA002D6D2F /* View+asButton.swift in Sources */,
4D734AC32C5D7C81002D6D2F /* MessageAction.swift in Sources */,
4D92BA172C3E108700ABCED7 /* CodeableConcept+Contains.swift in Sources */,
4DBE86E02C7FAF6E0003390B /* Data+HexString.swift in Sources */,
4D62BF2A2C6A71500088C414 /* FirestoreSettings+EmulatorWithHost.swift in Sources */,
4D8CE0FC2C753A4700560327 /* NotificationManager.swift in Sources */,
4DC0F67A2C34AD620025AB13 /* VitalsList.swift in Sources */,
Expand Down Expand Up @@ -2289,6 +2288,11 @@
package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */;
productName = SpeziFirebaseStorage;
};
9B0723AA2C8F6AE700D901E5 /* FirebaseMessaging */ = {
isa = XCSwiftPackageProductDependency;
package = 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseMessaging;
};
A9623C032C17A3F500189BA1 /* SpeziOmron */ = {
isa = XCSwiftPackageProductDependency;
package = A9623C022C17A3F500189BA1 /* XCRemoteSwiftPackageReference "SpeziDevices" */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
</CommandLineArgument>
<CommandLineArgument
argument = "--skipRemoteNotificationRegistration"
isEnabled = "NO">
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--setupTestUserMetaData"
Expand Down
17 changes: 0 additions & 17 deletions ENGAGEHF/Managers/NotificationManager/Data+HexString.swift

This file was deleted.

31 changes: 19 additions & 12 deletions ENGAGEHF/Managers/NotificationManager/NotificationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Combine
import FirebaseFunctions
import FirebaseMessaging
import Foundation
import OSLog
import Spezi
Expand Down Expand Up @@ -64,7 +65,7 @@ class NotificationManager: Module, NotificationHandler, NotificationTokenHandler
guard let self else {
return
}

if event.newEnrolledAccountDetails != nil {
do {
_ = try await self.requestNotificationPermissions()
Expand Down Expand Up @@ -144,33 +145,32 @@ class NotificationManager: Module, NotificationHandler, NotificationTokenHandler
func requestNotificationPermissions() async throws -> Bool {
logger.debug("Requesting notification permissions.")

let deviceToken = try await self.getDeviceToken(askPermissionIfNeeded: true)

guard let deviceToken else {
guard let deviceToken = try await self.getDeviceToken(askPermissionIfNeeded: true) else {
return false
}

try await self.configureRemoteNotifications(using: deviceToken)
try await self.registerDeviceToken(using: deviceToken)
return true
}


func receiveUpdatedDeviceToken(_ deviceToken: Data) {
func receiveUpdatedDeviceToken(_ apnsToken: Data) {
Task {
do {
try await self.configureRemoteNotifications(using: deviceToken)
try await self.registerDeviceToken(using: apnsToken)
} catch {
self.logger.error("Failed to configure remote notifications for updated device token: \(error)")
}
}
}


private func configureRemoteNotifications(using deviceToken: Data) async throws {
private func registerDeviceToken(using apnsToken: Data) async throws {
self.logger.debug("Registering device for remote notifications.")

let fcmToken = try await convertTokenToFCM(apns: apnsToken)
let registerDevice = Functions.functions().httpsCallable("registerDevice")
_ = try await registerDevice.call(NotificationRegistrationSchema(deviceToken).codingRepresentation)
_ = try await registerDevice.call(NotificationRegistrationSchema(fcmToken).codingRepresentation)

self.logger.debug("Successfully registered device for remote notifications.")
}
Expand All @@ -183,8 +183,9 @@ class NotificationManager: Module, NotificationHandler, NotificationTokenHandler
return
}

let fcmToken = try await convertTokenToFCM(apns: deviceToken)
let unregisterDevice = Functions.functions().httpsCallable("unregisterDevice")
_ = try await unregisterDevice.call(NotificationRegistrationSchema(deviceToken).codingRepresentation)
_ = try await unregisterDevice.call(NotificationRegistrationSchema(fcmToken).codingRepresentation)

self.logger.debug("Successfully unregistered device for remote notifications.")
}
Expand Down Expand Up @@ -215,9 +216,15 @@ class NotificationManager: Module, NotificationHandler, NotificationTokenHandler
}

#if TEST
return Data()
return nil
#else
return FeatureFlags.skipRemoteNotificationRegistration ? Data() : try await registerRemoteNotifications()
return FeatureFlags.skipRemoteNotificationRegistration ? nil : try await registerRemoteNotifications()
#endif
}

private func convertTokenToFCM(apns apnsToken: Data) async throws -> String {
let messaging = Messaging.messaging()
messaging.apnsToken = apnsToken
return try await messaging.token()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ struct NotificationRegistrationSchema: Codable {
}


init(_ deviceToken: Data, locale: Locale = Locale.current, timeZone: TimeZone = .current) {
self.notificationToken = deviceToken.hexString
init(_ notificationToken: String, locale: Locale = Locale.current, timeZone: TimeZone = .current) {
self.notificationToken = notificationToken
self.platform = MobilePlatform.iOS.rawValue
self.osVersion = UIDevice.current.systemVersion
self.appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
Expand Down
24 changes: 0 additions & 24 deletions ENGAGEHF/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"strings" : {
"" : {

},
"%@" : {

},
"%@ Date: %@" : {
"localizations" : {
Expand Down Expand Up @@ -115,12 +112,6 @@
},
"Add Medications" : {

},
"Add Mock" : {

},
"Add mock notification" : {

},
"All Data" : {

Expand Down Expand Up @@ -182,9 +173,6 @@
}
}
}
},
"Content ..." : {

},
"Content Unavailable" : {

Expand Down Expand Up @@ -215,9 +203,6 @@
},
"Expansion Button" : {

},
"Expected Progress: %lf" : {

},
"Failed to fetch HKUnits for the given samples." : {

Expand Down Expand Up @@ -407,12 +392,6 @@
}
}
}
},
"List With Sections" : {

},
"List Without Sections" : {

},
"Logout" : {

Expand Down Expand Up @@ -658,9 +637,6 @@
}
}
}
},
"Tap Here" : {

},
"Target" : {

Expand Down
2 changes: 1 addition & 1 deletion ENGAGEHF/Supporting Files/GoogleService-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<key>REVERSED_CLIENT_ID</key>
<string>REVERSED_CLIENT_ID</string>
<key>API_KEY</key>
<string>API_KEY</string>
<string>API_KEY89012345678901234567890123456789</string>
<key>GCM_SENDER_ID</key>
<string>GCM_SENDER_ID</string>
<key>PLIST_VERSION</key>
Expand Down
2 changes: 1 addition & 1 deletion ENGAGEHFTests/HKSampleGraphUnitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ final class HKSampleGraphUnitTests: XCTestCase {
validateSeriesDictionary(actualOutput: viewModel.seriesData, expectedOutput: expectedOutput)

// Make sure the correct unit was identified
XCTAssertEqual(viewModel.displayUnit, "lb")
XCTAssertEqual(viewModel.displayUnit, Locale.current.measurementSystem == .us ? "lb" : "kg")

// Make sure the correct formatter was chosen
XCTAssertEqual(viewModel.formatter([(KnownVitalsSeries.bodyWeight.rawValue, 120.0), ("Diastolic", 60.0)]), "120.0")
Expand Down
2 changes: 1 addition & 1 deletion ENGAGEHFUITests/Account/ContactsUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class ContactsUITests: XCTestCase {

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)

try app.goTo(tab: "Home")
app.goTo(tab: "Home")

XCTAssertTrue(app.navigationBars.buttons["Your Account"].waitForExistence(timeout: 2))
app.navigationBars.buttons["Your Account"].tap()
Expand Down
2 changes: 1 addition & 1 deletion ENGAGEHFUITests/Account/NotificationSettingsUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class NotificationSettingsUITests: XCTestCase {

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)

try app.goTo(tab: "Home")
app.goTo(tab: "Home")

XCTAssertTrue(app.navigationBars.buttons["Your Account"].waitForExistence(timeout: 2))
app.navigationBars.buttons["Your Account"].tap()
Expand Down
18 changes: 9 additions & 9 deletions ENGAGEHFUITests/Dashboard/MessagesUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ final class MessagesUITests: XCTestCase {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

// Directly dismiss by tapping dismiss button
let medicationChangeMessage = app.otherElements["Message Card - Medication Change"]
Expand All @@ -48,7 +48,7 @@ final class MessagesUITests: XCTestCase {

uptitrationMessage.tap()
sleep(1)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")
XCTAssertFalse(app.otherElements["Message Card - Medication Uptitration"].exists)


Expand All @@ -59,15 +59,15 @@ final class MessagesUITests: XCTestCase {

vitalsMessage.tap()
sleep(1)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")
XCTAssert(app.otherElements["Message Card - Vitals"].exists)
}

func testPlayVideoAction() throws {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

let medicationChangeMessage = app.otherElements["Message Card - Medication Change"]
XCTAssert(medicationChangeMessage.exists)
Expand All @@ -89,7 +89,7 @@ final class MessagesUITests: XCTestCase {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

let questionnaireMessage = app.otherElements["Message Card - Symptom Questionnaire"]
XCTAssert(questionnaireMessage.exists)
Expand All @@ -106,7 +106,7 @@ final class MessagesUITests: XCTestCase {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

let medicationUptitrationMessage = app.otherElements["Message Card - Medication Uptitration"]
XCTAssert(medicationUptitrationMessage.exists)
Expand All @@ -122,7 +122,7 @@ final class MessagesUITests: XCTestCase {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

let vitalsMessage = app.otherElements["Message Card - Vitals"]
XCTAssert(vitalsMessage.exists)
Expand All @@ -138,7 +138,7 @@ final class MessagesUITests: XCTestCase {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

let unknownActionMessage = app.otherElements["Message Card - Unknown"]
XCTAssert(unknownActionMessage.exists)
Expand All @@ -153,7 +153,7 @@ final class MessagesUITests: XCTestCase {
let app = XCUIApplication()

_ = app.staticTexts["Home"].waitForExistence(timeout: 5)
try app.goTo(tab: "Home")
app.goTo(tab: "Home")

let medicationChangeMessage = app.otherElements["Message Card - Medication Change"]
XCTAssert(medicationChangeMessage.exists)
Expand Down
6 changes: 3 additions & 3 deletions ENGAGEHFUITests/Dashboard/RecentVitalsUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class RecentVitalsUITests: XCTestCase {
let weightUnit = Locale.current.measurementSystem == .us ? "lb" : "kg"

// Delete all previous measurements
try app.deleteAllMeasurements("Weight", header: "Body Weight")
app.deleteAllMeasurements("Weight", header: "Body Weight")

// Make sure we're on the home screen
XCTAssert(app.buttons["Home"].waitForExistence(timeout: 2.0))
Expand Down Expand Up @@ -67,8 +67,8 @@ final class RecentVitalsUITests: XCTestCase {
_ = app.staticTexts["Home"].waitForExistence(timeout: 5)

// Delete previous measurements
try app.deleteAllMeasurements("HR", header: "Heart Rate")
try app.deleteAllMeasurements("BP", header: "Blood Pressure")
app.deleteAllMeasurements("HR", header: "Heart Rate")
app.deleteAllMeasurements("BP", header: "Blood Pressure")

// Make sure we're on the home screen
XCTAssert(app.buttons["Home"].waitForExistence(timeout: 2.0))
Expand Down
Loading

0 comments on commit c740a4f

Please sign in to comment.