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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Okay, thank you. And just clarifying, what needs to be passed to the handleAppRefresh function?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
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.
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() {
}
}
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
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.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Hi, the code came from this webpage: https://developer.apple.com/documentation/uikit/using-background-tasks-to-update-your-app
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
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'"
Just following up regarding to the question in my previous post. Thank you.
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.
For some reason, the line with the print statement skips when stepping through code despite having a breakpoint:
var body: some View {
Text("Test")
.onAppear {
print("test")
}
}
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.
Hi,
The Paid Apps Agreement, tax, and banking are all active in App Store Connect. Thank you.