How to get separate price and currency information for an in-app purchase?
Asked Answered
U

8

28

I am implementing in-app purchases for an app with support for several countries.

The In-App Billing Version 3 API claims that:

No currency conversion or formatting is necessary: prices are reported in the user's currency and formatted according to their locale.

This is actually true, since skuGetDetails() takes care of all necessary formatting. The response includes a field called price, which contains the

Formatted price of the item, including its currency sign. The price does not include tax.

However, I need the ISO 4217 currency code (retrievable if I know the store locale) and the actual non-formatted price (optimally in a float or decimal variable) so I can do further processing and analysis myself.

Parsing the return of skuGetDetails() is not a reliable idea, because many countries share the same currency symbols.

Currencies

How can I get the ISO 4217 currency code and non-formatted price of an in-app purchase with the In-App Billing Version 3 API?

Undemonstrative answered 11/6, 2013 at 7:57 Comment(5)
help me to understand why do you need this? .. //btw. you can declare in the developer console for every country a diffrent price as i know..Psoriasis
@AlexanderSidikov: I need this to perform analytics on in-app purchase information. As the accepted answer states, this is not currently possible, so that answers my question. I do not know why a bounty was set for this question though...Undemonstrative
@AlexanderSidikov: Our IAP analytics system is completely separate from the actual IAP system. We use the same analytics system across the entire organization for several products over several platforms. It is much easier to gather information if it is sent directly from the client device to the analytics servers than to implement a custom solution for each product for each platform. Possible it is, but not practical. For example, in iOS you can get the locale of the store in SKProduct.priceLocale, which you can then use to get the currency code with objectForKey:NSLocaleCurrencyCode.Undemonstrative
@AlexanderSidikov: In fact, getting the store locale, and a way to produce a currency code from a store locale (just like in iOS) would be optimal. You can use the locale for other fancy things like number and date formatting, which you can then eventually use to produce a formatted price like the API does.Undemonstrative
Any idea how to get from the latest in-app API - version 5 or 6? for both onetime and subscription productsScary
D
21

Full information can be found here, but essentially in August 2014 this was resolved with:

The getSkuDetails() method

This method returns product details for a list of product IDs. In the response Bundle sent by Google Play, the query results are stored in a String ArrayList mapped to the DETAILS_LIST key. Each String in the details list contains product details for a single product in JSON format. The fields in the JSON string with the product details are summarized below

price_currency_code ISO 4217 currency code for price. For example, if price is specified in British pounds sterling, price_currency_code is "GBP".

price_amount_micros Price in micro-units, where 1,000,000 micro-units equal one unit of the currency. For example, if price is "€7.99", price_amount_micros is "7990000".

Denbrook answered 8/4, 2015 at 8:50 Comment(1)
Yes, I already knew this, and mentioned it in some comments. However, I'm changing the accepted answer to this one, as it is the one that most accurately reflects the current state of the situation.Undemonstrative
P
13

You can't, this is currently not supported. There is a feature request for it, but it may or may not get implemented.

https://code.google.com/p/marketbilling/issues/detail?id=93

Preindicate answered 11/6, 2013 at 8:53 Comment(1)
Seems like it finally got implementedUndemonstrative
C
8

You can. You need to modify SkuDetails.java like below.

Steps:

  1. Check their sample app for in-app billing.
  2. Modify the SkuDetails.java file as follows:
import org.json.JSONException; import org.json.JSONObject;

/**  
 * Represents an in-app product's listing details.  
 */ 
public class SkuDetails {
    String mItemType;
    String mSku;
    String mType;
    int mPriceAmountMicros;
    String mPriceCurrencyCode;
    String mPrice;
    String mTitle;
    String mDescription;
    String mJson;

    public SkuDetails(String jsonSkuDetails) throws JSONException {
        this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
    }

