From 3870e0153cc791b411d0087d211e9d1aca1b20a9 Mon Sep 17 00:00:00 2001 From: Ryan Tobin Date: Mon, 11 Nov 2024 10:15:08 -0800 Subject: [PATCH] Dedup Optimization Summary: In the original dedup implementation, we only checked for implicit transactions at the beginning of the dedup window when a manual transaction was logged. However, based on testing, an implicit transaction could occur or be "finished" some elapsed time after the manual transaction occurs but still within the dedup window. Therefore, we update the implementation to recheck for implicit transactions again at the end of the dedup window so we don't miss this edge case. Reviewed By: jjiang10 Differential Revision: D65046779 fbshipit-source-id: c2f180c3007929abb5a6cebe5884d7284ca4085f --- .../Internal/IAP/IAPDedupeProcessor.swift | 11 +++++++++ .../Internal/IAP/IAPEventResolver.swift | 4 +++- .../IAPTests/IAPDedupeProcessorTests.swift | 24 +++++++++---------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPDedupeProcessor.swift b/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPDedupeProcessor.swift index aadbca8a9..30d0a8125 100644 --- a/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPDedupeProcessor.swift +++ b/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPDedupeProcessor.swift @@ -291,6 +291,17 @@ extension IAPDedupeProcessor { extension IAPDedupeProcessor { private func dedupTimerFired() { + if #available(iOS 15.0, *) { + Task { + await IAPTransactionObserver.shared.observeNewTransactions() + executeDedupTimerFired() + } + } else { + executeDedupTimerFired() + } + } + + private func executeDedupTimerFired() { timer?.invalidate() timer = nil var implicitEvents = synchronizedImplicitEvents diff --git a/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPEventResolver.swift b/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPEventResolver.swift index 68b6e90f2..92e017fc4 100644 --- a/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPEventResolver.swift +++ b/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/IAP/IAPEventResolver.swift @@ -147,9 +147,11 @@ extension IAPEventResolver { eventName: AppEvents.Name ) -> IAPEvent? { let transaction = iapTransaction?.transaction - var currency = transaction?.currencyCode + var currency: String? if #available(iOS 16.0, *) { currency = transaction?.currency?.identifier + } else { + currency = transaction?.currencyCode } let introOffer = product.subscription?.introductoryOffer let hasIntroductoryOffer = introOffer != nil diff --git a/FBSDKCoreKit/FBSDKCoreKitTests/Internal/AppEvents/IAP/IAPTests/IAPDedupeProcessorTests.swift b/FBSDKCoreKit/FBSDKCoreKitTests/Internal/AppEvents/IAP/IAPTests/IAPDedupeProcessorTests.swift index ea21aaaaa..8d1597f11 100644 --- a/FBSDKCoreKit/FBSDKCoreKitTests/Internal/AppEvents/IAP/IAPTests/IAPDedupeProcessorTests.swift +++ b/FBSDKCoreKit/FBSDKCoreKitTests/Internal/AppEvents/IAP/IAPTests/IAPDedupeProcessorTests.swift @@ -608,13 +608,13 @@ extension IAPDedupeProcessorTests { func testDedupWithDuplicatePurchaseEvents() async { dedupeProcessor.enable() let productID = Self.ProductIdentifiers.nonConsumableProduct1.rawValue - guard let (iapTransaction, _) = + guard let (iapTransaction, product) = await executeTransactionFor(productID) else { return } dedupeProcessor.processManualEvent( .purchased, - valueToSum: iapTransaction.transaction.price?.currencyNumber ?? 0, + valueToSum: iapTransaction.transaction.price?.currencyNumber ?? product.price.currencyNumber, parameters: [ AppEvents.ParameterName.currency: "USD", AppEvents.ParameterName.contentID: productID, @@ -642,13 +642,13 @@ extension IAPDedupeProcessorTests { func testDedupWithDuplicateSubscribeEvents() async { dedupeProcessor.enable() let productID = Self.ProductIdentifiers.autoRenewingSubscription1.rawValue - guard let (iapTransaction, _) = + guard let (iapTransaction, product) = await executeTransactionFor(productID) else { return } dedupeProcessor.processManualEvent( .subscribe, - valueToSum: iapTransaction.transaction.price?.currencyNumber ?? 0, + valueToSum: iapTransaction.transaction.price?.currencyNumber ?? product.price.currencyNumber, parameters: [ AppEvents.ParameterName.currency: "USD", AppEvents.ParameterName.contentID: productID, @@ -676,13 +676,13 @@ extension IAPDedupeProcessorTests { func testDedupWithDuplicateStartTrialEvents() async { dedupeProcessor.enable() let productID = Self.ProductIdentifiers.autoRenewingSubscription2.rawValue - guard let (iapTransaction, _) = + guard let (iapTransaction, product) = await executeTransactionFor(productID) else { return } dedupeProcessor.processManualEvent( .startTrial, - valueToSum: iapTransaction.transaction.price?.currencyNumber ?? 0, + valueToSum: iapTransaction.transaction.price?.currencyNumber ?? product.price.currencyNumber, parameters: [ AppEvents.ParameterName.currency: "USD", AppEvents.ParameterName.contentID: productID, @@ -710,13 +710,13 @@ extension IAPDedupeProcessorTests { func testDedupWithDuplicatePurchaseEventsTestDedupConfig() async { dedupeProcessor.enable() let productID = Self.ProductIdentifiers.nonConsumableProduct1.rawValue - guard let (iapTransaction, _) = + guard let (iapTransaction, product) = await executeTransactionFor(productID) else { return } dedupeProcessor.processManualEvent( .purchased, - valueToSum: iapTransaction.transaction.price?.currencyNumber ?? 0, + valueToSum: iapTransaction.transaction.price?.currencyNumber ?? product.price.currencyNumber, parameters: [ AppEvents.ParameterName.currency: "USD", AppEvents.ParameterName.contentID: productID, @@ -745,13 +745,13 @@ extension IAPDedupeProcessorTests { func testDedupWithNonDuplicatePurchaseEvents() async { dedupeProcessor.enable() let productID = Self.ProductIdentifiers.nonConsumableProduct1.rawValue - guard let (iapTransaction, _) = + guard let (iapTransaction, product) = await executeTransactionFor(productID) else { return } dedupeProcessor.processManualEvent( .purchased, - valueToSum: iapTransaction.transaction.price?.currencyNumber ?? 0, + valueToSum: iapTransaction.transaction.price?.currencyNumber ?? product.price.currencyNumber, parameters: [ AppEvents.ParameterName.currency: "USD", ], @@ -777,7 +777,7 @@ extension IAPDedupeProcessorTests { func testSeveralManualAndImplicitEventsWithSomeDuplicatesAndSomeNonDuplicates() async { dedupeProcessor.enable() let productID = Self.ProductIdentifiers.nonConsumableProduct1.rawValue - guard let (iapTransaction, _) = + guard let (iapTransaction, product) = await executeTransactionFor(productID) else { return } @@ -788,7 +788,7 @@ extension IAPDedupeProcessorTests { } dedupeProcessor.processManualEvent( .purchased, - valueToSum: iapTransaction.transaction.price?.currencyNumber ?? 0, + valueToSum: iapTransaction.transaction.price?.currencyNumber ?? product.price.currencyNumber, parameters: [ AppEvents.ParameterName.currency: "USD", AppEvents.ParameterName.contentID: productID,