Ios 如何处理为应用商店兑换消费促销代码

Ios 如何处理为应用商店兑换消费促销代码,ios,in-app-purchase,app-store,Ios,In App Purchase,App Store,我到处都在寻找这个问题,但没有找到我问题的答案。这是一个场景: 我在应用商店有一个游戏直播。我有x个硬币的可消费IAP。我为一个用户生成了一个促销代码,以获得一些免费硬币。他在应用商店里成功地兑换了密码,但当他打开我的游戏时,他的硬币没有被记入帐户。他试着点击“恢复”按钮,重新启动他的设备,然后注销,然后用他的苹果ID再次登录,但没有任何效果 我用另一个可消费的促销代码自己尝试了一下,但也无法让它工作。然而,我成功地赎回了非消耗品IAP 所以我的问题是,我必须处理代码中使用的可消费促销代码吗?否

我到处都在寻找这个问题,但没有找到我问题的答案。这是一个场景:

我在应用商店有一个游戏直播。我有x个硬币的可消费IAP。我为一个用户生成了一个促销代码,以获得一些免费硬币。他在应用商店里成功地兑换了密码,但当他打开我的游戏时,他的硬币没有被记入帐户。他试着点击“恢复”按钮,重新启动他的设备,然后注销,然后用他的苹果ID再次登录,但没有任何效果

我用另一个可消费的促销代码自己尝试了一下,但也无法让它工作。然而,我成功地赎回了非消耗品IAP

所以我的问题是,我必须处理代码中使用的可消费促销代码吗?否则,用户如何兑换消费促销代码

编辑:显示我的代码

GameStoreViewController.swift(从表视图中选择要购买的IAP)

IAPHelper.swift:

import StoreKit

/// Notification that is generated when a product is purchased.
public let IAPHelperPurchaseNotification = "IAPHelperPurchaseNotification"

/// Notification that is generated when a transaction fails.
public let IAPHelperTransactionFailedNotification = "IAPHelperTransactionFailedNotification"

/// Notification that is generated when cannot retrieve IAPs from iTunes.
public let IAPHelperConnectionErrorNotification = "IAPHelperConnectionErrorNotification"

/// Notification that is generated when we need to stop the spinner.
public let IAPHelperStopSpinnerNotification = "IAPHelperStopSpinnerNotification"



/// Product identifiers are unique strings registered on the app store.
public typealias ProductIdentifier = String

/// Completion handler called when products are fetched.
public typealias ProductsRequestCompletionHandler = (_ success: Bool, _ products: [SKProduct]?) -> ()


/// A Helper class for In-App-Purchases.
open class IAPHelper : NSObject  {

/// MARK: - User facing API

fileprivate let productIdentifiers: Set<ProductIdentifier>
fileprivate var purchasedProductIdentifiers = Set<ProductIdentifier>()

fileprivate var productsRequest: SKProductsRequest?
fileprivate var productsRequestCompletionHandler: ProductsRequestCompletionHandler?

// These two notifications are private, so are needed in addition to the public ones on line 12
//static let IAPHelperPurchaseNotification = "IAPHelperPurchaseNotification"
//static let IAPHelperTransactionFailedNotification = "IAPHelperTransactionFailedNotification"

/// Initialize the helper.  Pass in the set of ProductIdentifiers supported by the app.
public init(productIds: Set<ProductIdentifier>) {
    self.productIdentifiers = productIds

    for productIdentifier in productIds {
        let purchased = UserDefaults.standard.bool(forKey: productIdentifier)
        if purchased {
            purchasedProductIdentifiers.insert(productIdentifier)
            print("Previously purchased: \(productIdentifier)")
        } else {
            print("Not purchased: \(productIdentifier)")
        }
    }

    super.init()

    SKPaymentQueue.default().add(self)
}
}

// MARK: - StoreKit API

