Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

Commit 520dcd9

Browse files
authored
Refactor StoreKit transaction handling for API compatibility (#12)
## Summary of Changes ### StoreKitTypesBridge.swift - Added helper methods `ownershipTypeDescription()` and `transactionReasonDetails()` for StoreKit API compatibility - Updated `purchaseIOS()` to use helpers instead of direct `transaction.ownershipType.description`, `reasonDescription`, and `transactionReason` access - Removed deprecated extensions for `Transaction.reasonDescription`, `transactionReason`, and `OwnershipType.description` ### OpenIapModule.swift - Fixed purchase options call: changed `iosProps.storeKitPurchaseOptions()` to `StoreKitTypesBridge.purchaseOptions(from: iosProps)` These changes ensure compatibility across different StoreKit SDK versions without breaking existing functionality.
1 parent e3343b2 commit 520dcd9

File tree

2 files changed

+159
-164
lines changed

2 files changed

+159
-164
lines changed

Sources/Helpers/StoreKitTypesBridge.swift

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ enum StoreKitTypesBridge {
8484
offerInfo = nil
8585
}
8686

87+
let ownershipDescription = ownershipTypeDescription(from: transaction.ownershipType)
88+
let reasonDetails = transactionReasonDetails(from: transaction)
89+
8790
return PurchaseIOS(
8891
appAccountToken: transaction.appAccountToken?.uuidString,
8992
appBundleIdIOS: transaction.appBundleID,
@@ -105,15 +108,15 @@ enum StoreKitTypesBridge {
105108
offerIOS: offerInfo,
106109
originalTransactionDateIOS: transaction.originalPurchaseDate.milliseconds,
107110
originalTransactionIdentifierIOS: transaction.originalID != 0 ? String(transaction.originalID) : nil,
108-
ownershipTypeIOS: transaction.ownershipType.description,
111+
ownershipTypeIOS: ownershipDescription,
109112
platform: .ios,
110113
productId: transaction.productID,
111114
purchaseState: purchaseState,
112115
purchaseToken: jwsRepresentation ?? transactionId,
113116
quantity: transaction.purchasedQuantity,
114117
quantityIOS: transaction.purchasedQuantity,
115-
reasonIOS: transaction.reasonDescription,
116-
reasonStringRepresentationIOS: transaction.reasonDescription,
118+
reasonIOS: reasonDetails.lowercased,
119+
reasonStringRepresentationIOS: reasonDetails.string,
117120
revocationDateIOS: revocationDate,
118121
revocationReasonIOS: transaction.revocationReason?.rawValue.description,
119122
storefrontCountryCodeIOS: {
@@ -126,7 +129,7 @@ enum StoreKitTypesBridge {
126129
subscriptionGroupIdIOS: transaction.subscriptionGroupID,
127130
transactionDate: transaction.purchaseDate.milliseconds,
128131
transactionId: transactionId,
129-
transactionReasonIOS: transaction.transactionReason ?? "PURCHASE",
132+
transactionReasonIOS: reasonDetails.uppercased,
130133
webOrderLineItemIdIOS: transaction.webOrderLineItemID.map { String($0) }
131134
)
132135
}
@@ -298,6 +301,56 @@ private extension StoreKitTypesBridge {
298301
type: String(describing: offer.type)
299302
)
300303
}
304+
305+
static func ownershipTypeDescription(from ownership: StoreKit.Transaction.OwnershipType) -> String {
306+
switch ownership {
307+
case .purchased:
308+
return "purchased"
309+
case .familyShared:
310+
return "family_shared" // Maintain backward compatibility
311+
default:
312+
return "purchased" // Default to purchased for compatibility
313+
}
314+
}
315+
316+
struct TransactionReason {
317+
let lowercased: String
318+
let string: String
319+
let uppercased: String
320+
}
321+
322+
static func transactionReasonDetails(from transaction: StoreKit.Transaction) -> TransactionReason {
323+
if let revocation = transaction.revocationReason {
324+
// Map revocation reasons to expected strings
325+
let reasonString: String
326+
switch revocation {
327+
case .developerIssue:
328+
reasonString = "developer_issue"
329+
case .other:
330+
reasonString = "other"
331+
default:
332+
reasonString = "unknown"
333+
}
334+
return TransactionReason(
335+
lowercased: reasonString,
336+
string: reasonString,
337+
uppercased: reasonString.uppercased()
338+
)
339+
}
340+
341+
if transaction.isUpgraded {
342+
return TransactionReason(lowercased: "upgrade", string: "upgrade", uppercased: "UPGRADE")
343+
}
344+
345+
// Try to infer renewal for iOS <17
346+
if transaction.productType == .autoRenewable,
347+
let expirationDate = transaction.expirationDate,
348+
expirationDate > transaction.purchaseDate {
349+
return TransactionReason(lowercased: "renewal", string: "renewal", uppercased: "RENEWAL")
350+
}
351+
352+
return TransactionReason(lowercased: "purchase", string: "purchase", uppercased: "PURCHASE")
353+
}
301354
}
302355

303356
@available(iOS 15.0, macOS 14.0, *)
@@ -343,50 +396,6 @@ private extension StoreKit.Product.SubscriptionPeriod.Unit {
343396
}
344397
}
345398

346-
@available(iOS 15.0, macOS 14.0, *)
347-
private extension Date {
399+
extension Date {
348400
var milliseconds: Double { timeIntervalSince1970 * 1000 }
349401
}
350-
351-
@available(iOS 15.0, macOS 14.0, *)
352-
private extension StoreKit.Transaction {
353-
var reasonDescription: String? {
354-
if #available(iOS 17.0, macOS 14.0, *) {
355-
switch reason {
356-
case .purchase: return "purchase"
357-
case .renewal: return "renewal"
358-
default: return "unknown"
359-
}
360-
}
361-
return nil
362-
}
363-
364-
var transactionReason: String? {
365-
if #available(iOS 17.0, macOS 14.0, *) {
366-
switch reason {
367-
case .purchase: return "PURCHASE"
368-
case .renewal: return "RENEWAL"
369-
default: return "UNKNOWN"
370-
}
371-
}
372-
return nil
373-
}
374-
}
375-
376-
@available(iOS 15.0, macOS 14.0, *)
377-
private extension StoreKit.Transaction.OwnershipType {
378-
var description: String {
379-
switch self {
380-
case .purchased: return "purchased"
381-
case .familyShared: return "family_shared"
382-
default: return "purchased"
383-
}
384-
}
385-
}
386-
387-
@available(iOS 15.0, macOS 14.0, *)
388-
extension RequestPurchaseIosProps {
389-
func storeKitPurchaseOptions() -> Set<StoreKit.Product.PurchaseOption> {
390-
StoreKitTypesBridge.purchaseOptions(from: self)
391-
}
392-
}

0 commit comments

Comments
 (0)