Post

Replies

Boosts

Views

Activity

Reply to Testing In-App Purchases
With this code, I'm getting an error: import Foundation import Observation import StoreKit enum ProductID: String { case subscriptionMonthly = "app_monthly" case subscriptionYearly = "monthly_yearly" } @MainActor @Observable final class SubscriptionsHandler { public var activeSubscription: String? = nil init() { // Because the tasks below capture 'self' in their closures, this object must be fully initialized before this point. Task(priority: .background) { // Finish any unfinished transactions -- for example, if the app was terminated before finishing a transaction. for await verificationResult in Transaction.unfinished { await handle(updatedTransaction: verificationResult) } // Fetch current entitlements for all product types except consumables. for await verificationResult in Transaction.currentEntitlements { await handle(updatedTransaction: verificationResult) } } Task(priority: .background) { for await verificationResult in Transaction.updates { await handle(updatedTransaction: verificationResult) } } } private func handle(updatedTransaction verificationResult: VerificationResult<Transaction>) async { // The code below handles only verified transactions; handle unverified transactions based on your business model. guard case .verified(let transaction) = verificationResult else { return } if let _ = transaction.revocationDate { // Remove access to the product identified by `transaction.productID`. // `Transaction.revocationReason` provides details about the revoked transaction. guard let productID = ProductID(rawValue: transaction.productID) else { print("Unexpected product: \(transaction.productID).") return } activeSubscription = nil UserDefaults.standard.set(false, forKey: "isSubscribed") await transaction.finish() return } else if let expirationDate = transaction.expirationDate, expirationDate < Date() { // In an app that supports Family Sharing, there might be another entitlement that still provides access to the subscription. activeSubscription = nil UserDefaults.standard.set(false, forKey: "isSubscribed") return } else { // Provide access to the product identified by transaction.productID. guard let productID = ProductID(rawValue: transaction.productID) else { print("Unexpected product: \(transaction.productID).") return } activeSubscription = transaction.productID UserDefaults.standard.set(true, forKey: "isSubscribed") await transaction.finish() return } } } SwiftUICore/Environment+Objects.swift:34: Fatal error: No Observable object of type SubscriptionsHandler found. A View.environmentObject(_:) for SubscriptionsHandler may be missing as an ancestor of this view.
Topic: Design SubTopic: General Tags:
Jun ’25
Reply to Background App Refresh
With the code below I get the error: class BackgroundTasksController: ObservableObject { func scheduleRoutineResetTask() { Task { BGTaskScheduler.shared.register(forTaskWithIdentifier: "app.BackgroundTask", using: nil) { task in Task { await self.handleAppRefresh(task: task as! BGAppRefreshTask) } } } } private func handleAppRefresh(task: BGAppRefreshTask) async { // Schedule a new refresh task. scheduleAppRefresh() // Create an operation that performs the main part of the background task. let operation = RefreshAppContentsOperation() // Provide the background task with an expiration handler that cancels the operation. task.expirationHandler = { operation.cancel() } // Inform the system that the background task is complete // when the operation completes. operation.completionBlock = { task.setTaskCompleted(success: !operation.isCancelled) } // Start the operation. //operationQueue.addOperation(operation) } private func scheduleAppRefresh() { let request = BGAppRefreshTaskRequest(identifier: "app.BackgroundTask") // Fetch no earlier than 15 minutes from now. request.earliestBeginDate = Date(timeIntervalSinceNow: 60) print(request) do { try BGTaskScheduler.shared.submit(request) } catch { print("Could not schedule app refresh: \(error)") } } } final class RefreshAppContentsOperation: Operation, @unchecked Sendable { } *** Assertion failure in -[BGTaskScheduler _unsafe_registerForTaskWithIdentifier:usingQueue:launchHandler:], BGTaskScheduler.m:225 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'All launch handlers must be registered before application finishes launching' *** First throw call stack: (0x18b5d321c 0x188a6dabc 0x18a8d1670 0x224da17f0 0x224da15f0 0x102fee124 0x102fee24d 0x102fefe1d 0x102feff79 0x19709d241) libc++abi: terminating due to uncaught exception of type NSException *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'All launch handlers must be registered before application finishes launching' *** First throw call stack: (0x18b5d321c 0x188a6dabc 0x18a8d1670 0x224da17f0 0x224da15f0 0x102fee124 0x102fee24d 0x102fefe1d 0x102feff79 0x19709d241) terminating due to uncaught exception of type NSException Is this configuration proper, and with this configuration is.addOperation necessary?
Jun ’25
Reply to Testing In-App Purchases
When trying to use Product.PurchaseResult or Transaction.updates, or SubscriptionStatus.updates within an .onChange function I get the error: "Instance method 'onChange(of:initial:_:)' requires that 'Transaction.Transactions' conform to 'Equatable'" Also, despite clearing purchase history in settings it doesn't seem that the subscription is resetting.
Topic: Design SubTopic: General Tags:
Jun ’25
Reply to Background App Refresh
Could you elaborate on how to build a model layer and how that differentiates from calling a function from a .task or .onappear function within the view level? What do I need to pass to handleAppRefresh? import Foundation import SwiftData import SwiftUI import BackgroundTasks func scheduleAppRefresh() { let request = BGAppRefreshTaskRequest(identifier: "app.RoutineRefresh") // Fetch no earlier than 15 minutes from now. request.earliestBeginDate = Date(timeIntervalSinceNow: 60) do { try BGTaskScheduler.shared.submit(request) } catch { print("Could not schedule app refresh: \(error)") } } func handleAppRefresh(task: BGAppRefreshTask) async { // Schedule a new refresh task. scheduleAppRefresh() // Create an operation that performs the main part of the background task. let operation = RefreshAppContentsOperation() // Provide the background task with an expiration handler that cancels the operation. task.expirationHandler = { operation.cancel() } // Inform the system that the background task is complete // when the operation completes. operation.completionBlock = { task.setTaskCompleted(success: !operation.isCancelled) } // Start the operation. //operationQueue.addOperation(operation) } final class RefreshAppContentsOperation: Operation, @unchecked Sendable { @Environment(\.modelContext) private var modelContext override func main() { } }
Jun ’25
Reply to Background App Refresh
I have the following code in ContentView: .onAppear { BGTaskScheduler.shared.register(forTaskWithIdentifier: "appname.RoutineRefresh", using: nil) { task in print(task) handleAppRefresh(task: task as! BGAppRefreshTask) } } However, nothing prints. Additionally, I have print statements in scheduleAppRefresh and handleAppRefresh but nothing prints from those functions either. I am also calling scheduleTaskRefresh in a .task function.
Jun ’25
Reply to Testing In-App Purchases
Hi, I'm trying to implement the code provided in a function within an async function in ContentView. However, I get an error "Value of type 'ContentView' has no member 'checkVerified'"
Topic: Design SubTopic: General Tags:
May ’25
Reply to Testing In-App Purchases
With my implementation, I am just using SubscriptionStoreView() so I wasn't able to apply the link you shared. I tried something like this: .onChange(of: Product.PurchaseResult.success(<#VerificationResult<Transaction>#>)) { } However, I get the error: Instance method 'onChange(of:initial:_:)' requires that 'Product.PurchaseResult' conform to 'Equatable' Also, I'm not sure what the parameter VerificationResult is and how to access it.
Topic: Design SubTopic: General Tags:
Apr ’25
Reply to .onAppear and .task code not running
Hi, Thanks for your response. I changed the original View names to generic names for the purpose of this post. The view variable is defined in the ContentView struct like this: @State var view: ScreenView ScreenView is an enum with the different view names. Only views 3 and 4 have code - the rest of the views/switch could be commented out.view6 is just the default view so there isn't a case for it in the switch statement. I changed .onAppear() to .onAppear. I don't see anything in the views that could possibly prevent those two functions from running.
Topic: Design SubTopic: General Tags:
Mar ’25