Redeem Button for in app purchases - ios

I submitted my app to apple but they rejected it because, there was no redeem button for in app purchases. How can i do that. I made a redeem button and linked it up to the view controller. Where do i go from there?
Here is my code:
class StoreViewController: UIViewController, SKPaymentTransactionObserver, SKProductsRequestDelegate {
#IBOutlet var redeemOutlet: UIButton!
#IBAction func redeem(_ sender: Any) {
}
#IBOutlet var productDescription: UITextView!
var product: SKProduct?
let productID = "com.myCoolAwesomeApp.mjay.noAdvertisements"
#IBOutlet var buyButton: UIButton!
#IBOutlet var returnButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
buyButton.layer.cornerRadius = 5.0
returnButton.layer.cornerRadius = 5.0
buyButton.isEnabled = false
SKPaymentQueue.default().add(self)
getPurchaseInfo()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func purchase(_ sender: Any) {
let payment = SKPayment(product: product!)
SKPaymentQueue.default().add(payment)
}
#IBAction func dismissView(_ sender: Any) {
//self.dismiss(animated: true, completion: nil)
}
func getPurchaseInfo() {
if SKPaymentQueue.canMakePayments() {
let request = SKProductsRequest(productIdentifiers: NSSet(objects: self.productID) as! Set<String>)
request.delegate = self
request.start()
} else {
productDescription.text = "Please enable In App Purchases in your settings."
}
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
var products = response.products
if (products.count) == 0 {
productDescription.text = "Product not found."
} else {
product = products[0]
productDescription.text = "Remove all advertisements within the game for $0.99"
buyButton.isEnabled = true
}
let invalids = response.invalidProductIdentifiers
for product in invalids {
print("Product not found: \(product)")
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case SKPaymentTransactionState.purchased:
SKPaymentQueue.default().finishTransaction(transaction)
productDescription.text = "Purchase Successful"
buyButton.isEnabled = false
let save = UserDefaults.standard
save.set(true, forKey: "Purchase")
save.synchronize()
case SKPaymentTransactionState.failed:
SKPaymentQueue.default().finishTransaction(transaction)
productDescription.text = "Purchase Failed. Try again later."
default:
break
}
}
}
}

Related

Swift / App Store : Problem with in app purchase

I have a problem with my app. My in app purchase work very well on my side, on ios 12,4 iphone 5s. But when I send the binary at Apple Store I have a return :"We noticed that your app still still does not display the purchase button for the In-App Purchase product, in the app.".The buy button is only displayed when the processing to pay is ready. About 2 to 3 seconds at home. But with them apparently it does not work at all ...
Here is the full code for my store that handles everything. And I specify that with my iphone I manage to have the purchase window and to buy the integrated purchase in sandbox.
import UIKit
import StoreKit
import MessageUI
class ShopViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver, MFMailComposeViewControllerDelegate {
#IBOutlet weak var buyBtn: UIButton!
#IBOutlet weak var restore: UIButton!
#IBOutlet weak var mail: UIImageView!
#IBOutlet weak var shopDescription: UILabel!
var productsRequest = SKProductsRequest()
var validProducts = [SKProduct]()
var productIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
buyBtn.isHidden = true
shopDescription.numberOfLines = 0
shopDescription.lineBreakMode = NSLineBreakMode.byWordWrapping
shopDescription.sizeToFit()
shopDescription.text = NSLocalizedString("packpro", comment: "")
// SKPaymentQueue.default().add(self)
let tap4 = UITapGestureRecognizer(target: self, action:#selector(tappedMe5))
mail.addGestureRecognizer(tap4)
mail.isUserInteractionEnabled = true
fetchAvailableProducts()
}
func fetchAvailableProducts() {
let productIdentifiers = NSSet(objects:
"customLifePremium" // 0
)
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
if (response.products.count > 0) {
validProducts = response.products
let prod100coins = response.products[0] as SKProduct
print("1st rpoduct: " + prod100coins.localizedDescription)
buyBtn.isHidden = false
}
}
/* func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
return true
}*/
func canMakePurchases() -> Bool { return SKPaymentQueue.canMakePayments() }
func purchaseMyProduct(_ product: SKProduct) {
if self.canMakePurchases() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
} else { print("Purchases are disabled in your device!") }
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction {
switch trans.transactionState {
case .purchased:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
UserDefaults.standard.set(true, forKey: "premiumUser")
UserDefaults.standard.set(false, forKey: "limitedVersion")
break
case .failed:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
print("Payment has failed.")
break
case .restored:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
print("Purchase has been successfully restored!")
UserDefaults.standard.set(true, forKey: "premiumUser")
UserDefaults.standard.set(false, forKey: "limitedVersion")
break
default: break
}}}
}
func restorePurchase() {
SKPaymentQueue.default().add(self as SKPaymentTransactionObserver)
SKPaymentQueue.default().restoreCompletedTransactions()
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
print("The Payment was successfull!")
}
override func viewWillAppear(_ animated: Bool) {
setGradientBackground()
super.viewWillAppear(animated)
}
#IBAction func restoreCC(_ sender: Any) {
restorePurchase()
}
#IBAction func buyCC(_ sender: Any) {
productIndex = 0
purchaseMyProduct(validProducts[productIndex])
}
#objc func tappedMe5()
{
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["dfmv.enterprise#gmail.com"])
mail.setSubject("")
mail.setMessageBody("", isHTML: true)
present(mail, animated: true)
}else{
let alert = UIAlertController(title: NSLocalizedString("info", comment: ""), message: NSLocalizedString("noClientMail", comment: ""), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: ""), style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func setGradientBackground() {
let colorTop = UIColor(red:1.00, green:0.30, blue:0.30, alpha:1.0).cgColor
let colorBottom = UIColor(red:1.00, green:0.69, blue:0.25, alpha:1.0).cgColor
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [colorTop, colorBottom]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.frame = self.view.bounds
self.view.layer.insertSublayer(gradientLayer, at:0)
}
}
Check this Gist that I personally used a week ago and passed the AppStore review for In-App Purchase flow.
IAP Service in Swift 5:
https://gist.github.com/egzonpllana/abd6d385bb45b1e329fe85a624ee531f
You can call IAPService.shared.getProducts() in AppDelegate method: didFinishLaunchingWithOptions to have all the products ready to use from your StoreKit in any viewcontroller, just check IAPService.shared.products.count.
Or call in your specific viewcontroller inside viewDidLoad and listen to changes with: IAPService.shared.didFinishRetrievingProducts = { [ weak self ] in ... }

