【发布时间】:2020-12-17 18:34:37
【问题描述】:
我已经尝试了多种方法来使用带有 storeKit 的模拟器和 testFlight 来验证 storeKit 收据,但似乎除了状态 21002 之外什么都没有。我上次使用的代码起源于 (Implementing Receipt Validation in Swift 3)。似乎很多人都遇到过这个问题,有人说无法使用沙箱进行验证。苹果文档表明可以做到吗?问题似乎出在下面代码底部的 func receiveValidation10() 上。其他一切似乎都很好。任何帮助表示赞赏。谢谢!
import StoreKit
import UIKit
let SUBSCRIPTION_SECRET = "xxx"
#if DEBUG
let certificate = "StoreKitTestCertificate"
#else
let certificate = "AppleIncRootCertificate"
#endif
class purchaseViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
private var models = [SKProduct]()
var pChoice = "Trial"
var pDate = today
var eDate = today
var myProducts: SKProduct?
@IBAction func back(_ sender: Any) { dismiss(animated: true, completion: nil)
}
@IBAction func home(_ sender: Any) { nav(to: "home")
}
@IBAction func basic(_ sender: Any) {
pChoice = "Basic"
eDate=dateAdd(date1: today, inc: 1, metric: "yr")
if SKPaymentQueue.canMakePayments() { // needed? https://www.youtube.com/watch?v=qyKmpr9EjwU
let payment = SKPayment(product: models[whichProduct(title: "com.markv.REX3.basic")])
SKPaymentQueue.default().add(self) // needed? https://www.youtube.com/watch?v=qyKmpr9EjwU
SKPaymentQueue.default().add(payment)
}
}
@IBAction func premium(_ sender: Any) {
pChoice = "Premium"
eDate=dateAdd(date1: today, inc: 1, metric: "yr")
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: models[whichProduct(title: "com.markv.REX3.premium")])
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
}
}
@IBAction func unlimited(_ sender: Any) {
pChoice = "Unlimited"
eDate="None"
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: models[whichProduct(title: "com.markv.REX3.unlimited")])
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
}
}
@IBAction func cancel(_ sender: Any) {
UIApplication.shared.open(URL(string: "Https://apps.apple.com/account/subscriptions")!)
}
func fetchProduct(upgrade: String) {
let request = SKProductsRequest(productIdentifiers: [upgrade])
request.delegate = self
request.start()
}
func whichProduct(title: String) -> Int {
for i in 0 ..< models.count {
let product = models[i]
if title == product.productIdentifier {
return i
}
}
print("No product match")
return models.count
}
enum Product: String, CaseIterable {
case unlimited = "com.markv.ddd.unlimited"
case basic = "com.markv.ddd.basic"
case premium = "com.markv.ddd.premium"
}
private func fetchProducts() {
let request = SKProductsRequest(productIdentifiers: Set(Product.allCases.compactMap({ $0.rawValue })))
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
DispatchQueue.main.async {
print("Count:\(response.products.count)")
self.models = response.products
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchasing:
print("purchasing")
// no op
break
case .purchased, .restored:
SKPaymentQueue.default().finishTransaction(transaction)
SKPaymentQueue.default().remove(self) // needed? https://www.youtube.com/watch?v=qyKmpr9EjwU
print("Purchase or Restore, version=",pChoice)
print("Method1:")
receiptValidation10()
break
case .failed, .deferred:
SKPaymentQueue.default().finishTransaction(transaction)
SKPaymentQueue.default().remove(self)
print("no payment")
//dismiss(animated: true)
break
default:
SKPaymentQueue.default().finishTransaction(transaction)
SKPaymentQueue.default().remove(self)
print("no payment")
//dismiss(animated: true)
break
}
}
}
func receiptValidation10() {
// method by Yasin Aktimur, updated by Not Batman, says working for swift 4, 11/17/2017, updated 1/17/18 https://stackoverflow.com/questions/39711350/implementing-receipt-validation-in-swift-3
//
#if DEBUG
let urlString = "https://sandbox.itunes.apple.com/verifyReceipt"
#else
let urlString = "https://buy.itunes.apple.com/verifyReceipt"
#endif
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do{
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let base64encodedReceipt = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions.endLineWithCarriageReturn)
let requestDictionary = ["receipt-data":base64encodedReceipt!,"password":SUBSCRIPTION_SECRET]
guard JSONSerialization.isValidJSONObject(requestDictionary) else { print("requestDictionary is not valid JSON"); return }
do {
let requestData = try JSONSerialization.data(withJSONObject: requestDictionary)
let validationURLString = urlString // this works but as noted above it's best to use your own trusted server
guard let validationURL = URL(string: validationURLString) else { print("the validation url could not be created, unlikely error"); return }
let session = URLSession(configuration: URLSessionConfiguration.default)
var request = URLRequest(url: validationURL)
request.httpMethod = "POST"
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringCacheData
let queue = DispatchQueue(label: "itunesConnect")
queue.async {
let task = session.uploadTask(with: request, from: requestData) { (data, response, error) in
if let data = data , error == nil {
do {
let appReceiptJSON = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary
print("success. here is the json representation of the app receipt: \(String(describing: appReceiptJSON))")
//self.getExpireInfo(appReceiptJSON!)
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
} else {
print("the upload task returned an error: \(error ?? "couldn't upload" as! Error)")
}
}
task.resume()
}
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
}
}
【问题讨论】:
-
您为什么希望收据存在于您的 App Bundle 中?