extension IAPHelper {

public func requestProducts(_ completionHandler: @escaping ProductsRequestCompletionHandler) {
    productsRequest?.cancel()
    productsRequestCompletionHandler = completionHandler

    productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
    productsRequest!.delegate = self
    productsRequest!.start()
}

public func buyProduct(_ product: SKProduct) {
    print("Buying \(product.productIdentifier)...")
    let payment = SKPayment(product: product)
    SKPaymentQueue.default().add(payment)
}

public func isProductPurchased(_ productIdentifier: ProductIdentifier) -> Bool {
    return purchasedProductIdentifiers.contains(productIdentifier)
}

public class func canMakePayments() -> Bool {
    return SKPaymentQueue.canMakePayments()
}

public func restorePurchases() {
    SKPaymentQueue.default().restoreCompletedTransactions()
}

// Adding functions from SA
public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
    print("Restore queue finished.")
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperStopSpinnerNotification), object: nil)
}

public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
    print("Restore queue failed.")
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperConnectionErrorNotification), object: nil)
}

}

// MARK: - SKProductsRequestDelegate

extension IAPHelper: SKProductsRequestDelegate {
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    print("Loaded list of products...")
    let products = response.products
    productsRequestCompletionHandler?(true, products)
    clearRequestAndHandler()

    for p in products {
        print("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
    }
}

public func request(_ request: SKRequest, didFailWithError error: Error) {
    print("Failed to load list of products.")
    print("Error: \(error.localizedDescription)")
    productsRequestCompletionHandler?(false, nil)
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperConnectionErrorNotification), object: nil)
    clearRequestAndHandler()
}

fileprivate func clearRequestAndHandler() {
    productsRequest = nil
    productsRequestCompletionHandler = nil
}
}

// MARK: - SKPaymentTransactionObserver

extension IAPHelper: SKPaymentTransactionObserver {

public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        switch (transaction.transactionState) {
        case .purchased:
            completeTransaction(transaction)
            break
        case .failed:
            failedTransaction(transaction)
            break
        case .restored:
            restoreTransaction(transaction)
            break
        case .deferred:
            break
        case .purchasing:
            break
        }
    }
}

fileprivate func completeTransaction(_ transaction: SKPaymentTransaction) {
    print("completeTransaction...")
    deliverPurchaseNotificationForIdentifier(transaction.payment.productIdentifier)
    SKPaymentQueue.default().finishTransaction(transaction)
}

fileprivate func restoreTransaction(_ transaction: SKPaymentTransaction) {
    guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }

    print("restoreTransaction... \(productIdentifier)")
    deliverPurchaseNotificationForIdentifier(productIdentifier)
    SKPaymentQueue.default().finishTransaction(transaction)
}

fileprivate func failedTransaction(_ transaction: SKPaymentTransaction) {
    print("failedTransaction...")
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperStopSpinnerNotification), object: nil)
    if transaction.error!._code != SKError.paymentCancelled.rawValue {
        print("Transaction Error: \(String(describing: transaction.error?.localizedDescription))")
        NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperTransactionFailedNotification), object: nil)
    } else {
        print("Transaction Error else statement")
    }

    SKPaymentQueue.default().finishTransaction(transaction)
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperTransactionFailedNotification), object: nil)

}

