我正在尝试实现新的
paymentQueue(_:shouldAddStorePayment:for:)
方法,以便我的应用程序可以直接从App Store处理IAP.
我正在使用itms-services:// url来测试它,就像它说的那样here.
问题是,我的SKPaymentTransactionObserver是一个特定的视图控制器,如果在打开itms-services://链接时它不可见,则不会调用委托方法.
我该怎么办?我想我必须检测用户是否来自App Store推送正确的视图控制器,但我不知道如何.我现在能想到的唯一另一个选择是让App Delegate成为SKPaymentTransactionObserver,但这看起来真的很麻烦,当我尝试它时我无法让它工作.还有别的办法吗?
解决方法@H_301_10@
这是我所做的一个可以帮助你实现你想要的类,只需复制下面的代码并将其粘贴到一个新文件中,然后你可以简单地访问类StoreManager.shared到你想要访问的任何方法/变量.
1-要初始化此类,只需从didFinishLaunchingWithOptions调用即可
StoreManager.shared.Begin()然后添加付款观察员.
import Foundation
import StoreKit
class StoreManager: NSObject{
/**
Initialize StoreManager and load subscriptions SKProducts from Store
*/
static let shared = StoreManager()
func Begin(){
print("StoreManager initialized"))
}
override init() {
super.init()
// Add pyament observer to payment qu
SKPaymentQueue.default().add(self)
}
func requestProductWithID(identifers:Set<String>){
if SKPaymentQueue.canMakePayments() {
let request = SKProductsRequest(productIdentifiers:
identifers)
request.delegate = self
request.start()
} else {
print("ERROR: Store Not Available")
}
}
func buyProduct(product: SKProduct) {
print("Buying \(product.productIdentifier)...")
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
func restorePurchases(){
SKPaymentQueue.default().restoreCompletedTransactions()
}
/*
Instance variables
*/
}
// MARK:
// MARK: SKProductsRequestDelegate
//The delegate receives the product information that the request was interested in.
extension StoreManager:SKProductsRequestDelegate{
func productsRequest(_ request: SKProductsRequest,didReceive response: SKProductsResponse) {
var products = response.products as [SKProduct]
var buys = [SKProduct]()
if (products.count > 0) {
for i in 0 ..< products.count
{
let product = products[i]
print("Product Found: ",product.localizedTitle)
}
} else {
print("No products found")
}
let productsInvalidIds = response.invalidProductIdentifiers
for product in productsInvalidIds
{
print("Product not found: \(product)")
}
}
func request(_ request: SKRequest,didFailWithError error: Error) {
print("Something went wrong: \(error.localizedDescription)")
}
}
// MARK:
// MARK: SKTransactions
extension StoreManager: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue,updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch (transaction.transactionState) {
case .purchased:
completeTransaction(transaction: transaction)
break
case .Failed:
FailedTransaction(transaction: transaction)
break
case .restored:
restoreTransaction(transaction: transaction)
break
case .deferred:
// TODO show user that is waiting for approval
break
case .purchasing:
break
}
}
}
private func completeTransaction(transaction: SKPaymentTransaction) {
print("completeTransaction...")
deliverPurchaseForIdentifier(identifier: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func restoreTransaction(transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
print("restoreTransaction... \(productIdentifier)")
deliverPurchaseForIdentifier(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func FailedTransaction(transaction: SKPaymentTransaction) {
if let error = transaction.error as NSError? {
if error.domain == SKErrorDomain {
// handle all possible errors
switch (error.code) {
case SKError.unknown.rawValue:
print("Unknown error")
case SKError.clientInvalid.rawValue:
print("client is not allowed to issue the request")
case SKError.paymentCancelled.rawValue:
print("user cancelled the request")
case SKError.paymentInvalid.rawValue:
print("purchase identifier was invalid")
case SKError.paymentNotAllowed.rawValue:
print("this device is not allowed to make the payment")
default:
break;
}
}
}
SKPaymentQueue.default().finishTransaction(transaction)
}
private func deliverPurchaseForIdentifier(identifier: String?) {
guard let identifier = identifier else { return }
}
}
//In-App Purchases App Store
extension StoreManager{
func paymentQueue(_ queue: SKPaymentQueue,shouldAddStorePayment payment: SKPayment,for product: SKProduct) -> Bool {
return true
//To hold
//return false
//And then to continue
//SKPaymentQueue.default().add(savedPayment)
}
}
1-要初始化此类,只需从didFinishLaunchingWithOptions调用即可
StoreManager.shared.Begin()然后添加付款观察员.
import Foundation import StoreKit class StoreManager: NSObject{ /** Initialize StoreManager and load subscriptions SKProducts from Store */ static let shared = StoreManager() func Begin(){ print("StoreManager initialized")) } override init() { super.init() // Add pyament observer to payment qu SKPaymentQueue.default().add(self) } func requestProductWithID(identifers:Set<String>){ if SKPaymentQueue.canMakePayments() { let request = SKProductsRequest(productIdentifiers: identifers) request.delegate = self request.start() } else { print("ERROR: Store Not Available") } } func buyProduct(product: SKProduct) { print("Buying \(product.productIdentifier)...") let payment = SKPayment(product: product) SKPaymentQueue.default().add(payment) } func restorePurchases(){ SKPaymentQueue.default().restoreCompletedTransactions() } /* Instance variables */ } // MARK: // MARK: SKProductsRequestDelegate //The delegate receives the product information that the request was interested in. extension StoreManager:SKProductsRequestDelegate{ func productsRequest(_ request: SKProductsRequest,didReceive response: SKProductsResponse) { var products = response.products as [SKProduct] var buys = [SKProduct]() if (products.count > 0) { for i in 0 ..< products.count { let product = products[i] print("Product Found: ",product.localizedTitle) } } else { print("No products found") } let productsInvalidIds = response.invalidProductIdentifiers for product in productsInvalidIds { print("Product not found: \(product)") } } func request(_ request: SKRequest,didFailWithError error: Error) { print("Something went wrong: \(error.localizedDescription)") } } // MARK: // MARK: SKTransactions extension StoreManager: SKPaymentTransactionObserver { public func paymentQueue(_ queue: SKPaymentQueue,updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { switch (transaction.transactionState) { case .purchased: completeTransaction(transaction: transaction) break case .Failed: FailedTransaction(transaction: transaction) break case .restored: restoreTransaction(transaction: transaction) break case .deferred: // TODO show user that is waiting for approval break case .purchasing: break } } } private func completeTransaction(transaction: SKPaymentTransaction) { print("completeTransaction...") deliverPurchaseForIdentifier(identifier: transaction.payment.productIdentifier) SKPaymentQueue.default().finishTransaction(transaction) } private func restoreTransaction(transaction: SKPaymentTransaction) { guard let productIdentifier = transaction.original?.payment.productIdentifier else { return } print("restoreTransaction... \(productIdentifier)") deliverPurchaseForIdentifier(identifier: productIdentifier) SKPaymentQueue.default().finishTransaction(transaction) } private func FailedTransaction(transaction: SKPaymentTransaction) { if let error = transaction.error as NSError? { if error.domain == SKErrorDomain { // handle all possible errors switch (error.code) { case SKError.unknown.rawValue: print("Unknown error") case SKError.clientInvalid.rawValue: print("client is not allowed to issue the request") case SKError.paymentCancelled.rawValue: print("user cancelled the request") case SKError.paymentInvalid.rawValue: print("purchase identifier was invalid") case SKError.paymentNotAllowed.rawValue: print("this device is not allowed to make the payment") default: break; } } } SKPaymentQueue.default().finishTransaction(transaction) } private func deliverPurchaseForIdentifier(identifier: String?) { guard let identifier = identifier else { return } } } //In-App Purchases App Store extension StoreManager{ func paymentQueue(_ queue: SKPaymentQueue,shouldAddStorePayment payment: SKPayment,for product: SKProduct) -> Bool { return true //To hold //return false //And then to continue //SKPaymentQueue.default().add(savedPayment) } }