Initial commit
This commit is contained in:
@ -6,13 +6,197 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import StoreKit
|
||||
|
||||
struct IAPTestView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
enum IAPProductTest: String, CaseIterable {
|
||||
case premiumFeature1 = "grammar_1_month"
|
||||
case premiumFeature2 = "grammar_1_week"
|
||||
|
||||
}
|
||||
|
||||
|
||||
class IAPManagerTest: ObservableObject {
|
||||
@Published var products: [Product] = []
|
||||
@Published var purchasedProducts: [Product] = []
|
||||
|
||||
init() {
|
||||
Task {
|
||||
await requestProducts()
|
||||
await updatePurchasedProducts()
|
||||
await listenForTransactions()
|
||||
}
|
||||
}
|
||||
|
||||
func requestProducts() async {
|
||||
do {
|
||||
let products = try await Product.products(for: IAPProductTest.allCases.map { $0.rawValue })
|
||||
DispatchQueue.main.async {
|
||||
// 按照产品的权重排序
|
||||
self.products = products
|
||||
|
||||
// 打印每个产品及其相关变量
|
||||
for product in self.products {
|
||||
print("--------------------------")
|
||||
print("Product ID: \(product.id)")
|
||||
print("Product Title: \(product.displayName)")
|
||||
print("Product Description: \(product.description)")
|
||||
print("Product Price: \(product.price)")
|
||||
print("Product displayPrice: \(product.displayPrice)")
|
||||
print("Product priceFormatStyle: \(product.priceFormatStyle)")
|
||||
print("Product subscriptionPeriodFormatStyle: \(product.subscriptionPeriodFormatStyle)")
|
||||
print("Product subscriptionPeriodUnitFormatStyle: \(product.subscriptionPeriodUnitFormatStyle)")
|
||||
print("--------------------------")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("Failed to fetch products: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
func buy(product: Product) async {
|
||||
do {
|
||||
let uuid = UUID()
|
||||
let token = Product.PurchaseOption.appAccountToken(uuid)
|
||||
print("purchase appAccountToken: \(uuid.uuidString)")
|
||||
|
||||
let result = try await product.purchase(options: [token])
|
||||
switch result {
|
||||
case .success(let verification):
|
||||
if case .verified(let transaction) = verification {
|
||||
// 在这里不需要处理交易完成,详细处理放在 listenForTransactions 中
|
||||
// 如果购买成功了,再点击这个按钮,会直接到这里
|
||||
print("Purchase initiated for product: \(product.id)")
|
||||
}
|
||||
case .userCancelled:
|
||||
print("User cancelled the purchase.")
|
||||
case .pending:
|
||||
print("Purchase is pending.")
|
||||
default:
|
||||
break
|
||||
}
|
||||
} catch {
|
||||
print("Failed to purchase product: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
func updatePurchasedProducts() async {
|
||||
for await result in Transaction.currentEntitlements {
|
||||
if case .verified(let transaction) = result {
|
||||
if let product = products.first(where: { $0.id == transaction.productID }) {
|
||||
DispatchQueue.main.async {
|
||||
self.purchasedProducts.append(product)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func listenForTransactions() async {
|
||||
for await transactionResult in Transaction.updates {
|
||||
if case .verified(let transaction) = transactionResult {
|
||||
if let product = products.first(where: { $0.id == transaction.productID }) {
|
||||
DispatchQueue.main.async {
|
||||
self.purchasedProducts.append(product)
|
||||
}
|
||||
}
|
||||
|
||||
// 打印详细的交易信息,为什么会有历史交易?
|
||||
print("Transaction ID: \(transaction.id)")
|
||||
print("Product ID: \(transaction.productID)")
|
||||
print("Purchase Date: \(transaction.purchaseDate)")
|
||||
//print("Transaction State: \(transaction.revocationReason ?? "None")")
|
||||
//print("Original Transaction ID: \(transaction.originalID ?? "None")")
|
||||
|
||||
// 获取票据数据
|
||||
|
||||
// 获取 jsonRepresentation
|
||||
let jsonData = try transaction.jsonRepresentation
|
||||
|
||||
// 将 Data 转换为 String
|
||||
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||
print("Transaction Receipt: \(jsonString)")
|
||||
} else {
|
||||
print("Failed to convert JSON data to string.")
|
||||
}
|
||||
|
||||
await transaction.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func restorePurchases() async {
|
||||
do {
|
||||
try await AppStore.sync()
|
||||
await updatePurchasedProducts()
|
||||
print("Purchases restored")
|
||||
} catch {
|
||||
print("Failed to restore purchases: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct IAPTestView: View {
|
||||
@StateObject var iapManager = IAPManager()
|
||||
//@StateObject var iapManager = IAPManagerTest()
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
if iapManager.products.isEmpty {
|
||||
Text("Loading products...")
|
||||
} else {
|
||||
ForEach(iapManager.products, id: \.id) { product in
|
||||
VStack {
|
||||
Text(product.displayName)
|
||||
.font(.title)
|
||||
|
||||
Button("Buy \(product.displayName)") {
|
||||
Task {
|
||||
await iapManager.buy(product: product){ result in
|
||||
switch result {
|
||||
case .success(let message):
|
||||
logger.info("succ")
|
||||
case .failure(let error):
|
||||
logger.error("error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color.blue)
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(10)
|
||||
}
|
||||
}
|
||||
|
||||
Button("Restore Purchases") {
|
||||
Task {
|
||||
await iapManager.restorePurchases(){ result in
|
||||
switch result {
|
||||
case .success(let message):
|
||||
logger.info("restore purchase succ. message: \(message)")
|
||||
case .failure(let error):
|
||||
logger.error("restore purchase error. message: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color.green)
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(10)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
Task {
|
||||
//await iapManager.requestProducts()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#Preview {
|
||||
IAPTestView()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user