SKProductsRequest returning 0 Products

I'm trying to do IAP however for some reason, my SKProductsRequest returns 0 products.
-Test products have been added to iTunes connect properly
-Banking and Taxing information is filled
-The product's bundle id matches the app bundle id
-I've waited up to two days for it to get processed through the servers
I used this youtube tutorial to build the app:
https://www.youtube.com/watch?v=zRrs7O5yjKI
And here is the code:
import UIKit
import StoreKit
class ViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
#IBOutlet weak var lblAd: UILabel!
#IBOutlet weak var lblCoinAmount: UILabel!
#IBOutlet weak var outRemoveAds: UIButton!
#IBOutlet weak var outAddCoins: UIButton!
#IBOutlet weak var outRestorePurchases: UIButton!
var coins = 50
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
outRemoveAds.isEnabled = false
outAddCoins.isEnabled = false
outRestorePurchases.isEnabled = false
if(SKPaymentQueue.canMakePayments()) {
print("IAP is enabled, loading")
let productID: NSSet = NSSet(objects: "com.IAPTesters.10Dolla", "com.IAPTesters.RemoveAds")
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
} else {
print("please enable IAPS")
}
}
#IBAction func btnRemoveAds(_ sender: Any) {
print("rem ads")
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.IAPTesters.RemoveAds") {
p = product
buyProduct()
}
}
}
#IBAction func btnAddCoins(_ sender: Any) {
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.IAPTesters.10Dolla") {
p = product
buyProduct()
}
}
}
#IBAction func btnRestorePurchases(_ sender: Any) {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
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
for product in myProduct {
print("product added")
print(product.productIdentifier)
print(product.localizedTitle)
print(product.localizedDescription)
print(product.price)
list.append(product)
}
outRemoveAds.isEnabled = true
outAddCoins.isEnabled = true
outRestorePurchases.isEnabled = true
}
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.IAPTesters.RemoveAds":
print("remove ads")
removeAds()
case "com.IAPTesters.10Dolla":
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, unlock IAP HERE")
print(p.productIdentifier)
let prodID = p.productIdentifier
switch prodID {
case "com.IAPTesters.RemoveAds":
print("remove ads")
removeAds()
case "com.IAPTesters.10Dolla":
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
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
When you run the app it will print "IAP is enabled, loading" and than "product request" but nothing else.
If I print response.invalidProductIdentifiers in the productsRequest function it will return my products: ["com.IAPTesters.RemoveAds", "com.IAPTesters.10Dolla"]
Thanks in advance for the help
It turns out that my banking and taxing information was filled out incorrectly. I refilled it and than I had to wait about 30 minutes for it to work again. Everything is now working correctly! Thanks for all the help
If you refer to the SKProductsRequest documentation you will see:
Note
Be sure to keep a strong reference to the request object; otherwise, the system might deallocate the request before it can complete.
Your SKProductsRequest instance is a local constant in viewDidLoad. This will be deallocated as soon as viewDidLoad exits and since the product request will complete asynchronously, this will be before the request is completed and you will therefore never get a call back.
You should retain your SKProductsRequest in a property so that it isn't released.
class ViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
#IBOutlet weak var lblAd: UILabel!
#IBOutlet weak var lblCoinAmount: UILabel!
#IBOutlet weak var outRemoveAds: UIButton!
#IBOutlet weak var outAddCoins: UIButton!
#IBOutlet weak var outRestorePurchases: UIButton!
var productsRequest: SKProductsRequest?
var coins = 50
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
outRemoveAds.isEnabled = false
outAddCoins.isEnabled = false
outRestorePurchases.isEnabled = false
if(SKPaymentQueue.canMakePayments()) {
print("IAP is enabled, loading")
let productID: NSSet = NSSet(objects: "com.IAPTesters.10Dolla", "com.IAPTesters.RemoveAds")
self.productsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request?.delegate = self
request?.start()
} else {
print("please enable IAPS")
}
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("product request")
let myProduct = response.products
for product in myProduct {
print("product added")
print(product.productIdentifier)
print(product.localizedTitle)
print(product.localizedDescription)
print(product.price)
list.append(product)
}
outRemoveAds.isEnabled = true
outAddCoins.isEnabled = true
outRestorePurchases.isEnabled = true
self.productsRequest = nil
}
FYI, your implementation of paymentQueueRestoreCompletedTransactionsFinished is incorrect; you should process the restored transactions in updatedTransactions through the .restored transaction state. The paymentQueueRestoreCompletedTransactionsFinished method should only be used to update your UI or perform any other tasks that are required when the restoration process is complete.
If I 'm understood correctly then the problem with your implementation is you have created your products in iTunes with wrong identifiers. As I know the product identifiers should be like your application bundle identifier followed by your product functionality i.e, COM.COMPANYNAME.MYNEWAPPLICATION.REMOVEADS, COM.COMPANYNAME.MYNEWAPPLICATION.10DOLLA
Sample code be like,
typealias SSIAPHelperCompletion = (_ result: [SKProduct]?, _ error: Error?) ->Void
class SSIAPHelper: NSObject {
fileprivate let productsRequest = SKProductsRequest(productIdentifiers: Set(arrayLiteral: "com.companyname.appname.removeads","com.companyname.appname.10dolla"))
fileprivate var completion: SSIAPHelperCompletion?
static let shared = SSIAPHelper()
func requestProducts(completionHandler: #escaping SSIAPHelperCompletion) {
self.completion = completionHandler
self.productsRequest.delegate = SSIAPHelper.shared
self.productsRequest.start()
}
}
extension SSIAPHelper: SKProductsRequestDelegate{
func requestDidFinish(_ request: SKRequest) {
print(#function)
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print(#function, response.products)
if let lCompletion = self.completion{
lCompletion(response.products, nil)
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print(#function)
}
}
You can get products by simply calling below function from your viewDidLoad()
SSIAPHelper.shared.requestProducts(completionHandler: { (result, error) in
})

Where should I declare/instantiate my Store object to keep it available while app running?

I have an iOS app written in Swift where I have written code for the store in it's own class (Store). I then have a view controller (StoreController) which displays the product details and presents buttons so that the user can buy/restore purchases. I am using the delegate pattern.
My question is where should I create the Store object? Currently I'm declaring it as a property of StoreController which I think is wrong. I would prefer to be able to create it when my app loads and keep it until it quits.
The current problem is that if I test it and navigate to the StoreController view (initiating the request via Store) then press 'back' the app freezes. I assume because it's waiting on the response?
I saw one example online where someone created it in the AppDelegate file but this didn't work for me as I wasn't able to reference it from my StoreController.
This is my Store class:
import Foundation
import StoreKit
protocol ClassStoreDelegate: class {
func storeUpdateReceived(store: Store)
}
class Store: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
// Properties
weak var delegate: ClassStoreDelegate?
var list = [SKProduct]()
var p = SKProduct()
var defaults = UserDefaults.standard // Where we save whether the user is pro
var localTitle: String?
var localDescription: String?
var localPrice: String?
// Methods
// Calling the delegate method
func storeUpdate() {
delegate?.storeUpdateReceived(store: self)
}
// Buy the product
func buy() {
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.squidgylabs.pro") {
p = product
buyProduct()
}
}
}
// Restore products
func restore() {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
func getProducts() {
if(SKPaymentQueue.canMakePayments()) {
let productID: NSSet = NSSet(objects: "com.squidgylabs.pro")
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
} else {
delegate?.storeUpdateReceived(store: self)
}
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let myProduct = response.products
for product in myProduct {
list.append(product)
}
// Update labels
localTitle = list[0].localizedTitle
localDescription = list[0].localizedDescription
// Format the price and display
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .currency
if let formattedPrice = formatter.string(from: list[0].price){
localPrice = ("buy \(formattedPrice)")
delegate?.storeUpdateReceived(store: self)
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
let transactionsArray = queue.transactions
if (transactionsArray.isEmpty) {
delegate?.storeUpdateReceived(store: self)
}
else {
for transaction in transactionsArray {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
switch prodID {
case "com.squidgylabs.pro":
defaults.set(true, forKey: "pro")
delegate?.storeUpdateReceived(store: self)
default:
delegate?.storeUpdateReceived(store: self)
}
}
}
}
func buyProduct() {
let pay = SKPayment(product: p)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(pay as SKPayment)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction: AnyObject in transactions {
let trans = transaction as! SKPaymentTransaction
switch trans.transactionState {
case .purchased:
let prodID = p.productIdentifier
switch prodID {
case "com.squidgylabs.pro":
defaults.set(true, forKey: "pro")
delegate?.storeUpdateReceived(store: self)
default:
delegate?.storeUpdateReceived(store: self)
}
queue.finishTransaction(trans)
break
case .failed:
delegate?.storeUpdateReceived(store: self)
queue.finishTransaction(trans)
break
case .restored:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
queue.finishTransaction(trans)
break
default:
break
}
}
}
}
And this is my StoreController (view controller):
import UIKit
class StoreController: UIViewController, ClassStoreDelegate {
// Properties
let store = Store()
// Outlets
#IBOutlet weak var localTitle: UILabel!
#IBOutlet weak var localDescription: UILabel!
#IBOutlet weak var buy: UIButton!
#IBOutlet weak var restore: UIButton!
// Actions
#IBAction func buy(_ sender: UIButton) {
print("buy pressed")
store.buy()
}
#IBAction func restore(_ sender: UIButton) {
print("restore pressed")
store.restore()
}
// Methods
override func viewDidLoad() {
super.viewDidLoad()
store.delegate = self // bind the delegate like this?
// Get list of products for the store
localTitle.isEnabled = false
localDescription.isEnabled = false
buy.isEnabled = false
restore.isEnabled = false
self.navigationItem.title = "Store"
// update once the list of products is got from the store object
store.getProducts()
}
// Running the delegate update
func storeUpdateReceived(store: Store) {
print("storeUpdateReceived activated")
if ((store.localTitle) != nil) {
localTitle.text = store.localTitle!
localDescription.text = store.localDescription
buy.setTitle(store.localPrice, for: .normal)
localTitle.isEnabled = true
localDescription.isEnabled = true
buy.isEnabled = true
restore.isEnabled = true
}
}
}
You're right - instantiate it in your AppDelegate. You know it will be called once and only once, so it's a good place to initialise things.
You can access the AppDelegate from anywhere in your app
appDelegate = (UIApplication.shared.delegate as! AppDelegate)

In-App-Purchase - Restore Purchase does not work?

In my application, the users can buy PRO membership to unlock stuff.
Here is the view controllers code where the user buy PRO membership:
import UIKit
import StoreKit
class UpgradePROViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
#IBOutlet weak var upgradeButton: UIButton!
var ApplicationLoadTime = NSUserDefaults().integerForKey("isPRO")
var product_id: NSString?;
let loadedValue = NSUserDefaults().integerForKey("isPRO")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var ApplicationLoadTimeUserDefault = NSUserDefaults.standardUserDefaults()
if (ApplicationLoadTimeUserDefault.valueForKey("isPRO") != nil){
ApplicationLoadTime = ApplicationLoadTimeUserDefault.valueForKey("isPRO") as! NSInteger!
}
upgradeButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
upgradeButton.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Highlighted)
upgradeButton.layer.cornerRadius = 5
upgradeButton.layer.borderWidth = 1
upgradeButton.layer.borderColor = UIColor(white: 1.0, alpha: 0.35).CGColor
upgradeButton.layer.backgroundColor = UIColor(white: 0.1, alpha: 0.85).CGColor
product_id = "com.myself.MyApp.GetPRO";
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func upgradeButtonAction(sender: AnyObject) {
buyConsumable()
}
#IBAction func restoreButtonAction(sender: AnyObject) {
if (SKPaymentQueue.canMakePayments()){
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
println("Purchased Restored");
}
}
func buyConsumable(){
println("About to fetch the products");
// 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<NSObject>);
productsRequest.delegate = self;
productsRequest.start();
println("Fething Products");
}else{
println("can't make purchases");
}
}
// Helper Methods
func buyProduct(product: SKProduct){
println("Sending the Payment Request to Apple");
var payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment);
}
// Delegate Methods for IAP
func productsRequest (request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
println("got the request from Apple")
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) {
println(validProduct.localizedTitle)
println(validProduct.localizedDescription)
println(validProduct.price)
buyProduct(validProduct);
} else {
println(validProduct.productIdentifier)
}
} else {
println("nothing")
}
}
func request(request: SKRequest!, didFailWithError error: NSError!) {
println("La vaina fallo");
}
func unlockProFeatures(){
ApplicationLoadTime = 1
NSString(format: "isPRO", "%i", 1)
var ApplicationLoadTimeUserDefault = NSUserDefaults.standardUserDefaults()
ApplicationLoadTimeUserDefault.setValue(ApplicationLoadTime, forKey: "isPRO")
ApplicationLoadTimeUserDefault.synchronize()
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
println("Received Payment Transaction Response from Apple");
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .Purchased:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
println("Product Purchased");
unlockProFeatures()
break;
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
println("Purchased Failed");
break;
case .Restored:
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
println("Purchased Restored");
break;
default:
break;
}
}
}
}
}
Somehow, it looks like the restore purchase does not work.. I am testing using sandbox users. Does anybody has any suggestions what to do? It works all fine to buy the items, but when I try to restore the purchase with the same user that has purchased the item, it does not work. Anything wrong in my code, or anything you would do different?

