diff --git a/Sources/Identity/IdentityManager.swift b/Sources/Identity/IdentityManager.swift index 801d32d2c8..11056969b1 100644 --- a/Sources/Identity/IdentityManager.swift +++ b/Sources/Identity/IdentityManager.swift @@ -92,7 +92,7 @@ class IdentityManager: CurrentUserProvider { } func switchUser(to newAppUserID: String) { - Logger.debug(Strings.identity.switching_user(newUserId: newAppUserID)) + Logger.debug(Strings.identity.switching_user(newUserID: newAppUserID)) self.resetCacheAndSave(newUserID: newAppUserID) } diff --git a/Sources/Logging/Strings/IdentityStrings.swift b/Sources/Logging/Strings/IdentityStrings.swift index f79e862b7b..1d2669039e 100644 --- a/Sources/Logging/Strings/IdentityStrings.swift +++ b/Sources/Logging/Strings/IdentityStrings.swift @@ -36,7 +36,9 @@ enum IdentityStrings { case invalidating_cached_customer_info - case switching_user(newUserId: String) + case switching_user(newUserID: String) + + case switching_user_same_app_user_id(newUserID: String) } @@ -68,8 +70,11 @@ extension IdentityStrings: CustomStringConvertible { return "Attempt to delete attributes for user, but there were none to delete" case .invalidating_cached_customer_info: return "Detected unverified cached CustomerInfo but verification is enabled. Invalidating cache." - case let .switching_user(newUserId): - return "Switching to user '\(newUserId)'." + case let .switching_user(newUserID): + return "Switching to user '\(newUserID)'." + case let .switching_user_same_app_user_id(newUserID): + return "switchUser(to:) called with the same appUserID as the current user (\(newUserID)). " + + "This has no effect." } } diff --git a/Sources/Purchasing/Purchases/Purchases.swift b/Sources/Purchasing/Purchases/Purchases.swift index 3d593c74c2..95c165acad 100644 --- a/Sources/Purchasing/Purchases/Purchases.swift +++ b/Sources/Purchasing/Purchases/Purchases.swift @@ -681,12 +681,13 @@ public extension Purchases { } -#else +#endif // - MARK: - Custom entitlement computation API -public extension Purchases { +extension Purchases { +#if ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION /// /// Updates the current appUserID to a new one, without associating the two. /// - Important: This method is **only available** in Custom Entitlements Computation mode. @@ -694,14 +695,28 @@ public extension Purchases { /// with the newAppUserID. /// @objc(switchUserToNewAppUserID:) - func switchUser(to newAppUserID: String) { + public func switchUser(to newAppUserID: String) { + self.internalSwitchUser(to: newAppUserID) + } +#endif + + internal func internalSwitchUser(to newAppUserID: String) { + guard self.identityManager.currentAppUserID != newAppUserID else { + Logger.warn(Strings.identity.switching_user_same_app_user_id(newUserID: newAppUserID)) + return + } + self.identityManager.switchUser(to: newAppUserID) + + self.systemInfo.isApplicationBackgrounded { isBackgrounded in + self.offeringsManager.updateOfferingsCache(appUserID: self.appUserID, + isAppBackgrounded: isBackgrounded, + completion: nil) + } } } -#endif - // MARK: Purchasing public extension Purchases { diff --git a/Tests/UnitTests/Purchasing/Purchases/PurchasesLogInTests.swift b/Tests/UnitTests/Purchasing/Purchases/PurchasesLogInTests.swift index 5e49a97bf2..2460326b08 100644 --- a/Tests/UnitTests/Purchasing/Purchases/PurchasesLogInTests.swift +++ b/Tests/UnitTests/Purchasing/Purchases/PurchasesLogInTests.swift @@ -100,20 +100,43 @@ class PurchasesLogInTests: BasePurchasesTests { // MARK: - Switch user - #if ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION - - func testSwitchUser() { + func testSwitchUserSwitchesUser() { self.systemInfo = MockSystemInfo(finishTransactions: true, customEntitlementsComputation: true) Purchases.clearSingleton() self.initializePurchasesInstance(appUserId: "old-test-user-id") - self.purchases.switchUser(to: "test-user-id") + self.purchases.internalSwitchUser(to: "test-user-id") expect(self.identityManager.invokedSwitchUser) == true expect(self.identityManager.invokedSwitchUserParametersList) == ["test-user-id"] } - #endif + func testSwitchUserRefreshesOfferingsCache() { + self.systemInfo = MockSystemInfo(finishTransactions: true, customEntitlementsComputation: true) + Purchases.clearSingleton() + self.initializePurchasesInstance(appUserId: "old-test-user-id") + + let baselineOfferingsCallCount = self.mockOfferingsManager.invokedUpdateOfferingsCacheCount + + self.purchases.internalSwitchUser(to: "test-user-id") + + expect(self.mockOfferingsManager.invokedUpdateOfferingsCacheCount) == baselineOfferingsCallCount + 1 + } + + func testSwitchUserNoOpIfAppUserIDIsSameAsCurrent() { + self.systemInfo = MockSystemInfo(finishTransactions: true, customEntitlementsComputation: true) + Purchases.clearSingleton() + let appUserId = "test-user-id" + self.initializePurchasesInstance(appUserId: appUserId) + + let baselineOfferingsCallCount = self.mockOfferingsManager.invokedUpdateOfferingsCacheCount + self.identityManager.mockAppUserID = appUserId + self.identityManager.mockIsAnonymous = false + self.purchases.internalSwitchUser(to: appUserId) + + expect(self.identityManager.invokedSwitchUser) == false + expect(self.mockOfferingsManager.invokedUpdateOfferingsCacheCount) == baselineOfferingsCallCount + } // MARK: - Update offerings cache