iOS内购——自动续订型会员集成StoreKit1和StoreKit2
StoreKit1
import UIKit
import StoreKit
//兼容iOS15以前
class StoreKitManager1: NSObject {
//产品ID(非消耗型或消耗型均可)
private let productID = "com.your.app.consumable"
//本地保存的Key
private let purchaseKey = "com.your.app.purchased"
//当前请求的产品(用于缓存)
private var product: SKProduct?
//购买完成回调(可选)
var purchaseCompletion: ((Bool) -> Void)?
//本地检查是否已购买
var isPurchasedLocally: Bool {
return UserDefaults.standard.bool(forKey: purchaseKey)
}
//shared
static let shared = StoreKitManager1()
private override init() {
super.init()
}
//启动时设置观察者
func setup() {
SKPaymentQueue.default().add(self)
}
//请求产品信息(通常在购买前调用)
func fetchProducts() {
let request = SKProductsRequest(productIdentifiers: Set([productID]))
request.delegate = self
request.start()
}
//购买
func buyProduct() {
guard let product = self.product else {
//如果没有缓存产品,先请求再购买(实际可结合回调)
fetchProducts()
return
}
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
}
extension StoreKitManager1: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
if let product = response.products.first {
self.product = product
print("get product success: \(product.productIdentifier)")
} else {
print("no checkout products")
}
}
func request(_ request: SKRequest, didFailWithError error: any Error) {
print("get product error: \(error.localizedDescription)")
}
}
extension StoreKitManager1: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
//购买成功
UserDefaults.standard.set(true, forKey: purchaseKey)
UserDefaults.standard.synchronize() // 可选
print("购买成功,已本地保存状态")
// 完成交易
SKPaymentQueue.default().finishTransaction(transaction)
purchaseCompletion?(true)
case .failed:
//购买失败
print("购买失败: \(transaction.error?.localizedDescription ?? "未知错误")")
SKPaymentQueue.default().finishTransaction(transaction)
purchaseCompletion?(false)
case .restored:
// 恢复购买(非消耗型或自动续期订阅)
// 同样保存状态
UserDefaults.standard.set(true, forKey: purchaseKey)
UserDefaults.standard.synchronize()
print("购买恢复成功,已本地保存")
SKPaymentQueue.default().finishTransaction(transaction)
purchaseCompletion?(true)
case .purchasing, .deferred:
// 正在购买或等待确认,无需处理
break
@unknown default:
break
}
}
}
}
StoreKit2(适用于iOS15及之后)
import UIKit
import StoreKit
class StoreKitManager2 {
private let productID = "com.your.app.product"
private let userID = "user_123"
//单例
static let shared = StoreKitManager2()
private init() {
startTransactionListener()
}
private(set) var isPurchased: Bool = false {
didSet {
DispatchQueue.main.async { [weak self] in
guard let `self` = self else { return }
self.purchaseStatusChanged?(self.isPurchased)
}
}
}
private var products: [Product] = []
private var isPurchasing: Bool = false
private var transactionListenerTask: Task<Void, Never>?
//购买状态变化
public var purchaseStatusChanged: ((Bool) -> ())?
//产品信息加载完成
public var productsLoaded: (([Product]) -> ())?
//购买尝试完成(成功/失败)
public var purchaseCompleted: ((Bool) -> ())?
//启动监听
private func startTransactionListener() {
transactionListenerTask = Task.detached { [weak self] in
for await verificationResult in Transaction.updates {
guard let `self` = self else { break }
await self.handleTransactionUpdate(verificationResult)
}
}
}
//加载产品
public func loadProducts() {
Task { [weak self] in
guard let `self` = self else { return }
do {
let productList = try await Product.products(for: [self.productID])
await MainActor.run {
self.products = productList
self.productsLoaded?(productList)
}
} catch {
print("加载产品失败:\(error.localizedDescription)")
}
}
}
//购买
public func purchase() {
guard !isPurchasing, let product = products.first else { return }
Task { [weak self] in
guard let `self` = self else { return }
await MainActor.run {
self.isPurchasing = true
}
defer {
Task { @MainActor in
self.isPurchasing = false
}
}
do {
let result = try await product.purchase()
switch result {
case .success(let verificationResult):
let transaction = try self.checkVerification(verificationResult)
let valid = await self.verifyWithServer(transaction)
if valid {
await transaction.finish()
await self.fetchPurchaseStatus()
await MainActor.run {
self.purchaseCompleted?(true)
}
} else {
//服务器验证失败
await MainActor.run {
self.purchaseCompleted?(false)
}
}
case .userCancelled:
//用户取消购买
await MainActor.run {
self.purchaseCompleted?(false)
}
case .pending:
print("交易等待中")
@unknown default:
break
}
} catch {
print("购买出错:\(error.localizedDescription)")
await MainActor.run {
self.purchaseCompleted?(false)
}
}
}
}
//刷新状态
public func refreshPurchaseStatus() {
Task { [weak self] in
await self?.fetchPurchaseStatus()
}
}
deinit {
transactionListenerTask?.cancel()
}
//处理交易更新(来自监听)
private func handleTransactionUpdate(_ verificationResult: VerificationResult<Transaction>) async {
do {
let transaction = try checkVerification(verificationResult)
guard transaction.revocationDate == nil && !transaction.isUpgraded else {
//交易被撤销,重新从服务器获取状态
await fetchPurchaseStatus()
await transaction.finish()
return
}
if transaction.productID == self.productID {
// 如果发现有未完成的购买,再次验证(通常购买流程已处理)
let valid = await verifyWithServer(transaction)
if valid {
await transaction.finish()
await fetchPurchaseStatus()
}
}
} catch {
print("交易失败,有内鬼:\(error.localizedDescription)")
}
}
//验证交易签名
private func checkVerification<T>(_ result: VerificationResult<T>) throws -> T {
switch result {
case .unverified(let signedType, let verificationError):
throw verificationError
case .verified(let signedType):
return signedType
}
}
//从服务器获取购买状态(模拟)
private func fetchPurchaseStatus() async {
//模拟网络延迟
try? await Task.sleep(nanoseconds: 800_000_000)
let request = [
"userId": userID,
"productId": productID
]
print("查询购买状态: \(request)")
// 模拟服务器返回(这里固定为 true,实际可改为从网络获取)
let serverStatus = true
print("服务器返回状态: \(serverStatus)")
await MainActor.run {
self.isPurchased = serverStatus
}
}
//模拟服务器验证交易
private func verifyWithServer(_ transaction: Transaction) async -> Bool {
//模拟网络延迟
try? await Task.sleep(nanoseconds: 1_500_000_000)
let payload = [
"transactionId": "\(transaction.id)",
"productId": transaction.productID,
"userId": userID
]
//模拟服务器响应(假设总是成功)
let serverResponse = ["valid": true]
return (serverResponse["valid"]) ?? false
}
}
控制器里调用
import UIKit
class StoreKitManagerViewController: UIViewController {
//
private let storeManager2 = StoreKitManager2.shared
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func storeKitManager1() {
//在 App 启动时初始化(例如在 AppDelegate 或 SceneDelegate 中):
StoreKitManager1.shared.setup()
// 如果需要预加载产品信息
StoreKitManager1.shared.fetchProducts()
}
//购买
func buyTapped1() {
StoreKitManager1.shared.buyProduct()
}
//是否购买完成
func buyResult1() {
print(StoreKitManager1.shared.isPurchasedLocally)
}
/********************************************/
func storeKitManager2() {
storeManager2.purchaseStatusChanged = { [weak self] isPurchased in
//购买状态
print(isPurchased)
}
storeManager2.productsLoaded = { [weak self] products in
if let product = products.first {
print("产品信息:\(product)")
}
}
storeManager2.purchaseCompleted = { [weak self] isSuccess in
print("是否成功购买:\(isSuccess)")
}
// 加载产品 & 刷新状态
storeManager2.loadProducts()
storeManager2.refreshPurchaseStatus()
}
//购买
func buyTapped2() {
storeManager2.purchase()
}
func restoreTapped2() {
// 重新从服务器拉取
storeManager2.refreshPurchaseStatus()
}
}
有任何问题请留言讨论

浙公网安备 33010602011771号