How to get Local Currency for SKProduct | Display

2020-05-22 09:25发布

I am trying to display the price of an in app purchase using the local currency, so the correct dollar is displayed for both US & CA as well as Euro, GBP etc.

I know each SKProduct has a price which appears during the transaction as an alert view, this appears when confirming the purchase.

However I want to display the price before confirmation.

I was thinking to do something like this:

//Products Array
var productsArray: Array<SKProduct!> = []

//Request Products
    func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
        if response.products.count != 0 {
            for product in response.products {
                print("\(product.localizedTitle)")
                productsArray.append(product)
            }
        }
        else {
            print("There are no products.")
        }

        if response.invalidProductIdentifiers.count != 0 {
            print("\(response.invalidProductIdentifiers.description)")
        }            
     }


let item = SKProduct
  for i in productsArray {
    if i.localizedTitle == "com.Company.App.item1" 
      item = i
    }
  }

But this doesn't work as i Doesn't seem to have a price property.

Does anybody know how I can set a label text to the price of an iAP using the correct local currency?

For example £1.49 GBP is $1.99 US dollars using Apples Pricing Matrix and outputting the value should match the values of the product price when confirming the transaction.

7条回答
我欲成王,谁敢阻挡
2楼-- · 2020-05-22 10:02

Swift 3 version of Olivier's priceStringForProduct:item

func priceStringForProduct(item: SKProduct) -> String? {
        let price = item.price
        if price == 0 {
            return "Free!" //or whatever you like
        } else {
            let numberFormatter = NumberFormatter()
            let locale = item.priceLocale
            numberFormatter.numberStyle = .currency
            numberFormatter.locale = locale
            return numberFormatter.string(from: price)
        }
    }
查看更多
我欲成王,谁敢阻挡
3楼-- · 2020-05-22 10:05

Swift 5 and 2019 version:

Create an extension to SKProduct so you can access product.localizedPrice conveniently:

extension SKProduct {
    fileprivate static var formatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        return formatter
    }

    var localizedPrice: String {
        if self.price == 0.00 {
            return "Get"
        } else {
            let formatter = SKProduct.formatter
            formatter.locale = self.priceLocale

            guard let formattedPrice = formatter.string(from: self.price) else {
                return "Unknown Price"
            }

            return formattedPrice
        }
    }
}

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)
    }
}
查看更多
戒情不戒烟
4楼-- · 2020-05-22 10:16

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

查看更多
再贱就再见
5楼-- · 2020-05-22 10:18

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))
    }
查看更多
神经病院院长
6楼-- · 2020-05-22 10:22

Simply you just need to do the following

product.priceLocale.currencyCode
查看更多
爷、活的狠高调
7楼-- · 2020-05-22 10:25

You MUST NOT display the price in the local currency. You must display it in the currency provided by the store. If say a French user purchases from the French app store then the price comes up in Euro, and that's what the user pays. If that user goes to New Zealand and changes his or her locale to New Zealand but stays with the French app store, they are still billed in Euros. So that's what you should display.

You say "£1.49 is $1.99 according to Apple's pricing matrix". But £1.49 IS NOT $1.99. If I, as a British user, go to the USA and buy from the UK app store, I pay £1.49 even if I'm in the USA. And "£1.49" is what the store will tell you.

查看更多
登录 后发表回答