应用程序无法处理可消耗产品的应用内购买促销代码赎回。

20

我的应用程序内置了应用内购买(我遵循了这个教程),购买功能正常工作。但是,当我在App Store中为其中一个应用内购买产品兑换促销代码时,我的应用程序没有响应它。即使App Store显示该产品已成功兑换,我的应用程序也没有响应。

是否有使用应用内购买的人测试过您的应用程序是否能够处理促销代码?您介意分享解决方案吗?

我是从这里开始的:

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self,
        selector: #selector(applicationDidBecomeActive(notification:)),
        name: NSNotification.Name.UIApplicationDidBecomeActive,
        object: nil
    )
}

func applicationDidBecomeActive(notification: NSNotification){
    let store = IAPHealper()

    //what needs to be put here?
}


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...")
        deliverPurchaseNotificatioForIdentifier(transaction.payment.productIdentifier)
        defaultQueue.finishTransaction(transaction)
        purchaseCompletionHandler?(true, transaction)
    }

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

        print("restoreTransaction... \(productIdentifier)")
        deliverPurchaseNotificatioForIdentifier(productIdentifier)
        defaultQueue.finishTransaction(transaction)
    }

    fileprivate func failedTransaction(_ transaction: SKPaymentTransaction) {
        print("failedTransaction...")

        if transaction.error!._code != SKError.paymentCancelled.rawValue {
            print("Transaction Error: \(String(describing: transaction.error?.localizedDescription))")
            purchaseCompletionHandler?(false, transaction)
        }

        defaultQueue.finishTransaction(transaction)
    }

    fileprivate func deliverPurchaseNotificatioForIdentifier(_ identifier: String?) {
        guard let identifier = identifier else { return }
        purchasedProductIdentifiers.insert(identifier)
        //NSNotificationCenter.defaultCenter().postNotificationName(IAPHelper.IAPHelperPurchaseNotification, object: identifier)
    }

    public func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]){
        print("Removed from queue.")
        print(transactions)
    }
}

谢谢。


请观看这个视频,它会对你有很大帮助。视频链接:https://www.youtube.com/watch?v=dwPFtwDJ7tc - Raksha Saini
3个回答

5
除了Andrew所说的(关于促销代码仅适用于生产环境),似乎您可能存在有关“应用内购买”处理机制的问题。
您应该在AppDelegate中初始化购买处理对象,以便它立即接收待处理的购买和刚创建的购买(或在此情况下,当代码被兑换时)。
如果您检查这里显示的示例:

https://developer.apple.com/library/content/technotes/tn2387/_index.html#//apple_ref/doc/uid/DTS40014795-CH1-BEST_PRACTICES-ADD_A_TRANSACTION_QUEUE_OBSERVER_AT_APPLICATION_LAUNCH

你实际上正在做苹果不推荐的事情。
相反,将StoreKit观察器添加到你的AppDelegate中:
class AppDelegate: UIResponder, UIApplicationDelegate {
                           ....
    // Attach an observer to the payment queue.
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Attach an observer to the payment queue.
        SKPaymentQueue.default().add(your_observer)
        return true
    }

    // Called when the application is about to terminate.
    func applicationWillTerminate(_ application: UIApplication) {
       // Remove the observer.
       SKPaymentQueue.default().remove(your_observer)
    }

    // OTHER STUFF...

}

你的应用程序可能由于此原因错过了购买时机。
顺便说一下,你已经有一个“应用内购买”帮助对象(IAPHealper)。你所需要做的就是让你的AppDelegate存储一个变量到它,并在“didFinishLaunchingWithOptions”方法中实例化它。
类似这样:
class AppDelegate: UIResponder, UIApplicationDelegate {

    var store : IAPHealper;
                           ....
    // Attach an observer to the payment queue.
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        store = IAPHelper();

        return true
    }

    // OTHER STUFF...

}

编辑: (为了让所有信息都在Stack Overflow上)

根据苹果员工的回复: https://forums.developer.apple.com/message/204476#204476

促销代码只能在生产商店中测试。

因此,为了测试它们:

  1. 提交您的应用进行应用审核。
  2. 将应用发布日期设置为未来某个时间,以便一旦应用审核批准应用程序,它不会对普通用户可用。
  3. 使用应用程序促销代码安装应用程序
  4. 使用应用内促销代码。

最后,开发者的帖子还警告我们,在应用程序被批准后,您必须等待48小时才能开始使用代码。


