How to get Local Currency for SKProduct | Display IAP Price in Swift
The StoreKit Programming Guide has this code snippet for showing the price using the App Store currency:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *formattedPrice = [numberFormatter stringFromNumber:product.price];
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/ShowUI.html Listing 2-3
you should use NSNumberFormatter with the product values for price and priceLocale to output a string that is formatted correctly regardless of the user's location. product.price returns the price in the local currency as an NSDecimalNumber, and product.productLocale returns the NSLocale for the price value.
eg
var item = SKProduct()
for i in productsArray {
if i.productIdentifier == "com.Company.App.item1" {
item = i
if let formattedPrice = priceStringForProduct(item) {
//update ui with price
}
}
}
where priceStringForProduct is function defined elsewhere:-
func priceStringForProduct(item: SKProduct) -> String? {
let numberFormatter = NSNumberFormatter()
let price = item.price
let locale = item.priceLocale
numberFormatter.numberStyle = .CurrencyStyle
numberFormatter.locale = locale
return numberFormatter.stringFromNumber(price)
}
You might also want to handle the special case where the price is 0.0 (free tier). In this case amend the priceStringForProduct function to:
func priceStringForProduct(item: SKProduct) -> String? {
let price = item.price
if price == NSDecimalNumber(float: 0.0) {
return "GET" //or whatever you like really... maybe 'Free'
} else {
let numberFormatter = NSNumberFormatter()
let locale = item.priceLocale
numberFormatter.numberStyle = .CurrencyStyle
numberFormatter.locale = locale
return numberFormatter.stringFromNumber(price)
}
}
Edit: Couple other things, when you specify your productArray a more 'Swifty' way of doing it is:
var productsArray = [SKProduct]()
and then in your didRecieveResponse, instead of looping through the products you can just set productsArray as response.products
var productsArray = [SKProduct]()
if response.products.count != 0 {
print("\(response.products.map {p -> String in return p.localizedTitle})")
productsArray = response.products
}
Edit: To test for a number of different locales I usually make an array of NSLocales and then loop through printing the result. There is a repo with all the localeIdentifiers's here
so:
let testPrice = NSDecimalNumber(float: 1.99)
let localeArray = [NSLocale(localeIdentifier: "uz_Latn"),
NSLocale(localeIdentifier: "en_BZ"),
NSLocale(localeIdentifier: "nyn_UG"),
NSLocale(localeIdentifier: "ebu_KE"),
NSLocale(localeIdentifier: "en_JM"),
NSLocale(localeIdentifier: "en_US")]
/*I got these at random from the link above, pick the countries
you expect to operate in*/
for locale in localeArray {
let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = .CurrencyStyle
numberFormatter.locale = locale
print(numberFormatter.stringFromNumber(testPrice))
}
Swift 5 and 2021 version:
Create an extension to SKProduct so you can access product.localizedPrice
conveniently:
extension SKProduct {
private static let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
return formatter
}()
var isFree: Bool {
price == 0.00
}
var localizedPrice: String? {
guard !isFree else {
return nil
}
let formatter = SKProduct.formatter
formatter.locale = priceLocale
return formatter.string(from: price)
}
}
Original Anser:
Swift 4.2 version of Olivier's answer
func priceStringForProduct(item: SKProduct) -> String? {
let price = item.price
if price == NSDecimalNumber(decimal: 0.00) {
return "GET" //or whatever you like really... maybe 'Free'
} else {
let numberFormatter = NumberFormatter()
let locale = item.priceLocale
numberFormatter.numberStyle = .currency
numberFormatter.locale = locale
return numberFormatter.string(from: price)
}
}
Simply you just need to do the following
product.priceLocale.currencyCode