ALL BUSINESS
COMIDA
DIRECTORIES
EDUCATIONAL
ENTERTAINMENT
FASHION TIPS
FINER THINGS
FREE CREATOR TOOLS
HEALTH
MARKETPLACE
MEMBER's ONLY
MONEY MATTER$
MOTIVATIONAL
NEWS & WEATHER
TECHNOLOGIA
TELEVISION NETWORKS
USA VOTES 2024
VIDEOS
INVESTOR RELATIONS
IN DEVELOPMENT
Posted by - Latinos MediaSyndication -
on - August 13, 2023 -
Filed in - Technology -
-
397 Views - 0 Comments - 0 Likes - 0 Reviews
So I am testing my in-app purchase implementation. I am currently testing Ask to buy or interrupted purchases using StoreKit config file in Xcode. Testing purchase errors is working good. When I am testing Ask to buy or Interrupted Purchase
According to apples documentation
Use updates to receive new transactions while the app is running. This sequence receives transactions that occur outside of the app, such as Ask to Buy transactions, subscription offer code redemptions, and purchases that customers make in the App Store.
When I accept or decline the transaction in Xcode. Transaction updates is not notified of the new transaction or failed transaction if I decline the transaction
This is my implementation of InappPurchase
enum PurchaseResult { case success(Date) case unverifiedResult case pending case userCancelled case unknownError } final class IAPManager: ObservableObject { private let userCache = UserCache.shared private let productIDs = ["my_product_identifier"] var updates: Task<Void, Never>? = nil static let shared = IAPManager() @Published var latestPurchaseTransaction: Transaction? = nil private init() { updates = newTransactionListenerTask() Task { await updateCurrentEntitlements() } } deinit { updates?.cancel() } private func newTransactionListenerTask() -> Task<Void, Never> { Task(priority: .background) { for await verificationResult in Transaction.updates { print("Transaction updates: \(verificationResult)") self.handle(updatedTransaction: verificationResult) } } } // This function fetches the lastest transactions the user has made private func updateCurrentEntitlements() async { guard let productID = productIDs.first, let verificationResult = await Transaction.latest(for: productID) else { // The user hasn't purchased this product. return } switch verificationResult { case .verified(let transaction): // Check the transaction and give the user access to purchased // content as appropriate. print("Latest transaction date: \(transaction.purchaseDate)") print("Expired date: \(transaction.expirationDate)") /* 1. Fetch the date 2. compare with saved date */ case .unverified(let transaction, let verificationError): // Handle unverified transactions based // on your business model. Crashlytics.crashlytics().record(error: verificationError) } } func fetchProducts() async throws -> [Product] { return try await Product.products(for: productIDs) } func purchase(_ product: Product) async throws -> PurchaseResult { let result = try await product.purchase() switch result { case .success(let verificationResult): switch verificationResult { case .verified(let transaction): // Give the user access to purchased content. // Complete the transaction after providing // the user access to the content. await transaction.finish() return .success(transaction.purchaseDate) case .unverified(let transaction, let verificationError): // Handle unverified transactions based // on your business model. Crashlytics.crashlytics().record(error: verificationError) return .unverifiedResult } case .pending: // The purchase requires action from the customer. // If the transaction completes, // it's available through Transaction.updates. return .pending case .userCancelled: // The user canceled the purchase. return .userCancelled @unknown default: return .unknownError } } private func handle(updatedTransaction verificationResult: VerificationResult<Transaction>) { guard case .verified(let transaction) = verificationResult else { // Ignore unverified transactions. return } if let _ = transaction.revocationDate { // Remove access to the product identified by transaction.productID. // Transaction.revocationReason provides details about // the revoked transaction. UserDatabaseService.shared.removeGodMode() } else if let expirationDate = transaction.expirationDate, expirationDate < Date() { // Do nothing, this subscription is expired. // we need to check the date in case we need to remove godmode userCache.fetchCurrentUser { user in if let user = user { if user.godmode == true { UserDatabaseService.shared.removeGodMode() } } } } else if transaction.isUpgraded { // Do nothing, there is an active transaction // for a higher level of service. return } else { // Provide access to the product identified by // transaction.productID. UserDatabaseService.shared.startGodMode() Task.init { await transaction.finish() } latestPurchaseTransaction = transaction UIViewController.showGodModeActivatedViewController() } } } extension IAPManager { // Function for checking if user is currently subscribed func isUserSubscribedToGodMode() async -> Bool { guard let productID = productIDs.first, let verificationResult = await Transaction.latest(for: productID) else { // The user hasn't purchased this product. return false } if case let .verified(transaction) = verificationResult { if Date.daysSinceDate(transaction.purchaseDate) <= 7 { return true } else { return false } } else { return false } } } extension IAPManager { // Function for restoring previous subscription func canRestoreSubscription() async -> Bool { guard let productID = productIDs.first, let verificationResult = await Transaction.latest(for: productID) else { // The user hasn't purchased this product. return false } if case .verified(_) = verificationResult { return true } else { return false } } }
Here are the image showing selecting Ask to buy in Xcode. It shows disable because it is already enabled