如果按照上述步骤操作后,您的应用程序仍未按预期运行,则您面临的问题是当苹果向您发送“购买成功”通知时,您的应用程序尚未“准备就绪”。因此,您应该遵循本答案第一部分中描述的指南(即在应用程序启动时立即初始化事务监听器)。

不起作用。你有没有尝试过你的解决方案?基本上,问题是解决方案适用于应用内购买,但不适用于促销代码兑换。 - zs2020
问题在于,应用内促销代码与“应用内购买”完全相同。但是,它们遵循您的应用程序在应用启动时“接收”成功购买通知的逻辑。因此,如果您已经按照此处提供的步骤进行了操作:https://forums.developer.apple.com/message/204476#204476,但仍然无法正常工作,则意味着“成功”的购买通知丢失了,因为您的应用程序在接收到通知时“尚未准备就绪”,这就是我编写如何正确配置应用内购买以在应用启动时接收通知的说明的原因。 - Pochi
@zsong 那位苹果员工的回复也说了同样的话: “如果在 SKProductsRequest 工作后应用内促销代码仍未激活,我将验证 transactionObserver 在启动时是否处于活动状态。” - Pochi
250个点数是被stackoverflow错误地存入的,而且解决方案实际上并不起作用。感谢您的努力。 - zs2020
嗨@Pochi。实际上,在所引用的链接中阅读提供的FAQ,我看到“如果开发人员不批准将生产应用程序发布到App Store,则不会激活任何新的应用内购买标识符”。据我所知,如果您的应用程序未发布,则无法使用SKProductRequest获取产品ID列表,因此无法显示要购买的产品列表。理论上,这2天是指开发人员发布后必须经过的时间。您是否成功收到了未发布应用程序(例如,“待开发人员发布”状态)的产品列表? - Andrea Gorrieri

1

促销代码仅在生产环境中有效。

如果您想确保应用内购功能在实际发布之前正常工作,请在应用程序处于“待开发者发布”状态(经过审核后)时使用促销代码。一个应用程序促销代码用于安装应用,另一个用于测试应用内购。有时需要额外的时间(最多2天)来分发所有苹果服务器的数据。

来自官方开发者论坛答案


实际上,在阅读引用链接中提供的常见问题解答时,我发现“如果开发人员不批准将生产应用发布到App Store,则不会激活任何新的应用内购买标识符”。因此,据我所知,如果您的应用程序处于“待开发人员发布”状态并使用促销代码进行安装,则无法使用SKProductRequest获取产品ID列表。理论上,2天是指在开发人员发布之后必须经过的时间。您是否成功在应用程序处于“待开发人员发布”状态时收到产品列表? - Andrea Gorrieri
我可以确认,在您的应用程序处于“待开发者发布”状态时,您无法下载产品列表。为了正确地从Apple商店检索产品列表,您必须将应用程序发布到“准备销售”状态。 - Andrea Gorrieri

1

@Eatton在另一个帖子中提供了非常有用的信息。我只想总结一下处理可消耗产品促销代码兑换的解决方案。

I. 您应该使用SwiftyStoreKit,并将以下代码放在AppDelegate中:

SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
    for purchase in purchases {
        switch purchase.transaction.transactionState {
        case .purchased, .restored: 
            if purchase.needsFinishTransaction {
                SwiftyStoreKit.finishTransaction(purchase.transaction)
            }
            // Unlock content
            self.unlockIAPContent(productID: purchase.productId)
        case .failed, .purchasing, .deferred:
            break // do nothing
        }
    }
}

II. 如果您想在任何视图控制器中调用逻辑,请考虑使用 NotificationCenter,将代码放置在//Unlock content下面。

III. 如何测试?

在iOS 11发布中,苹果公司推出了一个新功能,可以直接在应用商店中推广您的应用内购买

首先添加处理程序:

#if DEBUG
SwiftyStoreKit.shouldAddStorePaymentHandler = { payment, product in
    return true
}
#endif

在您的Mac上,然后编写以下URL,并使用AirDrop将其发送到您的iOS设备,在Safari中打开它。
itms-services://?action=purchaseIntent&bundleId=com.example.app&productIdentifier=product_name

然后,您的AppDelegate中的SwiftyStoreKit.completeTransactions()完成块将被触发。

这也可以用于测试促销代码兑换,因为URL请求会创建一个挂起的交易并将其添加到队列中。确保在您的生产发布中删除此代码。

希望这有所帮助!


哪些代码应该从生产版本中删除?删除后它仍然能正常工作吗?IF DEBUG标志呢?它应该被删除还是保留在SwiftyStoreKit调用中? - JerseyDevel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接