I am using Xcode 8.0, Swift 3.0 and testing in app purchases in my iPad. I want to test in app purchases using sandbox user.
There is no account added in device's Setting
The Problem is I am not getting product list in response of product request code.
Please take a look on my code:
let PRODUCT_ID_MY_PRODUCT = "com.company.ProjectName.MyProduct"
// The ProducID in this code and ProducID on iTunes are the SAME. ✔️
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if productID == nil {
productID = PRODUCT_ID_MY_PRODUCT
}
SKPaymentQueue.default().add(self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startPurchases()
}
func startPurchases() {
if (SKPaymentQueue.canMakePayments())
{
let productIDs = NSSet(object: self.productID!)
let productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productIDs as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
}
// Delegate Methods for SKProductsRequest
func productsRequest (_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let count : Int = response.products.count
// THE PROBLEM IS HERE.. I AM GETTING COUNT IS ZERO.. MEANS response.products returning null ARRAY
if (count>0) {
let validProducts = response.products
for aProduct in validProducts {
print(aProduct.productIdentifier)
}
} else {
DispatchQueue.main.async(execute: {
UIAlertView(title: "Purchase !", message: "Product not available", delegate: nil, cancelButtonTitle: "OK").show()
return
})
}
}
So..... That's the problem: I am getting response.products null (no data in array) so Please help me to find the solution. You can see the comments in code:
// THE PROBLEM IS HERE.. I AM GETTING COUNT IS ZERO.. MEANS response.products returning null ARRAY
I created products over iTunes Connect. You can see the image below. All the products are in "Ready to Submit" state.
There is some warning on iTunes
Your first In-App Purchase must be submitted with a new app version.
Select it from the app’s In-App Purchases section and click Submit.
Once your binary has been uploaded and your first In-App Purchase
has been submitted for review, additional In-App Purchases can be
submitted using the table below.
And
I also created Sendbox user for testing In-App Purchases. See the image below:
Did I miss something? Or what is the error? And where is error? I want to test in app purchases using sandbox user
I fixed this. There are some points need to careful about. See below:
Make sure your developer account did the paid application contract. see image below:
Create Products on the iTunes Connect.
Implement In-App-Purchases code and configuration settings.
Create one build with Distribution profile.
Upload build on store. Add build to current version. Add In-App-Purchases to the version on iTunes Connect.
Then try to test, if still not then submit app once then cancel it. then after try to test on your device.
Make sure when you test with sandbox user, you need to sign-out from your already logged in account from device settings, and login with sandbox ID.
some screenshots might be helpful.
please check these settings
capabilities --> In-App purchase --> set to "ON"
and at developer.apple.com--> enable In-App purchase for App ID.
and please test app on Device instead of simulator.
Related
If I purchase something and check the purchase receipt I can get the encoded value of it by this:
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
print(receiptData)
let receiptString = receiptData.base64EncodedString(options: [])
print("receiptString \(receiptString)")
// Read receiptData
}
catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
}
But If I purchase something, then delete the app and reinstall it again and check the receipt, I can't get anything with the upper code. It just get the appStoreReceiptURL and go straight away without entering do {} catch. How can I get the receipt in this scenario?
If you attempt to restore purchase , the user will not be refunded the purchased amount, however you would be able to verify that user purchased the product, and will also receive receipt that contants all the information about his previous purchase, therefore you can safely verify the purchase in your App.
In App Store Review Guides is clearly stated that
Any credits or in-game currencies purchased via in-app purchase may
not expire, and you should make sure you have a restore mechanism for
any restorable in-app purchases.
That means you should provide some mechanism (e.g. Restore Purchase Button) anyway, regardless of scenario when the user uninstalls Application. In your case, you can provide the Restore button directly on your Login screen. Check some inspiration on Restore purchase button in Apple Human Interface guidelines.
I you want to restore purchase directly with Apple API after user taps the Restore Purchase button, you can use:
SKPaymentQueue.default().restoreCompletedTransactions()
,which triggers Apple servers, checks the users Apple ID and gets all of the app purchases they have made before and returns you transaction that you observe with SKPaymentTransactionObserver with this code:
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
if transaction.transactionState == .restored {
//here is your restored transaction
}
}
}
If you however want to get hold of the new receipt with all receipt data, including previous purchases, I recommend not using directly Apple API, but using SwiftyStoreKit library : link on github . Code example below:
func restoreYourPurchases( completion: #escaping (Result<Bool,Error>) -> Void) {
SwiftyStoreKit.restorePurchases(atomically: true) { results in
var restoreSuccessfull = false
if results.restoreFailedPurchases.count > 0 {
print("Restore Failed: \(results.restoreFailedPurchases)")
}
else if results.restoredPurchases.count > 0 {
print("Restore Success: \(results.restoredPurchases)")
for purchase in results.restoredPurchases {
if purchase.productId == "yourID" {
let timeOfPurchase = purchase.originalPurchaseDate
}
}
}
else {
print("Nothing to Restore")
completion(.success(false))
}
}
}
I have never integrate IAP before, I am trying to integrate IAP in my iOS App first time, I have search lots of articles on internet, I followed all of them to resolve my issue, but I don't have any idea how to solve it.
I have full filled Agreement Tax and Banking, now Its status is Active.
I have added new user in sandbox tester.
I have choose Non-Renewing Subscription in features menu, now It's status is Ready To Submit,
I have again and again removed application in device (iPhone XR and iPad 5).
I have been waited for a long time, approx 5 to 7 days for activation.
I have already enabled In-App Purchase flag from capabilities.
My Development Profile is also consider with In-App Purchase.
I have sign out (iTunes account) my all device (iPhone XR and iPad 5).
My Product ID is relevant with my Bundle ID.
My Code is below...
func IAPintegrate(){
if (SKPaymentQueue.canMakePayments()) {
let productId : NSSet = NSSet(objects: IAP_DEV_PRODUCT_ID)
productsRequest = SKProductsRequest(productIdentifiers: productId as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
}
I have also added Delegate methods,
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print(response.products)
let count : Int = response.products.count
if (count>0) {
let validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == IAP_DEV_PRODUCT_ID) {
print(validProduct.localizedTitle)
print(validProduct.localizedDescription)
print(validProduct.price)
self.buyProduct(product: validProduct)
} else {
print(validProduct.productIdentifier)
}
} else {
print("nothing")
}
}
still my product count is always 0 please help me what should i do ?
Check whether you are getting any product identifier strings that is invalid in didReceive response method.
print("Invalid product identifiers \(response.invalidProductIdentifiers)")
The source of the problem is shown in your third screen shot. Your in-app purchases are Ready To Submit. That means they have not yet been submitted and approved. Therefore, as far as the store is concerned, they don't exist.
I am trying to fetch an in-app-purchase from App Store Connect like this:
private let kOneMonthSubscriptionId = "DOUBLESPEEDENERGY"
func loadProducts() {
let identifiers = Set([kOneMonthSubscriptionId])
let request = SKProductsRequest(productIdentifiers: identifiers)
request.delegate = self
request.start()
}
override func viewDidAppear(_ animated: Bool) {
if SKPaymentQueue.canMakePayments()
{
loadProducts()
}
}
extension homeVC: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
if response.products.count > 0 {
print("Purchasable products available!")
// 1. Save the SKProduct's so you could let the user make a purchase
// 2. Update the UI - it lets you change the product prices without updating the app
} else {
print("No purchasable products available.")
// This might happen when your product identifiers are incorrect or your in-app purchases products weren't processed on iTunes Connect yet
}
}
Please have a look if their is anything wrong with my code, I really appreciate it!
Thanks in advance for all the help!
The most likely reason is that you don't have a banking method for In-App Purchases setup in App Store Connect (Agreements, Tax and Banking section (Paid Apps)), if you don't then your app cannot access the In-App Purchase service because it doesn't know where to make payments even though you are in a sandbox environment.
If this doesn't help have a look at some other possibilities why it's not working:
You did not use an explicit App ID.
You did not use the Provisioning
Profile associated with your explicit App ID.
You did not use the
correct product identifier in your code.
You did not clear your In App Purchase products for sale in iTunes Connect.
You might have modified your products, but these changes are not yet available to all the App Store servers.
Hope this helps!
I have been google this issue for couple hours. I have attempted something like:
confirm Bundle Identifier and product id are absolutely correct
remove and reinstall app on both Simulator and real devices
I have try both 'productID' and 'com.company.project.productID'
The IAP in iTunes connect should be configured correct as well
The only thing I'm not sure is that I haven't fill Banking and Tax things in my iTunes connect. Actually, I just filled the Banking info, but it needs 24 hours to update.
My codes look like this
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Set IAPS
if(SKPaymentQueue.canMakePayments()) {
println("IAP is enabled, loading")
var productID:NSSet = NSSet(objects: "ProductID")
var request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as Set<NSObject>)
request.delegate = self
request.start()
} else {
println("please enable IAPS")
}
}
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)
}
}
This code is from a example, it was work very well in my simulator. But when I replace the ProductID with my own productID (of course bundleID as well), the SKProductsrequest become return nothing.
I have no idea why, hope some one can help me. Thx!
I was having this issue all week - no matter what I tried code wise and tweaking my build & provisioning settings, I got no products back.
What finally fixed it for me was changing the bundle id for my app xcode from company.appname to com.company.appname. Meanwhile you want to refer to your in-app purchase IDs withthe format com.company.appname.thingforpurchase1 etc.
In trying to solve this, I re-did the process of setting up automatic provisioning within the project and build settings & I re-added my developer account to xcode again. After doing this, the above syntax worked for me. Note that on itunes connect, my apps' bundle ID is still specified as just company.appname, but for some reason in xcode it needs the com. at the start too.
There is one other thing i've had to do differently with Swift 2.0 vs Swift 1.x - the compiler will no longer accept the product id's are no longer an NSSet - instead the request seems to want identifiers be given as a Set<String> - see this in the example below.
Note this solution was developed with and worked in swift 2.0 and xcode 7 beta.
Ex:
func requestProductInfo() {
print("about to fetch product info")
if SKPaymentQueue.canMakePayments() {
let request = SKProductsRequest(productIdentifiers:
Set(productIDs))
let productIdentifiers: NSSet = NSSet(array: productIDs) // NSset might need to be mutable
let productRequest : SKProductsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
//we set our class as its delegate (so we can handle the response)& trigger the request.
productRequest.delegate = self
productRequest.start()
print("Fetching Products");
}
else {
print("can't make purchases")
}
}
The problem was US Tax Form and Agreement. Once its approved, everything it will work.
I'm having an issue with In-App purchases on iOS. I have 5 In-App Purchases in a game, all of which work exactly as expected when tested on an iPhone 6 (iOS 8.3). When I go to test on iPad Air 2 (iOS 8.2), all IAPs fail immediately. Has anyone else experienced this problem? Is there some code that is specific to iPad that I have to add?
EDIT: Strangely, updating the iPad to iOS 8.3 fixed the problem. Any ideas as to why this issue is occurring? Should I change my app to only support iOS 8.3 and above?
To test the app, I'm using TestFlight, the same network connection, and the same Apple ID.
The code I'm using for In-App Purchases is Below:
func inApp() {
if (SKPaymentQueue.canMakePayments())
{
var productID:NSSet = NSSet(object: product_id);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as Set<NSObject>);
productsRequest.delegate = self;
productsRequest.start();
}else{
displayAlert()
}
}
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 == product_id) {
println(validProduct.localizedTitle)
println(validProduct.localizedDescription)
println(validProduct.price)
buyProduct(validProduct);
} else {
println(validProduct.productIdentifier)
}
} else {
displayAlert()
}
}
func request(request: SKRequest!, didFailWithError error: NSError!) {
self.displayAlert()
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .Purchased:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
if product_id == "com.shv.FrenzyTenLives" {
defaults.setInteger(10, forKey: "totalLives")
} else if product_id == "com.shv.FrenzyFiveLives" {
defaults.setInteger(5, forKey: "totalLives")
} else if product_id == "com.shv.FrenzyInfiniteLives" {
defaults.setBool(true, forKey: "infiniteLives")
} else if product_id == "com.shv.FrenzyShield" {
defaults.setInteger(5, forKey: "shieldValue")
} else if product_id == "com.shv.FrenzyRemoveAds" {
defaults.setBool(true, forKey: "adsRemoved")
adBanner.hidden = true
}
break;
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
self.displayAlert()
break;
case .Restored:
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
if product_id == "com.shv.FrenzyTenLives" {
defaults.setInteger(10, forKey: "totalLives")
} else if product_id == "com.shv.FrenzyFiveLives" {
defaults.setInteger(5, forKey: "totalLives")
} else if product_id == "com.shv.FrenzyInfiniteLives" {
defaults.setBool(true, forKey: "infiniteLives")
} else if product_id == "com.shv.FrenzyRemoveAds" {
defaults.setBool(true, forKey: "adsRemoved")
adBanner.hidden = true
}
break;
default:
break;
}
}
}
}
Usually, when one device will not perform in app purchase, it's a setting under restrictions.
If you've checked and disabled that restriction or all restrictions - you can often fix this by signing out of the App Store entirely and powering down the device. When it starts cleanly, you can log in again. When you sign in, be sure to buy something (a free song of the week, a free app or even a paid app) to get through the verification questions. Once that's done, recheck an IAP (in-app purchase) to be sure things are functional.
As a last resort, you might need to contact Apple Support for Apple ID - but most times you can fix this without needing their help.
You should check the following things.
Make sure you can answer “Yes” to each of these questions:
Have you enabled In-App Purchases for your App ID?
Have you checked Cleared for Sale for your product?
Does your project’s .plist Bundle ID match your App ID?
Have you generated and installed a new provisioning profile for the new App ID?
Have you configured your project to code sign using this new provisioning profile?
Are you using the full product ID when when making an SKProductRequest?
Have you waited several hours since adding your product to iTunes Connect?
Have you tried deleting the app from your device and reinstalling?
Is your device jailbroken? If so, you need to revert the jailbreak for IAP to work.
If you answered “No” to any one of these questions, there’s your problem.
You should visit following links definitely you will get solution.
https://www.innofied.com/in-app-purchase-working-ios-solution/
Without a definition of "fail immediately" my best guess is that you were not logged in to a valid sandbox testing account on the iPad and in the midst of updating the iOS version this got reconciled, which is why it works on 8.3.
The easiest way to get IAP testing to work is to log out of iTunes:
Settings -> App and iTunes Store -> Tap apple ID and log out.
Once you've logged out, try to make an IAP and you will be prompted to log in - once you enter valid test account credentials, the IAP will download - if it doesn't, post your log files here. Note that you can find or create testing accounts inside iTunes Connect.
IAP is an extremely complicated subject with numerous points of failure - knowing that your IAPs work on one device but not another points to a configuration issue specific to the device on which the IAP failed.