Skip to content

Instantly share code, notes, and snippets.

@adammagana
Last active March 15, 2021 22:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adammagana/916b38e1e8c9081caccc7bea9d441e73 to your computer and use it in GitHub Desktop.
Save adammagana/916b38e1e8c9081caccc7bea9d441e73 to your computer and use it in GitHub Desktop.
An Android SkuDetails property extension that calculates price-per-month.
import com.android.billingclient.api.SkuDetails
import java.lang.Exception
import java.text.NumberFormat
import java.util.*
/**
* Currency code for the U.S. dollar
*/
private const val USD = "USD"
/**
* Uses [SkuDetails.getSubscriptionPeriod], [SkuDetails.getOriginalPriceAmountMicros],
* [SkuDetails.getPriceCurrencyCode], and the device's default locale to calculate and format the
* price per month from the given subscription's "original" price.
*
* "Original" price is defined in the SDK as "before any applicable sales have been applied."
*
* @return Null if [SkuDetails.getSubscriptionPeriod] does not match a supported ISO 8601 formatted
* string (i.e. the value is absent/null).
* @see SkuDetails
*/
val SkuDetails.pricePerMonth: String?
get() {
// Bail early if we know that we can't derive a subscription from the SkuDetails. This value
// is expected to be absent for non-subscription products.
if (this.subscriptionPeriod.isNullOrBlank()) {
return null
}
val originalPriceAmountMicros: Float = this.originalPriceAmountMicros.toFloat()
// `subscriptionPeriod` produces an ISO 8601 formatted string. Only check against the
// relevant strings specified by the `BillingClient` API.
val rawPricePerMonth: Float = when (this.subscriptionPeriod) {
"P1Y" -> originalPriceAmountMicros / 12_000_000 // 12 month period
"P6M" -> originalPriceAmountMicros / 6_000_000 // 6 month period
"P3M" -> originalPriceAmountMicros / 3_000_000 // 3 month period
"P1M" -> originalPriceAmountMicros / 1_000_000 // 1 month period
else -> return null
}
// Use the device's locale and the SkuDetail's currency code to produce a string that
// represents the calculated monthly price.
val numberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault())
numberFormat.currency = try {
Currency.getInstance(this.priceCurrencyCode)
} catch (ex: Exception) {
// Protect against null currency codes as well as a codes that aren't a valid ISO 4217
// string. Fallback to USD in this case.
Currency.getInstance(USD)
}
return numberFormat.format(rawPricePerMonth)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment