#swift #xcode #in-app-purchase
#swift #xcode #покупка в приложении
Вопрос:
Я постараюсь объяснить свою проблему как можно более четко. У меня есть IAP в моем приложении, я пытаюсь использовать логические значения, чтобы определить, должен ли игрок получать награды или нет. Я использую этот код
self.purchaseExtraRounds = true
self.purchaseRemoveAds = true
но я не уверен, где его разместить, чтобы пользователь мог получать награды только после завершения покупки. На данный момент, где бы я его ни разместил, я могу щелкнуть по IAP, а затем нажать «Отмена», и награды будут включены без фактической покупки. Вот мой файл IAP manager.
class IAPManager: NSObject {
static let shared = IAPManager()
var purchaseExtraRounds = false
var purchaseRemoveAds = false
private override init() {
super.init()
}
func getProducts() {
let request = SKProductsRequest(productIdentifiers: allInAppPurchases)
request.delegate = self
request.start()
}
func purchase(product: SKProduct) -> Bool {
if !IAPManager.shared.canMakePayments() {
return false
} else {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
return true
}
func canMakePayments() -> Bool {
return SKPaymentQueue.canMakePayments()
}
}
extension IAPManager: SKProductsRequestDelegate, SKRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let badProducts = response.invalidProductIdentifiers
let goodProducts = response.products
if !goodProducts.isEmpty {
ProductsDB.shared.items = response.products
print("Good", ProductsDB.shared.items)
}
print("Bad", badProducts)
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("didFailWithError ", error)
DispatchQueue.main.async {
print("purchase failed")
}
}
func requestDidFinish(_ request: SKRequest) {
DispatchQueue.main.async {
print("request did finish ")
}
}
}
final class ProductsDB: ObservableObject, Identifiable {
static let shared = ProductsDB()
var items: [SKProduct] = [] {
willSet {
DispatchQueue.main.async {
self.objectWillChange.send()
}
}
}
}
Я устал размещать код в нескольких местах в этом файле, но я натыкаюсь на стену.
Комментарии:
1. Вам необходимо отслеживать транзакции SKPaymentQueue с вашим наблюдателем и делать это после завершения платежной транзакции. Сделанный запрос на продукт еще не означает, что деньги будут выплачены.
Ответ №1:
Вам нужно будет начать наблюдение внутри AppDelegate, когда ваше приложение завершит запуск.
Вы должны вызвать
SKPaymentQueue.default().add(self) //<< here comes your observer
внутри вашего IAPManager.
Тогда ваша функция purchase() может быть вызвана правильно. Затем примите
SKPaymentTransactionObserver
протокол, в котором вы можете реализовать следующий метод:
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
Здесь вы получаете свои транзакции и a transaction.transactionState
, который указывает, была ли ваша транзакция успешной.
Возвращаясь к вашему первоначальному вопросу, если ваше состояние приобретено, вы установите свою переменную соответственно тому, какой продукт был куплен
Комментарии:
1. Спасибо @davidev теперь я понимаю, почему тогда у меня была эта проблема. До сих пор я реализовал этот код, но не получил никакого результата. Я добавил награду в состояние успешной покупки. мне потребуется некоторое время, чтобы разобраться в этом.
2. Хорошо, теперь я правильно реализую свой IAP, спасибо. У меня есть шесть элементов IAP, и я не уверен, как вызвать правильный метод для конкретного IAP, который был запрошен, когда он переходит в состояние purchased. Есть предложения? Вот список методов, которые я вызываю. case .purchased: removeAds() roundsx5() roundsx30() roundsx70() roundsx400() roundsx1000() SKPaymentQueue. default().finishTransaction(транзакция)
Ответ №2:
Итак, я решил проблему следующим образом; реализовать эту функцию
private func handlePurchase(_ id: String) {
if id == "remove ads product id" {
removeAds(id: "remove ads product id")}
}
вызов на этом этапе
case .purchased:
handlePurchase(transaction.payment.productIdentifier)
который вызовет другую функцию, которую я создал, чтобы выдать награду следующим образом
func removeAds(id: String) {
UserDefaults.standard.set(true, forKey: "RemoveAdsPurchased")
}