fileprivate func deliverPurchaseNotificationForIdentifier(_ identifier: String?) {
    guard let identifier = identifier else { return }

    purchasedProductIdentifiers.insert(identifier)
    UserDefaults.standard.set(true, forKey: identifier)
    UserDefaults.standard.synchronize()
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperPurchaseNotification), object: identifier)
}
}
导入存储套件
///购买产品时生成的通知。
public let iaphelperpurchasenotify=“iaphelperpurchasenotify”
///事务失败时生成的通知。
public let IAPHelperTransactionFailedNotification=“IAPHelperTransactionFailedNotification”
///无法从iTunes检索IAP时生成的通知。
public let IAPHelperConnectionErrorNotification=“IAPHelperConnectionErrorNotification”
///需要停止微调器时生成的通知。
公共租赁IAPHELPERSOPPINERNOTIATION=“IAPHELPERSOPPINERNOTIATION”
///产品标识符是在应用商店上注册的唯一字符串。
公共类型别名ProductIdentifier=字符串
///获取产品时调用的完成处理程序。
公共类型别名ProductsRequestCompletionHandler=(\uSuccess:Bool,\uProducts:[SKProduct]?)->()
///用于应用内购买的帮助器类。
开放类IAPHelper:NSObject{
///MARK:-面向用户的API
fileprivate let productIdentifiers:设置
fileprivate var purchasedProductIdentifiers=Set()
fileprivate var productsRequest:SKProductsRequest?
fileprivate var productsRequestCompletionHandler:productsRequestCompletionHandler?
//这两个通知是私有的,因此除了第12行的公共通知外,还需要这两个通知
//静态let IAPHelperPurchaseNotification=“IAPHelperPurchaseNotification”
//静态let IAPHelperTransactionFailedNotification=“IAPHelperTransactionFailedNotification”
///初始化帮助程序。传入应用程序支持的ProductIdentifier集。
公共初始化(productid:Set){
self.productIdentifiers=productId
对于ProductID中的productIdentifier{
let purchased=UserDefaults.standard.bool(forKey:productIdentifier)
如果购买{
PurchasedProductIdentifier.insert(productIdentifier)
打印(“以前购买的:\(productIdentifier)”)
}否则{
打印(“未购买:\(productIdentifier)”)
}
}
super.init()
SKPaymentQueue.default().add(self)
}
}
//MARK:-StoreKit API
分机{
public func requestProducts(completionHandler:@escaping ProductsRequestCompletionHandler){
productsRequest?.cancel()
productsRequestCompletionHandler=completionHandler
productsRequest=SKProductsRequest(productIdentifiers:productIdentifiers)
productsRequest!.delegate=self
productsRequest!.start()
}
公共func buyProduct(产品:SKProduct){
打印(“购买\(product.productIdentifier)…”)
let payment=SKPayment(产品:产品)
SKPaymentQueue.default().add(付款)
}
公共函数isProductPurchased(productIdentifier:productIdentifier)->Bool{
返回PurchasedProductIdentifier.contains(productIdentifier)
}
公共类func canMakePayments()->Bool{
返回SKPaymentQueue.canMakePayments()
}
公共职能恢复采购(){
SKPaymentQueue.default().restoreCompletedTransactions()
}
//从SA添加函数
public func paymentQueueRestoreCompletedTransactionsFinished(队列:SKPaymentQueue){
打印(“还原队列已完成”)
NotificationCenter.default.post(名称:Notification.name(rawValue:IapherPersTopSpinnerNotification),对象:nil)
}
public func paymentQueue(queue:SKPaymentQueue,RestoreCompletedTransactionsFailedWither错误:错误){
打印(“还原队列失败”)
NotificationCenter.default.post(名称:Notification.name(rawValue:IAPHelperConnectionErrorNotification),对象:nil)
}
}
//标记:-SKProductsRequestDelegate
扩展IAPHelper:SKProductsRequestDelegate{
public func productsRequest(u请求:SKProductsRequest,didReceive响应:SKProductsResponse){
打印(“已加载的产品列表…”)
让产品=响应.products
productsRequestCompletionHandler?(true,产品)
clearRequestAndHandler()
产品中的p{
打印(“找到的产品:\(p.productIdentifier)\(p.localizedTitle)\(p.price.floatValue)”)
}
}
公共函数请求(请求:SKRequest,错误:error){
打印(“未能加载产品列表”)
打印(“错误:\(Error.localizedDescription)”)
productsRequestCompletionHandler?(false,nil)
NotificationCenter.default.post(名称:Notification.name(rawValue:IAPHelperConnectionErrorNotification),对象:nil)
clearRequestAndHandler()
}
fileprivate func clearRequestAndHandler(){
productsRequest=nil
productsRequestCompletionHandler=nil
}
}
//MARK:-SKPaymentTransactionObserver
扩展IAPHelper:SKPaymentTransactionObserver{
public func paymentQueue(queue:SKPaymentQueue,updatedTransactions事务:[SKPaymentTransaction]){
交易中的交易{
开关(transaction.transactionState){
案例。购买:
completeTransaction(事务)
打破
案例。失败:
失败的交易(交易)
打破
案件.恢复:
import StoreKit

/// Notification that is generated when a product is purchased.
public let IAPHelperPurchaseNotification = "IAPHelperPurchaseNotification"

/// Notification that is generated when a transaction fails.
public let IAPHelperTransactionFailedNotification = "IAPHelperTransactionFailedNotification"

/// Notification that is generated when cannot retrieve IAPs from iTunes.
public let IAPHelperConnectionErrorNotification = "IAPHelperConnectionErrorNotification"

/// Notification that is generated when we need to stop the spinner.
public let IAPHelperStopSpinnerNotification = "IAPHelperStopSpinnerNotification"



/// Product identifiers are unique strings registered on the app store.
public typealias ProductIdentifier = String

/// Completion handler called when products are fetched.
public typealias ProductsRequestCompletionHandler = (_ success: Bool, _ products: [SKProduct]?) -> ()


/// A Helper class for In-App-Purchases.
open class IAPHelper : NSObject  {

/// MARK: - User facing API

fileprivate let productIdentifiers: Set<ProductIdentifier>
fileprivate var purchasedProductIdentifiers = Set<ProductIdentifier>()

fileprivate var productsRequest: SKProductsRequest?
fileprivate var productsRequestCompletionHandler: ProductsRequestCompletionHandler?

// These two notifications are private, so are needed in addition to the public ones on line 12
//static let IAPHelperPurchaseNotification = "IAPHelperPurchaseNotification"
//static let IAPHelperTransactionFailedNotification = "IAPHelperTransactionFailedNotification"

/// Initialize the helper.  Pass in the set of ProductIdentifiers supported by the app.
public init(productIds: Set<ProductIdentifier>) {
    self.productIdentifiers = productIds

    for productIdentifier in productIds {
        let purchased = UserDefaults.standard.bool(forKey: productIdentifier)
        if purchased {
            purchasedProductIdentifiers.insert(productIdentifier)
            print("Previously purchased: \(productIdentifier)")
        } else {
            print("Not purchased: \(productIdentifier)")
        }
    }

    super.init()

    SKPaymentQueue.default().add(self)
}
}

// MARK: - StoreKit API

extension IAPHelper {

public func requestProducts(_ completionHandler: @escaping ProductsRequestCompletionHandler) {
    productsRequest?.cancel()
    productsRequestCompletionHandler = completionHandler

    productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
    productsRequest!.delegate = self
    productsRequest!.start()
}

public func buyProduct(_ product: SKProduct) {
    print("Buying \(product.productIdentifier)...")
    let payment = SKPayment(product: product)
    SKPaymentQueue.default().add(payment)
}

public func isProductPurchased(_ productIdentifier: ProductIdentifier) -> Bool {
    return purchasedProductIdentifiers.contains(productIdentifier)
}

public class func canMakePayments() -> Bool {
    return SKPaymentQueue.canMakePayments()
}

public func restorePurchases() {
    SKPaymentQueue.default().restoreCompletedTransactions()
}

// Adding functions from SA
public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
    print("Restore queue finished.")
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperStopSpinnerNotification), object: nil)
}

public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
    print("Restore queue failed.")
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperConnectionErrorNotification), object: nil)
}

}

