I'm trying to add a restore button to my app, I have a non-consumable inApp purchase and the purchase part works fine. I have a button that calls this two methods:
product_id = "RemoveAdsIAP";
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
and this the purchasing code:
func buyConsumable(){
succssessIAP = false
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID);
productsRequest.delegate = self;
productsRequest.start();
} else {
displayErrorAlert()
}
}
func buyProduct(product: SKProduct){
var payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment);
}
func productsRequest (request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
var count : Int = response.products.count
if (count>0) {
var validProducts = response.products
var validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == self.product_id) {
buyProduct(validProduct);
} else { }
} else {
displayErrorAlert()
}
}
func request(request: SKRequest!, didFailWithError error: NSError!) {
activityIndicatorShop.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
displayErrorAlert()
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
succssessIAP = false
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .Purchased, .Restored:
if (product_id == "GetNextFactIAP" && succssessIAP == false) {
startController.getData()
startController.hideContainerView()
succssessIAP = true
}
if (product_id == "RemoveAdsIAP" && succssessIAP == false) {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "viewAdsBool")
NSUserDefaults.standardUserDefaults().synchronize()
startController.removeOnce()
disableAds(true)
succssessIAP = true
}
SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
break;
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
activityIndicatorShop.stopAnimating()
displayErrorAlert()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
break;
default:
break;
}
}
}
}
When I press the button nothing happens, I've added a log statement to check if the updatedTransactions method was called and it wasn't, What's the problem?
you didn't add the button as an IBAction.
Read this...
http://rshankar.com/different-ways-to-connect-ibaction-to-uibutton/
Try This Code
import UIKit
import StoreKit
class ViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver{
var list = [SKProduct]()
var p = SKProduct()
// 2
func buyProduct() {
println("buy " + p.productIdentifier)
var pay = SKPayment(product: p)
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(pay as SKPayment)
}
//3
func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
println("product request")
var myProduct = response.products
for product in myProduct {
println("product added")
println(product.productIdentifier)
println(product.localizedTitle)
println(product.localizedDescription)
println(product.price)
list.append(product as SKProduct)
}
outRemoveAds.enabled = true
outAddCoins.enabled = true
}
// 4
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue!) {
println("transactions restored")
var purchasedItemIDS = []
for transaction in queue.transactions {
var t: SKPaymentTransaction = transaction as SKPaymentTransaction
let prodID = t.payment.productIdentifier as String
switch prodID {
case "seemu.iap.removeads":
println("remove ads")
removeAds()
case "seemu.iap.addcoins":
println("add coins to account")
addCoins()
default:
println("IAP not setup")
}
}
}
// 5
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
println("add paymnet")
for transaction:AnyObject in transactions {
var trans = transaction as SKPaymentTransaction
println(trans.error)
switch trans.transactionState {
case .Purchased:
println("buy, ok unlock iap here")
println(p.productIdentifier)
let prodID = p.productIdentifier as String
switch prodID {
case "seemu.iap.removeads":
println("remove ads")
removeAds()
case "seemu.iap.addcoins":
println("add coins to account")
addCoins()
default:
println("IAP not setup")
}
queue.finishTransaction(trans)
break;
case .Failed:
println("buy error")
queue.finishTransaction(trans)
break;
default:
println("default")
break;
}
}
}
// 6
func finishTransaction(trans:SKPaymentTransaction)
{
println("finish trans")
}
//7
func paymentQueue(queue: SKPaymentQueue!, removedTransactions transactions: [AnyObject]!)
{
println("remove trans");
}
Related
I'm using this code for my inApp Purchases to show localized price:
private func priceStringFor(product: SKProduct) -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.locale = product.priceLocale
return numberFormatter.string(from: product.price)!
}
override func viewDidLoad() {
super.viewDidLoad()
perYearPrice.setTitle("\(priceStringFor(product: IAPManager.shared.products[1])) per year", for: .normal)
oneTimePrice.setTitle("\(priceStringFor(product: IAPManager.shared.products[0])) one time", for: .normal)
}
And this is my IAPManager code:
import Foundation
import StoreKit
class IAPManager: NSObject {
static let shared = IAPManager()
private override init() {}
var products: [SKProduct] = []
let paymentQueue = SKPaymentQueue.default()
public func setupPurchases(callback: #escaping(Bool) -> ()) {
if SKPaymentQueue.canMakePayments() {
paymentQueue.add(self)
callback(true)
return
}
callback(false)
}
public func getProducts() {
let identifiers: Set = ["inapp1", "inapp2"]
let productRequest = SKProductsRequest(productIdentifiers: identifiers)
productRequest.delegate = self
productRequest.start()
}
public func purchase(productWith identifier: String) {
guard let product = products.filter({ $0.productIdentifier == identifier }).first else { return }
let payment = SKPayment(product: product)
paymentQueue.add(payment)
}
public func restoreCompletedTransactions() {
paymentQueue.restoreCompletedTransactions()
}
}
extension IAPManager: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .deferred: break
case .purchasing: break
case .failed: failed(transaction: transaction)
case .purchased: completed(transaction: transaction)
case .restored: restored(transaction: transaction)
#unknown default: fatalError()
}
}
}
func purchased() {
let adRemovalPurchased = UserDefaults.standard
adRemovalPurchased.set(true, forKey: "adRemoved")
adRemovalPurchased.synchronize()
}
private func failed(transaction: SKPaymentTransaction) {
if let transactionError = transaction.error as NSError? {
if transactionError.code != SKError.paymentCancelled.rawValue {
print("Error: \(transaction.error!.localizedDescription)")
}
}
paymentQueue.finishTransaction(transaction)
}
private func completed(transaction: SKPaymentTransaction) {
paymentQueue.finishTransaction(transaction)
purchased()
}
private func restored(transaction: SKPaymentTransaction) {
paymentQueue.finishTransaction(transaction)
purchased()
}
}
extension IAPManager: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
self.products = response.products
products.forEach { print($0.localizedTitle) }
}
}
Also I put this code in AppDelegate:
IAPManager.shared.setupPurchases { success in
if success {
print("can make payments")
IAPManager.shared.getProducts()
}
}
But when I try to get localized price for IAPManager.shared.products[1]) I get
Fatal error: Index out of range.
I don't understant where is the error. In some cases this code works, but in some cases it gets fatal error.
This
IAPManager.shared.getProducts()
is an asynchronous method , you can't access products array until this called
var callBack:(() -> ())? // 1
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
self.products = response.products
products.forEach { print($0.localizedTitle) }
callBack?() // 2
}
Then do
IAPManager.shared.setupPurchases { success in
if success {
print("can make payments")
IAPManager.shared.callBack = {
// now access the products
}
IAPManager.shared.getProducts()
}
}
BTW you can make use of https://github.com/bizz84/SwiftyStoreKit
My VC like this:
var coins = 50 // coins
override func viewDidLoad() {
super.viewDidLoad()
if(SKPaymentQueue.canMakePayments()) {
//print("enabled, loading")
let productID: NSSet = NSSet(objects: "com.tahabuyruk.taha.coinsal", "com.tahabuyruk.taha.reklam") // my products Id
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
} else {
print("please enable IAPS")
}
}
//I have 2 products on itunesconnect
#IBAction func btnRemoveAds(_ sender: Any) {
print("rem ads")
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.tahabuyruk.taha.reklam") {
// ad product id
p = product
buyProduct()
}
}
}
// my bundle id is com.tahabuyruk.taha
// my product id is com.tahabuyruk.taha.coins
#IBAction func satinAl(_ sender: Any) { // addCoin Button
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.tahabuyruk.taha.coinsal") {
p = product
buyProduct()
}
}
}
func buyProduct() {
print("buy " + p.productIdentifier)
let pay = SKPayment(product: p)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(pay as SKPayment)
}
func removeAds() {
lblAd.removeFromSuperview()
}
func addCoins() {
coins += 50
lblCoinAmount.text = "\(coins)"
}
var list = [SKProduct]()
var p = SKProduct()
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("product request")
let myProduct = response.products // myProduct is always be 0 . I don't know why .
for product in myProduct {
print("product added")
print(product.productIdentifier)
print(product.localizedTitle)
print(product.localizedDescription)
print(product.price)
list.append(product)
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
print("transactions restored")
for transaction in queue.transactions {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
switch prodID {
case "com.tahabuyruk.taha.reklam":// ad product id
print("remove ads")
removeAds()
case "com.tahabuyruk.taha.coinsal":
print("add coins to account")
addCoins()
default:
print("IAP not found")
}
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
print("add payment")
for transaction: AnyObject in transactions {
let trans = transaction as! SKPaymentTransaction
print(trans.error)
switch trans.transactionState {
case .purchased:
print("buy ok")
print(p.productIdentifier)
let prodID = p.productIdentifier
switch prodID {
case "com.tahabuyruk.taha.reklam":// ad product id
print("remove ads")
removeAds()
case "com.tahabuyruk.taha.coinsal":
print("add coins to account")
addCoins()
default:
print("IAP not found")
}
queue.finishTransaction(trans)
case .failed:
print("buy error")
queue.finishTransaction(trans)
break
default:
print("Default")
break
}
}
}
Always myProduct is 0.
What's wrong with this code?
I want to know why always be 0?
I handle this problem , look for Agreements , Tax and Banking and check that your banking, contact and tax information has been filled up
Whenever I conduct an in-app purchase in a sandbox environment, it acts like it is completing, when it really isn't. To be more specific, I click to buy more coins, I confirm that I want to buy them in the sandbox environment. Then it says "You're all set!" saying that I have completed the purchase. Well when I check my coins, nothing changed!
After looking through the code, I realized that the
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
...is not firing.
Full code:
import UIKit
import StoreKit
import AVFoundation
class InAppPurchases: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
#IBOutlet weak var noAdsBtn: UIButton!
var product_id: String?
let defaultsAD = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
product_id = "noads"
SKPaymentQueue.default().add(self)
//Check if product is purchased
if (defaultsAD.bool(forKey: "purchased")){
// Hide a view or show content depends on your requirement
// overlayView.hidden = true
noAdsBtn.backgroundColor = UIColor.red
noAdsBtn.isUserInteractionEnabled = false
} else {
print("false")
// noAds = true
// var NAD = UserDefaults.standard
// NAD.setValue(noAds, forKey: "nad")
// NAD.synchronize()
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func backBtnA(_ sender: Any) {
music2()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBAction func Buy600(_ sender: Any) {
print("About to fetch the products")
product_id = "600coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy1500(_ sender: Any) {
print("About to fetch the products")
product_id = "1500coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy3500(_ sender: Any) {
print("About to fetch the products")
product_id = "3500coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy8000(_ sender: Any) {
print("About to fetch the products")
product_id = "8000coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy25000(_ sender: Any) {
print("About to fetch the products")
product_id = "25000coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buyTruckload(_ sender: Any) {
print("About to fetch the products")
product_id = "truckloadofcoins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buyNoAds(_ sender: Any) {
print("About to fetch the products")
product_id = "noads"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
func buyProduct(product: SKProduct){
print("Sending the Payment Request to Apple");
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment);
//
SKPaymentQueue.default().add(self)
//^^??
}
func productsRequest (_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let count : Int = response.products.count
if (count>0) {
let validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == self.product_id) {
print(validProduct.localizedTitle)
print(validProduct.localizedDescription)
print(validProduct.price)
buyProduct(product: validProduct);
} else {
print(validProduct.productIdentifier)
}
} else {
print("nothing")
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Error Fetching product information");
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
print("Received Payment Transaction Response from Apple");
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .purchased:
print("Product Purchased");
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
if product_id == "noads"{
defaultsAD.set(true , forKey: "purchased")
noAdsBtn.backgroundColor = UIColor.red
noAdsBtn.isUserInteractionEnabled = false
noAds = true
var NAD = UserDefaults.standard
NAD.setValue(noAds, forKey: "nad")
NAD.synchronize()
}
//add coins
if product_id == "600coins"{
coins += 600
print("just bought 600 coins")
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "1500coins"{
coins += 1500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "3500coins"{
coins += 3500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "8000coins"{
coins += 8000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "25000coins"{
coins += 25000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
print("just boughtn 25k coins")
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "100000coins"{
coins += 100000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
// overlayView.hidden = true
break;
case .failed:
print("Purchased Failed");
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break;
case .restored:
print("Already Purchased");
SKPaymentQueue.default().restoreCompletedTransactions()
if product_id == "noads"{
defaultsAD.set(true , forKey: "purchased")
noAdsBtn.backgroundColor = UIColor.red
noAdsBtn.isUserInteractionEnabled = false
noAds = true
var NAD = UserDefaults.standard
NAD.setValue(noAds, forKey: "nad")
NAD.synchronize()
}else{
//add coins
if product_id == "600coins"{
coins += 600
print("already bought")
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "1500coins"{
coins += 1500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "3500coins"{
coins += 3500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "8000coins"{
coins += 8000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "25000coins"{
coins += 25000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "100000coins"{
coins += 100000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
}
default:
break;
}
}
}
}
func paymentQueue(_ queue: SKPaymentQueue,
updatedTransactions transactions: [SKPaymentTransaction]){
print("updating transactions")
}
func music2(){
// currentlyPlayingAudio = true
// print("\n\n\n\n\n\n\n\n\nview appeared...music??\n\n\n\n\n\n\n\n\n")
if soundFX == true{
let ButtonAudioURL2 = URL(fileURLWithPath: Bundle.main.path(forResource: "Click2", ofType: "mp3")!)
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ {
}
var error: NSError?
do {
audioPlayerClick = try AVAudioPlayer(contentsOf: ButtonAudioURL2)
} catch let error1 as NSError {
error = error1
}
audioPlayerClick.prepareToPlay()
// audioPlayer.volume = 0.3
audioPlayerClick.play()
}
}
func music3(){
// currentlyPlayingAudio = true
// print("\n\n\n\n\n\n\n\n\nview appeared...music??\n\n\n\n\n\n\n\n\n")
if soundFX == true{
let ButtonAudioURL3 = URL(fileURLWithPath: Bundle.main.path(forResource: "Toggle", ofType: "mp3")!)
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ {
}
var error: NSError?
do {
audioPlayerClick2 = try AVAudioPlayer(contentsOf: ButtonAudioURL3)
} catch let error1 as NSError {
error = error1
}
audioPlayerClick2.prepareToPlay()
// audioPlayer.volume = 0.3
audioPlayerClick2.play()
}
}
}
One last thing; the IAP to remove ads (with id "noads") keeps returning "nothing" in the console. Any ideas why it won't successfully trigger? It is a non-consumable and is labeled in iTunes Connect as "Waiting for Upload".
I am doing simple in app purchase application. At the time of product load I simply restore all my previous purchase, so I start loading indicator when I start loading product but in some device I already used inapp id so every time I load the product in that device some type of alert come and if I press cancel then nothing happen and my loading indicator goes infinite.
Here I have screenshot too.
extension IAPHelper: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
if productIdentifiers.contains(transaction.payment.productIdentifier) {
switch (transaction.transactionState) {
case .purchased:
complete(transaction: transaction)
break
case .failed:
fail(transaction: transaction)
break
case .restored:
restore(transaction: transaction)
break
case .deferred:
print("denied")
break
case .purchasing:
break
}
}
}
if productsRestoreCompletionHandler != nil
{
productsRestoreCompletionHandler = nil
}
}
private func complete(transaction: SKPaymentTransaction) {
print("complete...")
// deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
productsPurchaseCompletionHandler?(true, transaction)
if productsPurchaseCompletionHandler != nil
{
productsPurchaseCompletionHandler = nil
}
}
private func restore(transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
print("restore... \(productIdentifier)")
// deliverPurchaseNotificationFor(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
productsRestoreCompletionHandler?(true, transaction)
}
private func fail(transaction: SKPaymentTransaction) {
print("fail...")
if let transactionError = transaction.error as? NSError {
if transactionError.code != SKError.paymentCancelled.rawValue {
print("Transaction Error: \(transaction.error?.localizedDescription)")
}
}
SKPaymentQueue.default().finishTransaction(transaction)
if productsRestoreCompletionHandler != nil
{
productsRestoreCompletionHandler?(false, transaction)
productsRestoreCompletionHandler = nil
}
if productsPurchaseCompletionHandler != nil
{
productsPurchaseCompletionHandler?(false, transaction)
productsPurchaseCompletionHandler = nil
}
}
private func deliverPurchaseNotificationFor(identifier: String?) {
guard let identifier = identifier else { return }
purchasedProductIdentifiers.insert(identifier)
// UserDefaults.standard.set(true, forKey: identifier)
// UserDefaults.standard.synchronize()
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: IAPHelper.IAPHelperPurchaseNotification), object: identifier)
}
}
When product load
//MARK:
//MARK: load the product
func getProduct()
{
let userData = getUserDataFromFile()
obj = IAPHelper(productIds: NetFishProducts.productIdentifiers)
if checkInternetConnection()
{
SINGLETON.startLoadingActivity(self.view)
obj.requestProducts { (isSuccess, arrProduct) in
if isSuccess == true
{
self.setProduct = Set<SKProduct>(arrProduct! as [SKProduct])
self.btnSignup.isUserInteractionEnabled = true
for p in arrProduct! {
print("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
if p.productIdentifier == NetFishProducts.monthlyPlan
{
self.setupLblMonth(withMothPrice: "\(p.price.floatValue)")
}
else
{
self.setupLblYear(withYearPrice: "\(p.price.floatValue)")
}
}
self.obj.requestRestoreProducts(completionHandler: { (isSuccess, transation) in
SINGLETON.stopLoadingActivity(self.view)
if isSuccess == true
{
let orignalTI = transation?.original?.transactionIdentifier
let userEmail = transation?.payment.applicationUsername
print("orignalTI:\(orignalTI)")
print("username:\(userEmail)")
if userEmail != nil && userData?.userEmail != userEmail
{
self.btnSignup.isUserInteractionEnabled = false
self.showAlertToUser("Information", MsgDesc: "You are login with different appstore account so login with correct appstore account")
return
}
}
else
{
self.btnSignup.isUserInteractionEnabled = false
}
},withUserName: (userData?.userEmail)!)
}
else
{
SINGLETON.stopLoadingActivity(self.view)
self.btnSignup.isUserInteractionEnabled = false
}
}
}
}
I'm trying to add a restore button to my app, I have a non-consumable inApp purchase and the purchase part works fine. I have a button that calls this two methods:
product_id = "RemoveAdsIAP";
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
and this the purchasing code:
func buyConsumable(){
succssessIAP = false
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID);
productsRequest.delegate = self;
productsRequest.start();
} else {
displayErrorAlert()
}
}
func buyProduct(product: SKProduct){
var payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment);
}
func productsRequest (request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
var count : Int = response.products.count
if (count>0) {
var validProducts = response.products
var validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == self.product_id) {
buyProduct(validProduct);
} else { }
} else {
displayErrorAlert()
}
}
func request(request: SKRequest!, didFailWithError error: NSError!) {
activityIndicatorShop.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
displayErrorAlert()
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
succssessIAP = false
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .Purchased, .Restored:
if (product_id == "GetNextFactIAP" && succssessIAP == false) {
startController.getData()
startController.hideContainerView()
succssessIAP = true
}
if (product_id == "RemoveAdsIAP" && succssessIAP == false) {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "viewAdsBool")
NSUserDefaults.standardUserDefaults().synchronize()
startController.removeOnce()
disableAds(true)
succssessIAP = true
}
SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
break;
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
activityIndicatorShop.stopAnimating()
displayErrorAlert()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
break;
default:
break;
}
}
}
}
When I press the button nothing happens, I've added a log statement to check if the updatedTransactions method was called and it wasn't, What's the problem?
Your products_id has the wrong format.
It should be more like
product_id = "com.xxxxxxxxx.RemoveAdsIAP"