这是商店管理器的代码:
import Foundation
import StoreKit
//MARK: Protocols
protocol StoreManagerDelegate: class {
func updateWithProducts(products:[SKProduct])
func refreshPurchaseStatus()
}
//MARK: Store Manager class
class StoreManager: NSObject {
weak var delegate: StoreManagerDelegate?
var loadedProducts: [SKProduct] = []
override init() {
super.init()
SKPaymentQueue.default().add(self)
getProductList()
}
//MARK: Request products
func getProductList() {
if SKPaymentQueue.canMakePayments() {
let products = NSSet(array: ProductList.products)
let request = SKProductsRequest(productIdentifiers: products as! Set<String>)
request.delegate = self
request.start()
}
}
//MARK: Purchasing
func restoreCompletedTransactions() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
func purchaseProduct(product: SKProduct) {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
}
extension StoreManager: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
loadedProducts = response.products
if loadedProducts.count != 0 {
delegate?.updateWithProducts(products: loadedProducts)
}
}
}
extension StoreManager: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]){
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .purchased:
//validateReceipt(transaction as! SKPaymentTransaction)
ProductDelivery.deliverProduct(product: trans.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
self.delegate?.refreshPurchaseStatus()
break
case .failed:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
case .restored:
//validateReceipt(transaction as! SKPaymentTransaction)
ProductDelivery.deliverProduct(product: trans.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
self.delegate?.refreshPurchaseStatus()
break
default:
break
}
}
}
}
}
extension SKProduct {
func localizedPrice() -> String {
let formatter = NumberFormatter()
//formatter.numberStyle = .CurrencyStyle
formatter.locale = self.priceLocale
return formatter.string(from: self.price)!
}
}
以下是商店产品的代码:
import Foundation
import StoreKit
//MARK: Add your products here
var core = UserDefaults.standard.integer(forKey: "cores")
struct ProductList {
static let buy50 : String = "com.AlienBeing.lightslicer.buy50"
static let buy150 : String = "com.AlienBeing.lightslicer.buy150"
static let buy400 : String = "com.AlienBeing.lightslicer.buy400"
static let buy750 : String = "com.AlienBeing.lightslicer.buy750"
static let buy1200 : String = "com.AlienBeing.lightslicer.buy1201"
static let buy2500 : String = "com.AlienBeing.lightslicer.buy2500"
static let buy5500 : String = "com.AlienBeing.lightslicer.buy5500"
static let products = [buy50, buy150, buy400, buy750, buy1200, buy2500, buy5500]
}
//MARK: Deliver your products here
struct ProductDelivery {
static let validatePurchase:Bool = true
static func deliverProduct(product: String) {
switch product {
case ProductList.buy50:
deliverConsumable(identifier: ProductList.buy50, units: 50)
case ProductList.buy150:
deliverConsumable(identifier: ProductList.buy150, units: 150)
case ProductList.buy400:
deliverConsumable(identifier: ProductList.buy400, units: 400)
case ProductList.buy750:
deliverConsumable(identifier: ProductList.buy750, units: 750)
case ProductList.buy1200:
deliverConsumable(identifier: ProductList.buy1200, units: 1200)
case ProductList.buy2500:
deliverConsumable(identifier: ProductList.buy2500, units: 2500)
case ProductList.buy5500:
deliverConsumable(identifier: ProductList.buy5500, units: 5500)
break
default:
break
}
}
//MARK: Non-consumable products
static func deliverNonconsumable(identifier: String) {
UserDefaults.standard.set(true, forKey: identifier)
UserDefaults.standard.synchronize()
}
static func isProductAvailable(identifier: String) -> Bool {
if UserDefaults.standard.bool(forKey: identifier) == true {
return true
} else if (identifier == "com.AlienBeing.lightslicer.buy50") {
return true
}
else if (identifier == "com.AlienBeing.lightslicer.buy150") {
return true
}
else if (identifier == "com.AlienBeing.lightslicer.buy400") {
return true
}
else if (identifier == "com.AlienBeing.lightslicer.buy750") {
return true
}
else if (identifier == "com.AlienBeing.lightslicer.buy1201") {
return true
}
else if (identifier == "com.AlienBeing.lightslicer.buy2500") {
return true
}
else if (identifier == "com.AlienBeing.lightslicer.buy5500") {
return true
}
else {
return false
}
}
//MARK: Consumable product
static func deliverConsumable(identifier: String, units: Int) {
let currentUnits:Int = UserDefaults.standard.integer(forKey: "cores")
UserDefaults.standard.set(currentUnits + units, forKey: identifier)
UserDefaults.standard.set(currentUnits + units, forKey: "cores")
UserDefaults.standard.synchronize()
}
static func remainingUnits(identifier: String) -> Int {
return UserDefaults.standard.integer(forKey: identifier)
}
}
以下是应用内容的代码:
import Foundation
enum ProductType {
case nonconsumable
case consumable
}
struct AppContent {
static let main = [
ContentItem(identifier: "com.AlienBeing.lightslicer.buy50", purchaseType: .consumable, content: ""),
ContentItem(identifier: "com.AlienBeing.lightslicer.buy150", purchaseType: .consumable, content: ""),
ContentItem(identifier: "com.AlienBeing.lightslicer.buy400", purchaseType: .consumable, content: ""),
ContentItem(identifier: "com.AlienBeing.lightslicer.buy750", purchaseType: .consumable, content: ""),
ContentItem(identifier: "com.AlienBeing.lightslicer.buy1201", purchaseType: .consumable, content: ""),
ContentItem(identifier: "com.AlienBeing.lightslicer.buy2500", purchaseType: .consumable, content: ""),
ContentItem(identifier: "com.AlienBeing.lightslicer.buy5500", purchaseType: .consumable, content: "")
]
}
struct ContentItem {
var identifier:String
var purchaseType:ProductType
var content:String
}
这是商店的代码:
import UIKit
import SpriteKit
import Darwin
import KeychainAccess
import StoreKit
class coreStore: SKScene{
let core = UserDefaults.standard.integer(forKey: "cores")
let storeManager = StoreManager()
var coreLabelNode: SKLabelNode!
var mainMenuButton: SKSpriteNode!
var buy50: SKSpriteNode!
var buy150: SKSpriteNode!
var buy400: SKSpriteNode!
var buy750: SKSpriteNode!
var buy1200: SKSpriteNode!
var buy2500: SKSpriteNode!
var buy5500: SKSpriteNode!
//var helper: IAPHelper
//var coreStoreView = coreStore()
var products = [SKProduct]()
override func didMove(to view: SKView) {
storeManager.delegate = self
let possibleProducts = ["com.AlienBeing.lightslicer.buy50", "com.AlienBeing.lightslicer.buy150", "com.AlienBeing.lightslicer.buy400", "com.AlienBeing.lightslicer.buy750", "com.AlienBeing.lightslicer.buy1201", "com.AlienBeing.lightslicer.buy2500", "com.AlienBeing.lightslicer.buy5500"]
//let possibleValues = [50, 150, 400, 750, 1200, 2500, 5500]
let core = UserDefaults.standard.integer(forKey: "cores")
coreLabelNode = self.childNode(withName: "coreLabel") as! SKLabelNode
coreLabelNode.text = "\(core)"
mainMenuButton = self.childNode(withName: "mainMenuButton") as! SKSpriteNode
mainMenuButton.texture = SKTexture(imageNamed: "MainMenuButton")
buy50 = self.childNode(withName: "buy50") as! SKSpriteNode
buy150 = self.childNode(withName: "buy150") as! SKSpriteNode
buy400 = self.childNode(withName: "buy400") as! SKSpriteNode
buy750 = self.childNode(withName: "buy750") as! SKSpriteNode
buy1200 = self.childNode(withName: "buy1200") as! SKSpriteNode
buy2500 = self.childNode(withName: "buy2500") as! SKSpriteNode
buy5500 = self.childNode(withName: "buy5500") as! SKSpriteNode
buy50.texture = SKTexture(imageNamed: "buy50")
buy150.texture = SKTexture(imageNamed: "buy150")
buy400.texture = SKTexture(imageNamed: "buy400")
buy750.texture = SKTexture(imageNamed: "buy750")
buy1200.texture = SKTexture(imageNamed: "buy1200")
buy2500.texture = SKTexture(imageNamed: "buy2500")
buy5500.texture = SKTexture(imageNamed: "buy5500")
buy50.userData = ["Index":0, "Product": possibleProducts[0]]
buy150.userData = ["Index":1, "Product": possibleProducts[1]]
buy400.userData = ["Index":2, "Product": possibleProducts[2]]
buy750.userData = ["Index":3, "Product": possibleProducts[3]]
buy1200.userData = ["Index":4, "Product": possibleProducts[4]]
buy2500.userData = ["Index":5, "Product": possibleProducts[5]]
buy5500.userData = ["Index":6, "Product": possibleProducts[6]]
buy50.name = "C\(0)"
buy150.name = "C\(1)"
buy400.name = "C\(2)"
buy750.name = "C\(3)"
buy1200.name = "C\(4)"
buy2500.name = "C\(5)"
buy5500.name = "C\(6)"
//storeManager.delegate?.updateWithProducts(products: products)
refreshPurchaseStatus()
// products.append(buy50.userData!["Product"] as! SKProduct)
// products.append(buy150.userData!["Product"] as! SKProduct)
// products.append(buy400.userData!["Product"] as! SKProduct)
// products.append(buy750.userData!["Product"] as! SKProduct)
// products.append(buy1200.userData!["Product"] as! SKProduct)
// products.append(buy2500.userData!["Product"] as! SKProduct)
// products.append(buy5500.userData!["Product"] as! SKProduct)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
print("gottotouch")
let location = touch.location(in: self)
for node in nodes(at: location) {
print("gottoloop")
if let nodename = node.name {
print("gottonodename")
if nodename.hasPrefix("C") {
print("gottoprefix")
print(nodename)
print(node.userData!["Product"] as! String)
print(products)
for product in products {
print(product.productIdentifier)
if product.productIdentifier == node.userData!["Product"] as! String {
print("gototpayment")
storeManager.purchaseProduct(product: product)
coreLabelNode.text = "\(core)"
}
}
}
}
}
}
let touch = touches.first
//interstitialAd = createAndLoadInterstitial()
if let location = touch?.location(in: self){
let nodesArray = self.nodes(at: location)
if nodesArray.first?.name == "mainMenuButton"{
let transition = SKTransition.flipHorizontal(withDuration: 0.5)
let menuScene = SKScene(fileNamed: "MenuScene")
menuScene?.scaleMode = .aspectFit
self.view!.presentScene(menuScene!, transition: transition)
}
}
}
}
extension coreStore: StoreManagerDelegate {
func updateWithProducts(products:[SKProduct]) {
self.products = products
}
func refreshPurchaseStatus() {
for node in children {
if let nodename = node.name {
if nodename.hasPrefix("C") {
if ProductDelivery.isProductAvailable(identifier: node.userData!["Product"] as! String) {
node.alpha = 1.0
} else {
node.alpha = 0.2
}
}
}
}
}
}
我相信问题就在商店中
for product in products {
print(product.productIdentifier)
if product.productIdentifier == node.userData!["Product"] as! String {
print("gototpayment")
storeManager.purchaseProduct(product: product)
coreLabelNode.text = "\(core)"
}
点击一个SKSpriteNode的一个,例如buy150将打印出来:
gottoloop 触碰 得环 gottonodename gettoprefix C1 com.AlienBeing.lightslicer.buy150 []
主要问题是它应该在沙盒环境中打开一个iTunes购买窗口,但它甚至从不访问对storeManager.purchaseProduct(product:product)的调用 因为产品数组是空的...我不知道
因为在总是立即以[]结尾的位置打印打印(产品),所以未使用正确的产品填充产品SKProduct数组。我不认为它应该为空,但填充它可能会丢失一些东西。我已经坚持了一段时间。真的可以使用一些帮助:)
我应该补充一点,我不是一个很好的程序员,或者更确切地说,我还在上大学并且还在训练自己,因此,如果有任何有益的提示可以帮助我学习更多的最佳实践,也请多多关照,谢谢向导未来。 (这真的是你们在这里所经历的,不要忘了它)