// MARK: - SKProductsRequestDelegate

extension IAPHelper: SKProductsRequestDelegate {
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    print("Loaded list of products...")
    let products = response.products
    productsRequestCompletionHandler?(true, products)
    clearRequestAndHandler()

    for p in products {
        print("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
    }
}

public func request(_ request: SKRequest, didFailWithError error: Error) {
    print("Failed to load list of products.")
    print("Error: \(error.localizedDescription)")
    productsRequestCompletionHandler?(false, nil)
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperConnectionErrorNotification), object: nil)
    clearRequestAndHandler()
}

fileprivate func clearRequestAndHandler() {
    productsRequest = nil
    productsRequestCompletionHandler = nil
}
}

// MARK: - SKPaymentTransactionObserver

extension IAPHelper: SKPaymentTransactionObserver {

public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        switch (transaction.transactionState) {
        case .purchased:
            completeTransaction(transaction)
            break
        case .failed:
            failedTransaction(transaction)
            break
        case .restored:
            restoreTransaction(transaction)
            break
        case .deferred:
            break
        case .purchasing:
            break
        }
    }
}

fileprivate func completeTransaction(_ transaction: SKPaymentTransaction) {
    print("completeTransaction...")
    deliverPurchaseNotificationForIdentifier(transaction.payment.productIdentifier)
    SKPaymentQueue.default().finishTransaction(transaction)
}

