Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup

- Adds an `onCustomCallback` parameter to `getPaywall`.
- `SuperwallOptions.localResources` now accepts UIImage's from xcasset files, e.g. `UIImage(named: "my-image")`.
- Exposes abandoned transaction product params in audience filters.

## 4.15.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,11 @@ enum InternalSuperwallEvent {
var params = paywallInfo.audienceFilterParams()
if let product = product {
params["abandoned_product_id"] = product.productIdentifier
if !product.period.isEmpty {
for (key, value) in product.attributes where key != "identifier" {
params["abandoned_product_\(key.camelCaseToSnakeCase())"] = value
}
}
}
return params
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,46 @@ struct TrackingTests {
result.parameters.audienceFilterParams["presented_by_event_name"] as? String == paywallInfo.presentedByPlacementWithName)
}

@Test func transaction_abandon() async {
let paywallInfo: PaywallInfo = .stub()
let productId = "abc"
let product = StoreProduct(
sk1Product: MockSkProduct(
subscriptionPeriod: SKProductSubscriptionPeriodMock(numberOfUnits: 1, unit: .month),
productIdentifier: productId
),
entitlements: [.stub()]
)
let dependencyContainer = DependencyContainer()
let skTransaction = MockSKPaymentTransaction(state: .purchased)
let transaction = await dependencyContainer.makeStoreTransaction(from: skTransaction)
let result = await Superwall.shared.track(
InternalSuperwallEvent.Transaction(
state: .abandon(product),
paywallInfo: paywallInfo,
product: product,
transaction: transaction,
source: .external,
isObserved: false,
storeKitVersion: .storeKit1
)
)

#expect(result.parameters.audienceFilterParams["$event_name"] as! String == "transaction_abandon")
#expect(result.parameters.audienceFilterParams["$product_period"] != nil)
#expect(result.parameters.audienceFilterParams["$product_period_months"] != nil)

#expect(
result.parameters.audienceFilterParams["event_name"] as! String == "transaction_abandon")
#expect(
result.parameters.audienceFilterParams["abandoned_product_id"] as! String == productId)
#expect(result.parameters.audienceFilterParams["abandoned_product_identifier"] == nil)
#expect(result.parameters.audienceFilterParams["abandoned_product_period"] as? String == "month")
#expect(result.parameters.audienceFilterParams["abandoned_product_period_months"] as? String == "1")
#expect(result.parameters.audienceFilterParams["abandoned_product_period_years"] as? String == "0")
#expect((result.parameters.audienceFilterParams["abandoned_product_localized_period"] as? String)?.isEmpty == false)
}

@Test func transaction_fail() async {
let paywallInfo: PaywallInfo = .stub()
let productId = "abc"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,22 @@ import Foundation
import StoreKit

final class SKProductSubscriptionPeriodMock: SKProductSubscriptionPeriod {
private let internalNumberOfUnits: Int
private let internalUnit: SKProduct.PeriodUnit

override var numberOfUnits: Int {
return 1
return internalNumberOfUnits
}

override var unit: SKProduct.PeriodUnit {
return internalUnit
}

init(
numberOfUnits: Int = 1,
unit: SKProduct.PeriodUnit = .month
) {
self.internalNumberOfUnits = numberOfUnits
self.internalUnit = unit
}
}