    public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
        mItemType = itemType;
        mJson = jsonSkuDetails;
        JSONObject o = new JSONObject(mJson);
        mSku = o.optString("productId");
        mType = o.optString("type");
        mPrice = o.optString("price");
        mPriceAmountMicros = o.optInt("price_amount_micros");
        mPriceCurrencyCode = o.optString("price_currency_code");
        mTitle = o.optString("title");
        mDescription = o.optString("description");
    }

    public String getSku() { return mSku; }
    public String getType() { return mType; }
    public String getPrice() { return mPrice; }
    public String getTitle() { return mTitle; }
    public String getDescription() { return mDescription; }
    public int getPriceAmountMicros() { return mPriceAmountMicros; }
    public String getPriceCurrencyCode() { return mPriceCurrencyCode; }

    @Override
    public String toString() {
        return "SkuDetails:" + mJson;
    } 
}
Columbia answered 10/10, 2014 at 10:48 Comment(1)
More than changing the code, I think explaining the reasoning behind it is more important. Around August 2014, a change in the billing API introduced a new field into the getSkuDetails() return value: price_currency_code. This change finally made it possible to get the currency code of a particular transaction.Undemonstrative
C
5

Here is my workaround :)

private static Locale findLocale(String price) {
    for (Locale locale : Locale.getAvailableLocales()){
        try {
            Currency currency = Currency.getInstance(locale);
            if (price.endsWith(currency.getSymbol())) 
                return locale;
        }catch (Exception e){

        }

    }
    return null;
}

Usage:

Locale locale = findLocale(price);
String currency = Currency.getInstance(locale).getCurrencyCode();
double priceClean = NumberFormat.getCurrencyInstance(locale).parse(price).doubleValue();
Cogency answered 8/9, 2013 at 18:22 Comment(1)
Plus one: Interesting workaround. But are there currencies using the same symbol that could lead to mistakes?Belay
F
2

Very simple. SKU returns the currency code ("price_currency_code" field). With that code you can retrieve the symbol using the Currency class. See the code attached:

String currencyCode = skuObj.getString("price_currency_code");
currencySymbol = Currency.getInstance(currencyCode).getSymbol();
Frans answered 12/4, 2016 at 8:28 Comment(0)
A
1

Here's a complete code:

ArrayList<String> skuList = new ArrayList<>();
skuList.add("foo");
skuList.add("bar");

final String[] prices = new String[skuList.size()];

Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

Bundle skuDetails = _appActivity.mService.getSkuDetails(3, _appActivity.getPackageName(), "inapp", querySkus);

int response = skuDetails.getInt("RESPONSE_CODE");
if(response == 0) {
    ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");

    int i = 0;
    for (String thisResponse : responseList) {
        JSONObject object = new JSONObject(thisResponse);
        String sku = object.getString("productId");
        final String priceCurrency = object.getString("price_currency_code");
        String priceAmountMicros = object.getString("price_amount_micros");
        float priceAmount = Float.parseFloat(priceAmountMicros) / 1000000.0f;
        String price = priceAmount + " " + priceCurrency;

        if(skuList.contains(sku)){
            prices[i] = price;
            i++;
        }
    }
}

From documentation:

price_currency_code ISO 4217 currency code for price. For example, if price is specified in British pounds sterling, price_currency_code is "GBP".

price_amount_micros Price in micro-units, where 1,000,000 micro-units equal one unit of the currency. For example, if price is "€7.99", price_amount_micros is "7990000". This value represents the localized, rounded price for a particular currency.

Now you just have to divide price_amount_micros by a 1000000 and concatenate it with currency.

Auburn answered 11/12, 2018 at 12:47 Comment(0)
O
0

You can check this The Android developers in select countries can now offer apps for sale in multiple currencies through Google Wallet Merchant Center. To sell your apps in additional currencies, you will need to set the price of the app in each country/currency. A list of supported countries/currencies is available in our help center.

If you make an app available in local currency, Google Play customers will only see the app for sale in that currency. Customers will be charged in their local currency, but payment will be issued in the currency set in your Google Wallet Merchant Center account.

Oarlock answered 1/8, 2013 at 11:13 Comment(1)
Ok, and how does this help me get the ISO 4217 currency code of the sold item?Undemonstrative
B
0

Another hardcoded workaround is to price items for countries with the same symbol, differently by a cent or so. When you retrieve the price of the item from google play upon purchasing and you know the retrieved currency symbol is one which is used in many countries ie. $. You then have a log of different prices on your backend server and correlate the purchase price with a specific country.

Bounty answered 24/2, 2014 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.