fileprivate func restoreTransaction(_ transaction: SKPaymentTransaction) {
    guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }

    print("restoreTransaction... \(productIdentifier)")
    deliverPurchaseNotificationForIdentifier(productIdentifier)
    SKPaymentQueue.default().finishTransaction(transaction)
}

fileprivate func failedTransaction(_ transaction: SKPaymentTransaction) {
    print("failedTransaction...")
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperStopSpinnerNotification), object: nil)
    if transaction.error!._code != SKError.paymentCancelled.rawValue {
        print("Transaction Error: \(String(describing: transaction.error?.localizedDescription))")
        NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperTransactionFailedNotification), object: nil)
    } else {
        print("Transaction Error else statement")
    }

    SKPaymentQueue.default().finishTransaction(transaction)
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperTransactionFailedNotification), object: nil)

}

fileprivate func deliverPurchaseNotificationForIdentifier(_ identifier: String?) {
    guard let identifier = identifier else { return }

    purchasedProductIdentifiers.insert(identifier)
    UserDefaults.standard.set(true, forKey: identifier)
    UserDefaults.standard.synchronize()
    NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelperPurchaseNotification), object: identifier)
}
}
import Foundation

// Use enum as a simple namespace.  (It has no cases so you can't instantiate it.)
public struct IAPList {

  /// TODO:  Change this to whatever you set on iTunes connect
  fileprivate static let Prefix = "com.xxx.xxx."

  /// MARK: - Supported Product Identifiers
  /// List your IAPs here:
  public static let PackOf4000Coins =   Prefix + "4000Coins"   
  public static let PackOf10000Coins =  Prefix + "10000Coins"
  public static let PackOf30000Coins =  Prefix + "30000Coins"
  public static let PackOf75000Coins =  Prefix + "75000Coins"
  public static let PackOf175000Coins = Prefix + "175000Coins"
  public static let RemoveAds =  Prefix + "RemoveAds"
  public static let PlayerEditor =  Prefix + "PlayerEditor"

  // All of the products assembled into a set of product identifiers.
  fileprivate static let productIdentifiers: Set<ProductIdentifier> = 
  [IAPList.PackOf4000Coins, IAPList.PackOf10000Coins, IAPList.PackOf30000Coins, 
IAPList.PackOf75000Coins, PackOf175000Coins, RemoveAds, PlayerEditor]

  /// Static instance of IAPHelper.
  public static let store = IAPHelper(productIds: IAPList.productIdentifiers)
}

  /// Return the resource name for the product identifier.
  func resourceNameForProductIdentifier(_ productIdentifier: String) -> String? {
      return productIdentifier.components(separatedBy: ".").last
}