How can I if my app will remember that I bought In-App Purchase

I have made an app and made an In-App purchase for the premium version. Because I can't test In-App purchases in the Simulator.
So here is my code:
class settingsViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver, ADBannerViewDelegate {
#IBOutlet var adBennerView: ADBannerView!
#IBOutlet var outletRemoveAds: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if(SKPaymentQueue.canMakePayments()) {
println("IAP is enabled, loading")
var productID:NSSet = NSSet(objects: "xxx")
var request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as Set<NSObject>)
request.delegate = self
request.start()
} else {
println("please enable IAPS")
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func removeAds(sender: AnyObject) {
for product in list {
var prodID = product.productIdentifier
if(prodID == "xxx") {
p = product
buyProduct()
break;
}
}
}
#IBAction func restorePurchases(sender: AnyObject) {
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
var list = [SKProduct]()
var p = SKProduct()
func buyProduct() {
println("buy " + p.productIdentifier)
var pay = SKPayment(product: p)
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(pay as SKPayment)
}
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)
}
outletRemoveAds.enabled = true
}
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 "xxx":
println("remove ads")
removeAds()
isPremium = true
default:
println("IAP not setup")
}
queue.finishTransaction(trans)
break;
case .Failed:
println("buy error")
queue.finishTransaction(trans)
break;
default:
println("default")
break;
}
}
}
func finishTransaction(trans:SKPaymentTransaction)
{
println("finish trans")
SKPaymentQueue.defaultQueue().finishTransaction(trans)
}
func paymentQueue(queue: SKPaymentQueue!, removedTransactions transactions: [AnyObject]!)
{
println("remove trans");
}
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 "xxx":
println("remove ads")
removeAds()
isPremium = true
default:
println("IAP not setup")
}
}
}
func removeAds() {
adBennerView!.removeFromSuperview()
}
If the user bought the premium version - isPremium becomes true, so how do I know that every time the user log in isPremium still be true?
That happens because you only storing isPremium in the RAM and not anywhere else. Try using NSUserDefaults for that purpose, just to see how it can be done (actually it is advised not to use NSUserDefaults for that type of information, because it is easy to hack, but you have to understand the basics of storing information about your app state).

Resources