You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何通过SKStoreProductViewController加载App Store商品并以Sheet展示

问题根源

你当前的写法会导致两次弹窗:SwiftUI的sheet先弹出一个空白视图,之后调用openAppStore又手动present了SKStoreProductViewController,所以才会出现先空白页再显示App Store页面的重复弹窗问题。

解决方案

把SKStoreProductViewController包装成SwiftUI可直接使用的UIViewControllerRepresentable组件,直接作为Sheet的内容展示,避免手动二次弹窗。

1. 编写App Store页面的SwiftUI包装组件

import SwiftUI
import StoreKit

struct AppStoreProductView: UIViewControllerRepresentable {
    let productID: Int
    @Binding var isPresented: Bool
    
    func makeUIViewController(context: Context) -> SKStoreProductViewController {
        let vc = SKStoreProductViewController()
        vc.delegate = context.coordinator
        // 传入App ID参数加载页面
        let parameters = [SKStoreProductParameterITunesItemIdentifier: productID]
        vc.loadProduct(withParameters: parameters) { _, error in
            // 加载失败时自动关闭Sheet并打印错误
            if let error = error {
                print("App Store页面加载失败: \(error.localizedDescription)")
                self.isPresented = false
            }
        }
        return vc
    }
    
    func updateUIViewController(_ uiViewController: SKStoreProductViewController, context: Context) {}
    
    // 处理UIKit的代理回调
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, SKStoreProductViewControllerDelegate {
        let parent: AppStoreProductView
        
        init(parent: AppStoreProductView) {
            self.parent = parent
        }
        
        // 关闭页面时同步SwiftUI的状态
        func productViewControllerDidFinish(_ viewController: SKStoreProductViewController) {
            parent.isPresented = false
        }
    }
}

2. 修改ContentView使用包装组件

import SwiftUI

struct ContentView: View {
    @State private var showAppStore = false
    // 替换成你的App Store产品ID
    private let appProductID = xxxxxxxxx
    
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
                .onTapGesture {
                    showAppStore.toggle()
                }
                // 直接在Sheet中展示包装好的App Store页面
                .sheet(isPresented: $showAppStore) {
                    AppStoreProductView(productID: appProductID, isPresented: $showAppStore)
                }
        }
        .padding()
    }
}

#Preview {
    ContentView()
}
说明
  • 这种写法直接将SKStoreProductViewController作为Sheet的内容,彻底避免了重复弹窗的问题
  • 通过Coordinator同步UIKit的关闭事件到SwiftUI的状态变量,保证页面状态一致
  • 新增了加载失败的处理逻辑,避免用户停留在空白页

内容的提问来源于stack exchange,提问作者piro299

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 23:07:16