Skip to content

Commit

Permalink
chore(Notifications) Updating public API and removing orphaned code. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ruisebas authored and harsh62 committed Jul 13, 2023
1 parent 75139f2 commit c5b1c37
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 282 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ import Foundation
import UserNotifications

extension PushNotificationsCategory: PushNotificationsCategoryBehaviour {
public func identifyUser(userId: String) {
plugin.identifyUser(userId: userId)
public func identifyUser(userId: String) async throws {
try await plugin.identifyUser(userId: userId)
}

public func registerDevice(token: Data) {
plugin.registerDevice(token: token)
public func registerDevice(apnsToken: Data) async throws {
try await plugin.registerDevice(apnsToken: apnsToken)
}

public func registerDidReceive(_ userInfo: NotificationUserInfo) {
plugin.registerDidReceive(userInfo)
public func recordNotificationReceived(_ userInfo: Notifications.Push.UserInfo) async {
await plugin.recordNotificationReceived(userInfo)
}

public func registerDidReceive(_ response: UNNotificationResponse) {
plugin.registerDidReceive(response)
public func recordNotificationOpened(_ response: UNNotificationResponse) async {
await plugin.recordNotificationOpened(response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import UserNotifications

extension Notifications {
public enum Push {
#if canImport(UIKit)
public typealias UserInfo = [AnyHashable: Any]
#elseif canImport(AppKit)
public typealias UserInfo = [String: Any]
#endif
// TODO: Replace with proper classes once they are implemented
public typealias AppDelegate = NSObject
public typealias ServiceExtension = UNNotificationServiceExtension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@

import Foundation
import UserNotifications
#if canImport(UIKit)
public typealias NotificationUserInfo = [AnyHashable: Any]
#else
public typealias NotificationUserInfo = [String: Any]
#endif

/// Defines the behaviour of the Push Notifications category that clients will use
public protocol PushNotificationsCategoryBehaviour: NotificationsSubcategoryBehaviour {
// TODO: These APIs can change. Document them once finalized.
/// Associates a given user ID with the current device
///
/// - Parameter userId: The unique identifier for the user
func identifyUser(userId: String) async throws

func identifyUser(userId: String)

func registerDevice(token: Data)

func registerDidReceive(_ userInfo: NotificationUserInfo)

func registerDidReceive(_ response: UNNotificationResponse)
/// Registers the given APNs token for this device, allowing it to receive Push Notifications
///
/// - Parameter apnsToken: A globally unique token that identifies this device to APNs
func registerDevice(apnsToken: Data) async throws

/// Records that a notification has been received.
///
/// - Parameter userInfo: A dictionary that contains information related to the remote notification
func recordNotificationReceived(_ userInfo: Notifications.Push.UserInfo) async

/// Records that a notification was opened, i.e. the user tapped on it
///
/// - Parameter response: The user’s response to the notification
func recordNotificationOpened(_ response: UNNotificationResponse) async
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public protocol AnalyticsClientBehaviour: Actor {
func removeGlobalMetric(forKey key: String, forEventType eventType: String)
func record(_ event: PinpointEvent) throws

func setGlobalEventSourceAttributes(_ attributes: [String: Any]) throws
func removeAllGlobalEventSourceAttributes()
func setRemoteGlobalAttributes(_ attributes: [String: String])
func removeAllRemoteGlobalAttributes()
func setAutomaticSubmitEventsInterval(_ interval: TimeInterval,
onSubmit: SubmitResult?)

Expand Down Expand Up @@ -62,8 +62,7 @@ actor AnalyticsClient: AnalyticsClientBehaviour {
private let sessionProvider: SessionProvider
private lazy var globalAttributes: PinpointEventAttributes = [:]
private lazy var globalMetrics: PinpointEventMetrics = [:]
// TODO: review this type
private lazy var globalEventSourceAttributes: [String: Any] = [:]
private lazy var globalRemoteAttributes: [String: String] = [:]
private lazy var eventTypeAttributes: [String: PinpointEventAttributes] = [:]
private lazy var eventTypeMetrics: [String: PinpointEventMetrics] = [:]

Expand Down Expand Up @@ -129,16 +128,12 @@ actor AnalyticsClient: AnalyticsClientBehaviour {
eventTypeMetrics[eventType, default: [:]][key] = metric
}

func setGlobalEventSourceAttributes(_ attributes: [String: Any]) throws {
guard let attributes = attributes as? [String: String] else {
return
func setRemoteGlobalAttributes(_ attributes: [String: String]) {
removeAllRemoteGlobalAttributes()
for (key, value) in attributes {
addGlobalAttribute(value, forKey: key)
}
globalEventSourceAttributes = attributes
let sessionId = self.sessionProvider().sessionId

try eventRecorder.updateAttributesOfEvents(ofType: SessionClient.Constants.Events.start,
withSessionId: sessionId,
setAttributes: attributes)
globalRemoteAttributes = attributes
}

func removeGlobalAttribute(forKey key: String) {
Expand All @@ -157,11 +152,11 @@ actor AnalyticsClient: AnalyticsClientBehaviour {
eventTypeMetrics[eventType]?[key] = nil
}

func removeAllGlobalEventSourceAttributes() {
for key in globalEventSourceAttributes.keys {
func removeAllRemoteGlobalAttributes() {
for key in globalRemoteAttributes.keys {
removeGlobalAttribute(forKey: key)
}
globalEventSourceAttributes = [:]
globalRemoteAttributes = [:]
}

// MARK: - Monetization events
Expand Down Expand Up @@ -261,14 +256,6 @@ actor AnalyticsClient: AnalyticsClientBehaviour {
event.addMetric(metric, forKey: key)
}

// Add event source attributes
for (key, attribute) in globalEventSourceAttributes {
// TODO: review this
if let attribute = attribute as? String {
event.addAttribute(attribute, forKey: key)
}
}

try eventRecorder.save(event)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ public protocol EndpointClientBehaviour: Actor {
func currentEndpointProfile() async -> PinpointEndpointProfile
func updateEndpointProfile() async throws
func updateEndpointProfile(with endpointProfile: PinpointEndpointProfile) async throws
func addAttributes(_ attributes: [String], forKey key: String)
func removeAttributes(forKey key: String)
func addMetric(_ metric: Double, forKey key: String)
func removeMetric(forKey key: String)
nonisolated func convertToPublicEndpoint(_ endpointProfile: PinpointEndpointProfile) -> PinpointClientTypes.PublicEndpoint
}

Expand All @@ -40,12 +36,6 @@ actor EndpointClient: EndpointClientBehaviour {
private let userDefaults: UserDefaultsBehaviour
private let keychain: KeychainStoreBehavior

typealias GlobalAttributes = [String: [String]]
typealias GlobalMetrics = [String: Double]

private var globalAttributes: GlobalAttributes = [:]
private var globalMetrics: GlobalMetrics = [:]

private var endpointProfile: PinpointEndpointProfile?
private static let defaultDateFormatter = ISO8601DateFormatter()

Expand All @@ -64,23 +54,10 @@ actor EndpointClient: EndpointClientBehaviour {
self.keychain = keychain

Self.migrateStoredValues(from: userDefaults, to: keychain, using: archiver)
if let attributes = Self.getStoredGlobalValues(key: Constants.attributesKey, as: GlobalAttributes.self, from: keychain, fallbackTo: userDefaults, using: archiver) {
globalAttributes = attributes
}

if let metrics = Self.getStoredGlobalValues(key: Constants.metricsKey, as: GlobalMetrics.self, from: keychain, fallbackTo: userDefaults, using: archiver) {
globalMetrics = metrics
}
}

func currentEndpointProfile() async -> PinpointEndpointProfile {
let endpointProfile = await retrieveOrCreateEndpointProfile()

// Refresh Attributes and Metrics
endpointProfile.removeAllAttributes()
endpointProfile.removeAllMetrics()
addAttributesAndMetrics(to: endpointProfile)

self.endpointProfile = endpointProfile
return endpointProfile
}
Expand All @@ -90,56 +67,9 @@ actor EndpointClient: EndpointClientBehaviour {
}

func updateEndpointProfile(with endpointProfile: PinpointEndpointProfile) async throws {
addAttributesAndMetrics(to: endpointProfile)
try await updateEndpoint(with: endpointProfile)
}

func addAttributes(_ attributes: [String], forKey key: String) {
precondition(!key.isEmpty, "Attributes and metrics must have a valid key")
globalAttributes[key] = attributes
do {
if let data = try? archiver.encode(globalAttributes) {
try keychain._set(data, key: Constants.attributesKey)
}
} catch {
log.error("Unable to store Analytics global attributes")
}
}

func removeAttributes(forKey key: String) {
globalAttributes[key] = nil
}

func addMetric(_ metric: Double, forKey key: String) {
precondition(!key.isEmpty, "Attributes and metrics must have a valid key")
globalMetrics[key] = metric
do {
if let data = try? archiver.encode(globalMetrics) {
try keychain._set(data, key: Constants.metricsKey)
}
} catch {
log.error("Unable to store Analytics global metrics")
}
}

func removeMetric(forKey key: String) {
globalMetrics[key] = nil
}

private func addAttributesAndMetrics(to endpointProfile: PinpointEndpointProfile) {
// Add global attributes
log.verbose("Applying Global Endpoint Attributes: \(globalAttributes)")
for (key, attributes) in globalAttributes {
endpointProfile.addAttributes(attributes, forKey: key)
}

// Add global metrics
log.verbose("Applying Global Endpoint Metrics: \(globalMetrics)")
for (key, metric) in globalMetrics {
endpointProfile.addMetric(metric, forKey: key)
}
}

private func retrieveOrCreateEndpointProfile() async -> PinpointEndpointProfile {
// 1. Look for the local endpointProfile variable
if let endpointProfile = endpointProfile {
Expand Down Expand Up @@ -263,26 +193,6 @@ actor EndpointClient: EndpointClientBehaviour {
log.error("Unable to migrate Analytics key-value store for key \(Constants.deviceTokenKey)")
}
}

if let attributes = userDefaults.object(forKey: Constants.attributesKey) as? GlobalAttributes,
let attributesData = try? archiver.encode(attributes) {
do {
try keychain._set(attributesData, key: Constants.attributesKey)
userDefaults.removeObject(forKey: Constants.attributesKey)
} catch {
log.error("Unable to migrate Analytics key-value store for key \(Constants.attributesKey)")
}
}

if let metrics = userDefaults.object(forKey: Constants.metricsKey) as? GlobalMetrics,
let metricsData = try? archiver.encode(metrics) {
do {
try keychain._set(metricsData, key: Constants.metricsKey)
userDefaults.removeObject(forKey: Constants.metricsKey)
} catch {
log.error("Unable to migrate Analytics key-value store for key \(Constants.metricsKey)")
}
}
}

private static func getStoredData(
Expand All @@ -296,20 +206,6 @@ actor EndpointClient: EndpointClientBehaviour {
return defaultSource.data(forKey: key)
}
}

private static func getStoredGlobalValues<T: Decodable>(
key: String,
as: T.Type,
from keychain: KeychainStoreBehavior,
fallbackTo defaultSource: UserDefaultsBehaviour,
using archiver: AmplifyArchiverBehaviour
) -> T? {
guard let data = try? keychain._getData(key) else {
return defaultSource.object(forKey: key) as? T
}

return try? archiver.decode(T.self, from: data)
}
}

extension EndpointClient: DefaultLogger {}
Expand All @@ -321,8 +217,6 @@ extension EndpointClient {
static let none = "NONE"
}

static let attributesKey = "AWSPinpointEndpointAttributesKey"
static let metricsKey = "AWSPinpointEndpointMetricsKey"
static let endpointProfileKey = "AWSPinpointEndpointProfileKey"
static let deviceTokenKey = "com.amazonaws.AWSDeviceTokenKey"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ class SessionClient: SessionClientBehaviour {
log.info("Session Stopped.")

Task {
await analyticsClient?.removeAllGlobalEventSourceAttributes()
log.verbose("Removing remote global attributes")
await analyticsClient?.removeAllRemoteGlobalAttributes()
log.verbose("Firing Session Event: Stop")
record(eventType: Constants.Events.stop)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ class AWSPinpointAnalyticsKeyValueStoreTests: XCTestCase {
override func setUp() {
userDefaults.removeObject(forKey: EndpointClient.Constants.deviceTokenKey)
userDefaults.removeObject(forKey: EndpointClient.Constants.endpointProfileKey)
userDefaults.removeObject(forKey: EndpointClient.Constants.attributesKey)
userDefaults.removeObject(forKey: EndpointClient.Constants.metricsKey)
keychain.resetCounters()
do {
try keychain._removeAll()
Expand Down Expand Up @@ -78,48 +76,4 @@ class AWSPinpointAnalyticsKeyValueStoreTests: XCTestCase {
XCTAssertNil(userDefaults.data(forKey:EndpointClient.Constants.endpointProfileKey))
XCTAssertNotNil(currentKeychainProfile)
}

func testAttributesMigrateFromUserDefaultsToKeychain() {
let attributes: [String: [String]] = ["Attributes1": ["Value1"]]
userDefaults.setValue(attributes, forKey: EndpointClient.Constants.attributesKey)

var currentAttributes = try? self.keychain._getData(EndpointClient.Constants.attributesKey)
XCTAssertNil(currentAttributes)
XCTAssertNotNil(userDefaults.object(forKey: EndpointClient.Constants.attributesKey))

_ = EndpointClient(configuration: .init(appId: currentApplicationId,
uniqueDeviceId: currentEndpointId,
isDebug: false),
pinpointClient: pinpointClient,
archiver: archiver,
endpointInformation: endpointInformation,
userDefaults: userDefaults,
keychain: keychain)

currentAttributes = try? self.keychain._getData(EndpointClient.Constants.attributesKey)
XCTAssertNil(userDefaults.object(forKey:EndpointClient.Constants.attributesKey))
XCTAssertNotNil(currentAttributes)
}

func testMetricsMigrateFromUserDefaultsToKeychain() {
let metrics = ["Attributes1": 123]
userDefaults.setValue(metrics, forKey: EndpointClient.Constants.metricsKey)

var currentMetrics = try? self.keychain._getData(EndpointClient.Constants.metricsKey)
XCTAssertNil(currentMetrics)
XCTAssertNotNil(userDefaults.object(forKey: EndpointClient.Constants.metricsKey))

_ = EndpointClient(configuration: .init(appId: currentApplicationId,
uniqueDeviceId: currentEndpointId,
isDebug: false),
pinpointClient: pinpointClient,
archiver: archiver,
endpointInformation: endpointInformation,
userDefaults: userDefaults,
keychain: keychain)

currentMetrics = try? self.keychain._getData(EndpointClient.Constants.metricsKey)
XCTAssertNil(userDefaults.object(forKey:EndpointClient.Constants.metricsKey))
XCTAssertNotNil(currentMetrics)
}
}
Loading

0 comments on commit c5b1c37

Please sign in to comment.