- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前在 iTunesConnect
中设置了非消耗品
和自动续订订阅
应用内购买。我的问题是,我不确定如何检查是否可以为用户解锁自动续订订阅
的内容。我对应用程序购买中的非消耗品
没有任何问题,我通过检查UserDefaults
中是否存在产品ID来验证它们,如果存在,我会解锁内容,否则我通知用户,但此方法不适用于自动续订订阅
应用内购买。当我测试它时,我可以通过应用程序商店进行购买交易,但是当我尝试查看 UserDefaults
中是否存在产品 ID 时,它返回 false。事实上,我手动检查了 key 是否存在,但不存在,它只显示 Non-Consumable
购买的 key 。
这是我正在使用的代码。
这是我多年来一直使用的工作代码,用于验证应用购买中的Non-Consumable
。
In App Manager
类。import UIKit
import StoreKit
protocol IAPManagerDelegate {
func managerDidRestorePurchases()
}
class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver, SKRequestDelegate {
static let sharedInstance = IAPManager()
var request:SKProductsRequest!
var products:NSArray!
var delegate:IAPManagerDelegate?
func setupInAppPurchases(){
self.validateProductIdentifiers(self.getProductIdentifiersFromMainBundle())
SKPaymentQueue.default().add(self)
}
func getProductIdentifiersFromMainBundle() -> NSArray {
var identifiers = NSArray()
if let url = Bundle.main.url(forResource: "iap_product_ids", withExtension: "plist"){
identifiers = NSArray(contentsOf: url)!
}
return identifiers
}
func validateProductIdentifiers(_ identifiers:NSArray) {
let productIdentifiers = NSSet(array: identifiers as [AnyObject])
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
self.request = productRequest
productRequest.delegate = self
productRequest.start()
}
func createPaymentRequestForProduct(_ product:SKProduct){
let payment = SKMutablePayment(product: product)
payment.quantity = 1
SKPaymentQueue.default().add(payment)
}
func verifyReceipt(_ transaction:SKPaymentTransaction?){
let receiptURL = Bundle.main.appStoreReceiptURL!
if let receipt = try? Data(contentsOf: receiptURL){
let requestContents = ["receipt-data" : receipt.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))]
do {
let requestData = try JSONSerialization.data(withJSONObject: requestContents, options: JSONSerialization.WritingOptions(rawValue: 0))
// PRODUCTION URL
// let storeURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")
// TESTING URL: Uncomment for testing InAppPurchases
let storeURL = URL(string: "https:/sandbox.itunes.apple.com/verifyReceipt")
var request = URLRequest(url: storeURL!)
request.httpMethod = "Post"
request.httpBody = requestData
let session = URLSession.shared
let task = session.dataTask(with: request,
completionHandler: { (responseData, response, error) -> Void in
do {
let json = try JSONSerialization.jsonObject(with: responseData!, options: .mutableLeaves) as! NSDictionary
if (json.object(forKey: "status") as! NSNumber) == 0 {
if let latest_receipt = json["latest_receipt_info"]{
self.validatePurchaseArray(latest_receipt as! NSArray)
} else {
let receipt_dict = json["receipt"] as! NSDictionary
if let purchases = receipt_dict["in_app"] as? NSArray{
self.validatePurchaseArray(purchases)
}
}
if transaction != nil {
SKPaymentQueue.default().finishTransaction(transaction!)
}
DispatchQueue.main.sync(execute: { () -> Void in
self.delegate?.managerDidRestorePurchases()
})
} else {
print(json.object(forKey: "status") as! NSNumber)
}
} catch {
print(error)
}
})
task.resume()
} catch {
print(error)
}
} else {
print("No Receipt")
}
}
func validatePurchaseArray(_ purchases:NSArray){
for purchase in purchases as! [NSDictionary]{
self.unlockPurchasedFunctionalityForProductIdentifier(purchase["product_id"] as! String)
}
}
func unlockPurchasedFunctionalityForProductIdentifier(_ productIdentifier:String){
UserDefaults.standard.set(true, forKey: productIdentifier)
UserDefaults.standard.synchronize()
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
func lockPurchasedFunctionalityForProductIdentifier(_ productIdentifier:String){
UserDefaults.standard.set(false, forKey: productIdentifier)
UserDefaults.standard.synchronize()
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let inAppPurchases = response.products
// Sort the items
self.products = inAppPurchases.reversed() as NSArray
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions as [SKPaymentTransaction]{
switch transaction.transactionState{
case .purchasing:
print("Purchasing")
UIApplication.shared.isNetworkActivityIndicatorVisible = true
case .deferred:
print("Deferrred")
UIApplication.shared.isNetworkActivityIndicatorVisible = false
case .failed:
print("Failed")
//print(transaction.error?.localizedDescription)
UIApplication.shared.isNetworkActivityIndicatorVisible = false
SKPaymentQueue.default().finishTransaction(transaction)
case.purchased:
print("Purchased")
self.verifyReceipt(transaction)
case .restored:
print("Restored")
}
}
}
func restorePurchases(){
let request = SKReceiptRefreshRequest()
request.delegate = self
request.start()
}
func requestDidFinish(_ request: SKRequest) {
self.verifyReceipt(nil)
}
}
UITableView
中呈现应用内购买
的方式。class StoreTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, IAPManagerDelegate {
@IBOutlet weak var premiumFeaturesTable: UITableView!
@IBOutlet weak var buttonClose: UIButton!
@IBOutlet weak var buttonRestore: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
IAPManager.sharedInstance.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return IAPManager.sharedInstance.products.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellInAppPurchase")as! CustomCellForInAppPurchasesTableViewCell
let product = IAPManager.sharedInstance.products.object(at: indexPath.row) as! SKProduct
cell.labelIAppItem.text = product.localizedTitle
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
IAPManager.sharedInstance.createPaymentRequestForProduct(IAPManager.sharedInstance.products.object(at: indexPath.row) as! SKProduct)
}
@IBAction func closeViewController(_ sender: AnyObject) {
self.presentingViewController!.dismiss(animated: true, completion: nil)
}
@IBAction func restorePurchases(_ sender: AnyObject) {
IAPManager.sharedInstance.restorePurchases()
}
}
if NSUserDefaults.standardUserDefaults().boolForKey("com.theAppID.app"){
// Unlock content.
}else{
// Notify user.
}
同样,一切都适用于非消耗品
,但对于自动续订订阅
,我不确定如何在用户购买后解锁内容。
我缺少什么,根据上述代码检查用户是否已支付自动续订订阅
的正确方法是什么?
最佳答案
请检查此link用于自动续订订阅。
您可以使用应用内管理器类中的以下函数。
func verifyReceipt(_ transaction:SKPaymentTransaction?)
验证后,您将收到以下响应代码以及您最后订阅日期的详细信息。请检查这个link .
注意:不要忘记在自动续订订阅的收据验证中传递“密码”字段。
关于ios - 如何在 Swift 中检查用户是否已在应用内购买中支付自动续订订阅费用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56319444/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!