现在我在应用程序商店上有一个应用程序。我知道我会迟到更新它,但我只是想确保在我做之前把它放好。所以现在我想实现应用内购买。但是,出于某种原因,它无法正常工作:
这是在ViewDidLoad()
中 let productIdentifiers: Set<String> = ["1000Coins"]
let productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
productsRequest.delegate = self
productsRequest.start()
这是另一个功能。由于某种原因,它不打印这个
print("Product: \(product.productIdentifier), \(product.localizedTitle),\(product.price.floatValue)")
func productsRequest(_ request: SKProductsRequest, didReceive
response: SKProductsResponse) {
print("Loaded Products")
for product in response.products {
print("Product: \(product.productIdentifier), \(product.localizedTitle),\(product.price.floatValue)")
}
}
我使用iTunes连接创建了应用内购买但由于某种原因它无法正常工作。有什么建议??谢谢!
答案 0 :(得分:0)
不要不必要地混乱ViewDidLoad。创建一个应用内购买帮助程序来处理与IAP相关的所有功能,例如获取产品标识符,验证收据,恢复等。
Ron Buencamino写的好帮手就是:
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?
//Load product identifiers for store usage
func setupInAppPurchases(){
self.validateProductIdentifiers(self.getProductIdentifiersFromMainBundle())
SKPaymentQueue.default().add(self)
}
//Get product identifiers
func getProductIdentifiersFromMainBundle() -> NSArray {
var identifiers = NSArray()
if let url = Bundle.main.url(forResource: "iap_products", withExtension: "plist"){
identifiers = NSArray(contentsOf: url)!
}
return identifiers
}
//Retrieve product information
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){
//Receipt exists
let requestContents = ["receipt-data" : receipt.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))]
//Perform request
do {
let requestData = try JSONSerialization.data(withJSONObject: requestContents, options: JSONSerialization.WritingOptions(rawValue: 0))
//Build URL Request
//change the storeURL before you submit to the app store
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! as Data, options: .mutableLeaves) as! NSDictionary
print(json)
if (json.object(forKey: "status") as! NSNumber) == 0 {
//
let receipt_dict = json["receipt"] as! NSDictionary
if let purchases = receipt_dict["in_app"] as? NSArray {
self.validatePurchaseArray(purchases)
}
// you can add more statements to check different parts of the receipt
if transaction != nil {
SKPaymentQueue.default().finishTransaction(transaction!)
}
DispatchQueue.main.sync(execute: { () -> Void in self.delegate?.managerDidRestorePurchases() } ) }
else {
//Debug the receipt
print(json.object(forKey: "status") as! NSNumber)
}
}
catch {
print(error)
}
} )
task.resume()
}
catch {
print(error)
}
}
else {
//Receipt does not exist
print("No Receipt")
}
}
func validatePurchaseArray(_ purchases:NSArray){
for purchase in purchases as! [NSDictionary]{
self.unlockPurchasedFunctionalityForProductIdentifier(purchase["product_id"] as! String)
}
}
func unlockPurchasedFunctionalityForProductIdentifier(_ productIdentifier:String){
///here you put the functionality that you want to unlock for the user
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
func isDateExpired(_ expires_date:Double) -> Bool{
var isExpired:Bool = false
let currentDate = (Date().timeIntervalSince1970 * 1000) as TimeInterval
if currentDate > expires_date{
isExpired = true
}
return isExpired
}
//MARK: SKProductsRequestDelegate
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
//
self.products = response.products as NSArray!
print(self.products)
}
//MARK: SKPaymentTransactionObserver Delegate Protocol
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)
}
}
将名为iap_products.plist的plist文件添加到Xcode中并包含产品ID。在所述文件中包括:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>product1Id</string>
<string>product2Id</string>
so on....
</array>
</plist>