I’m struggling to get StoreKit 2 to fetch merchandise in my SwiftUI app whereas utilizing a sandbox person. I feel I’ve adopted all mandatory setup steps in Xcode, App Retailer Join, and my bodily check gadget, however Product.merchandise(for:)
at all times returns an empty array. I’d admire any insights!
What I’ve Finished
-
Native App Setup (Xcode 16.2)
• Created a clean SwiftUI Xcode venture.
• Enabled In-App Buy functionality beneath Signing & Capabilities.
• Carried out minimal StoreKit 2 code to fetch out there merchandise (see under).
• Utilizing the proper bundle identifier, which matches App Retailer Join.
-
App Retailer Join Configuration
• Registered the app with the identical bundle identifier.
• Created an Auto-Renewable Subscription with: Product ID v1 (matches my code). All fields crammed (pricing, localization, and many others.). Standing: Prepared for Assessment.
-
Sandbox Person & Testing Setup
• Created a sandbox tester account.
• On my bodily gadget (iOS 18.2): Logged in with the sandbox person beneath Settings → Developer → Sandbox Apple ID. Put in and ran the app instantly from Xcode.
-
Challenge: StoreKit Returns No Merchandise
•
Product.merchandise(for:["v1"])
doesn’t return any merchandise.• There are not any errors thrown, simply an empty array.
• I confirmed that StoreKit Configuration is ready to None in Xcode.
• No StoreKit-related logs seem within the Console.
Code Snippets
//StoreKitManager.swift
import StoreKit
import SwiftUI
@MainActor
class StoreKitManager: ObservableObject {
@Revealed var merchandise: [Product] = []
@Revealed var errorMessage: String?
func fetchProducts() async {
do {
let productIDs: Set = ["v1"] // Matches App Retailer Join
let fetchedProducts = attempt await Product.merchandise(for: productIDs)
print(fetchedProducts) // Debug output
DispatchQueue.essential.async {
self.merchandise = fetchedProducts
}
} catch {
DispatchQueue.essential.async {
self.errorMessage = "Did not fetch merchandise: (error.localizedDescription)"
}
}
}
}
//ContentView.swift
import SwiftUI
struct ContentView: View {
@StateObject personal var storeKitManager = StoreKitManager()
var physique: some View {
VStack {
if let errorMessage = storeKitManager.errorMessage {
Textual content(errorMessage).foregroundColor(.crimson)
} else if storeKitManager.merchandise.isEmpty {
Textual content("No merchandise out there")
} else {
Record(storeKitManager.merchandise, id: .id) { product in
VStack(alignment: .main) {
Textual content(product.displayName).font(.headline)
Textual content(product.description).font(.subheadline)
Textual content("(product.value.formatted(.forex(code: product.priceFormatStyle.currencyCode ?? "USD")))")
.daring()
}
}
}
Button("Fetch Merchandise") {
Process {
await storeKitManager.fetchProducts()
}
}
}
.padding()
.onAppear {
Process {
await storeKitManager.fetchProducts()
}
}
}
}
#Preview {
ContentView()
}
Further Info
• iOS Model: 18.2
• Xcode Model: 16.2
• macOS Model: 15.3.1
• Gadget: Bodily iPhone (not simulator)
• StoreKit Configuration: Set to None
Is there any technique to debug why StoreKit isn’t recognizing my subscription?