show yearly price in InApp Purchase swift ios - ios

Currently i am working on a iOS App using Swift. I am enabled InApp Purchased. Payment is doing perfectly but when i am showing data from iTunes Connect, the monthly subscription data showing perfectly but i want show price on yearly tab in monthly format with some discount and when user tap on card, it should be show yearly price. I am unable to do this. Description shown in image. Thanks in Advance.
image1
image 2
I want show price like this
// Currently i am getting product info with this method
// MARK: - REQUEST IAP PRODUCTS
func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
if (response.products.count > 0) {
iapProducts = response.products
// showHUD("Loading...")
let indexPath = IndexPath.init(row: 0, section: 0)
guard let cell = collectionView.cellForItem(at: indexPath) as? CollectionViewCell else { return }
let numberFormatter = NumberFormatter()
let firstProduct = response.products[0] as SKProduct
print("localizedDescription", firstProduct.localizedDescription)
print("localizedTitle", firstProduct.localizedTitle)
// Get its price from iTunes Connect
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.numberStyle = .currency
numberFormatter.locale = firstProduct.priceLocale
let price1Str = numberFormatter.string(from: firstProduct.price)
// Show its description
cell.monthlyLabel.text = "\(firstProduct.localizedTitle)"
cell.rupeesLabel.text = "\(price1Str!)"
cell.perMonthLabel.text = "\(firstProduct.localizedDescription)"
let indexPath1 = IndexPath.init(row: 1, section: 0)
guard let cell2 = collectionView.cellForItem(at: indexPath1) as? CollectionViewCell else { return }
let secondProd = response.products[1] as SKProduct
// Get its price from iTunes Connect
numberFormatter.locale = secondProd.priceLocale
let price2Str = numberFormatter.string(from: secondProd.price)
// Show its description
cell2.monthlyLabel.text = "\(secondProd.localizedTitle)"
cell2.rupeesLabel.text = "\(price2Str!)"
cell2.perMonthLabel.text = "\(secondProd.localizedDescription)"
// ------------------------------------
}
}

Showing an annual subscription in terms of months is a little more complicated than just dividing by twelve. SKProduct.price is an NSDecimalNumber class, not a regular float, so standard divide operator doesn't work.
You need to do something like this
product.price.dividing(by: NSDecimalNumber(decimal: Decimal(12.0)))
This will give you the divided NSDecimalNumber which you can pass to the formatter. One problem is that the divided value might round to an incorrect value. The trick is to create a custom NSDecimalNumberHandler that rounds as you want.
let behavior = NSDecimalNumberHandlerroundingMode: .down, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
product.price.dividing(by: NSDecimalNumber(decimal: Decimal(12.0)), withBehavior: behavior)
That should give you all the control you need to display the annual price at the monthly rate. I would also suggest that you display the total price nearby to not mislead the user too much. There is a fine line between optimizing your purchase flow and trying to scam people.

Thanks a lot Jacob Eiting. This is worked for me in Swift3.
let behavior = NSDecimalNumberHandler(roundingMode: .down, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
let price2Str = numberFormatter.string(from: (secondProd.price.dividing(by: NSDecimalNumber(decimal: Decimal(12.0)), withBehavior: behavior)))
cell2.rupeesLabel.text = "\(price2Str!)"

Related

HealthKit Blood Oxygen SPO2

With the series 6 Apple Watch, you can now get a measure of your SP02, hemoglobin content in your blood oxygen. The health app on the iPhone shows you all the measurements in the Respiratory section. This is a critical component for COVID patients.
I have not been able to find anyway to access this information programatically.
I have checked all HKObjectTypes in the latest Apple documentation. Is this information currently available to iOS developers?
Any information would be of great use as several researchers are requesting it.
Ok, I am being told that this is the same as Oxygen Saturation.Here is the code I use to query HK for Oxygen Saturation:
// Get SPO2
func getOxygenSaturation()
{
// Type is SPO2 SDNN
let osType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.oxygenSaturation)!
let predicate = HKQuery.predicateForSamples(withStart: Date.distantPast, end: Date(), options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let osUnit:HKUnit = HKUnit(from: "%")
let osQuery = HKSampleQuery(sampleType: osType,
predicate: predicate,
limit: 10,
sortDescriptors: [sortDescriptor]) { (query, results, error) in
guard error == nil else { print("error"); return }
// Get the array of results from the sample query
let sampleArray:[HKSample]? = results!
// Loop through the array of rsults
for (_, sample) in sampleArray!.enumerated()
{
// Be sure something is there
if let currData:HKQuantitySample = sample as? HKQuantitySample
{
let os: Double = (currData.quantity.doubleValue(for: osUnit) * 100.0)
let d1: Date = currData.startDate
let str1 = SwiftLib.returnDateAndTimeWithTZ(date: d1, info: self.info!)
Dispatch.DispatchQueue.main.async {
self.tvOxygenValue.text = String(format: "%.0f%#", os, "%");
self.tvOxygenDate.text = str1
//print("\(os)");
}
}
}
print("Done")
self.loadAndDisplayActivityInformation()
}
healthStore!.execute(osQuery)
}

Only show my float number to a certain decimal place - Swift

basically I want to remove the decimal places for my step calories burnt calculation. I know I need to add something to self.total2.text = ("\(String(bmi)) kcal") but just need a quick bit of advice on achieving this.
#IBAction func calc2(_ sender: Any) {
if self.value111.text! != "" && self.value222.text! != "" {
let textfieldInt = Float(value111.text!)
let textfield2Int = Float(value222.text!)
var bmi:Float = (((textfieldInt! * 2.204623) * 0.5) / 1500) * textfield2Int!
self.total2.text = ("\(String(bmi)) kcal")
let banner = StatusBarNotificationBanner(title: "Calculation Done! Submit to save. ✅", style: .warning)
banner.show(queuePosition: .front)
}
}
#IBAction func submit2(_ sender: Any) {
let dict = (["kcal": self.total.text!, "date": self.getDate()])
ref?.child("user").child(Auth.auth().currentUser!.uid).child("measurements").child("calculations").child("kcal").child("\(getDate())").setValue(dict)
total.text = ""
let banner = NotificationBanner(title: "Success, Step Calories Burnt has been saved today ⚖️", style: .success)
banner.show(queuePosition: .front)
}
Use a NumberFormatter (have a look here)
let bmi:Float = (((textfieldInt! * 2.204623) * 0.5) / 1500) * textfield2Int!
let formatter = NumberFormatter()
//Set the min and max number of digits to your liking, make them equal if you want an exact number of digits
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 3
self.total2.text = formatter.string(from: NSNumber(value: bmi)) + " kcal"
Have a look at the NumberFormatter class, which lets you fine-tune the string representation of a numeric value, whether integer or floating-point. Set up the NumberFormatter to produce the output in the format you want, then call string(from:) to create a string from your number.

How to fetch Resting energy value from HealthKit which has same value as Health App's value?

I'm using apple's HealthKit sample however resting energy value shown in Health app in iPhone doesn't match with the value fetched in sample app.
As per apple docs, HKQuantityTypeIdentifierBasalEnergyBurned is representing resting energy so I fetched this value from the HealthKit but the value I received doesn't match with the resting energy shown in Health App.
So I came across the apple's HealthKit sample where they are calculating resting energy based on formula:
// Calculates the user's total basal (resting) energy burn based off of their height, weight, age,
// and biological sex. If there is not enough information, return an error.
private func fetchTotalBasalBurn(completion: #escaping (HKQuantity?, Error?) -> Void)
{
let todayPredicate: NSPredicate = self.predicateForSamplesToday()
let weightType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bodyMass)!
let heightType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.height)!
let queryWeigth: HKCompletionHandle = {
(weight, error) -> Void in
guard let weight = weight else {
completion(nil, error)
return
}
let queryHeigth: HKCompletionHandle = {
(height, error) -> Void in
if height == nil {
completion(nil, error)
return;
}
var dateOfBirth: Date!
do {
dateOfBirth = try self.healthStore!.dateOfBirth()
} catch {
completion(nil, error)
return
}
var biologicalSexObjet: HKBiologicalSexObject!
do {
biologicalSexObjet = try self.healthStore!.biologicalSex()
} catch {
completion(nil, error)
return
}
// Once we have pulled all of the information without errors, calculate the user's total basal energy burn
let basalEnergyButn: HKQuantity? = self.calculateBasalBurnTodayFromWeight(weight, height: height, dateOfBirth: dateOfBirth!, biologicalSex: biologicalSexObjet)
completion(basalEnergyButn, nil)
}
if let healthStore = self.healthStore {
healthStore.mostRecentQuantitySample(ofType: heightType, predicate: todayPredicate, completion: queryHeigth)
}
}
if let healthStore = self.healthStore {
healthStore.mostRecentQuantitySample(ofType: weightType, predicate: nil, completion: queryWeigth)
}
}
private func calculateBasalBurnTodayFromWeight(_ weight: HKQuantity?, height: HKQuantity?, dateOfBirth: Date, biologicalSex: HKBiologicalSexObject) -> HKQuantity?
{
// Only calculate Basal Metabolic Rate (BMR) if we have enough information about the user
guard let weight = weight, let height = height else {
return nil
}
// Note the difference between calling +unitFromString: vs creating a unit from a string with
// a given prefix. Both of these are equally valid, however one may be more convenient for a given
// use case.
let heightInCentimeters: Double = height.doubleValue(for: HKUnit(from:"cm"))
let weightInKilograms: Double = weight.doubleValue(for: HKUnit.gramUnit(with: HKMetricPrefix.kilo))
let nowDate = Date()
let ageComponents: DateComponents = Calendar.current.dateComponents([Calendar.Component.year], from: dateOfBirth, to: nowDate)
let ageInYears: Int = ageComponents.year!
// BMR is calculated in kilocalories per day.
let BMR: Double = self.calculateBMRFromWeight(weightInKilograms: weightInKilograms, height: heightInCentimeters, age: ageInYears, biologicalSex: biologicalSex.biologicalSex)
// Figure out how much of today has completed so we know how many kilocalories the user has burned.
let (startOfToday, endOfToday): (Date, Date) = self.datesFromToday()
let secondsInDay: TimeInterval = endOfToday.timeIntervalSince(startOfToday)
let percentOfDayComplete: Double = nowDate.timeIntervalSince(startOfToday) / secondsInDay
let kilocaloriesBurned: Double = BMR * percentOfDayComplete
let basalBurn = HKQuantity(unit: HKUnit.kilocalorie(), doubleValue: kilocaloriesBurned)
return basalBurn
}
/// Returns BMR value in kilocalories per day. Note that there are different ways of calculating the
/// BMR. In this example we chose an arbitrary function to calculate BMR based on weight, height, age,
/// and biological sex.
private func calculateBMRFromWeight(weightInKilograms: Double, height heightInCentimeters: Double, age ageInYears: Int, biologicalSex: HKBiologicalSex) -> Double
{
var BMR: Double = 0
if biologicalSex == .male {
BMR = 66.0 + (13.8 * weightInKilograms) + (5.0 * heightInCentimeters) - (6.8 * Double(ageInYears))
return BMR
}
BMR = 655 + (9.6 * weightInKilograms) + (1.8 * heightInCentimeters) - (4.7 * Double(ageInYears))
return BMR
}
I'm tried the sample app to fetch resting energy however still resting energy value shown in health app and sample app doesn't have same value.
Could any body tell me how to fetch resting energy or what is the calculation used by Health App to find resting energy?
It would be great if someone can give me some pointers on it, I'm pretty new to HealthKit.
Thanks.
It seems that Apple's sample is outdated. As of iOS 8 and watchOS 2 there's a call to retrieve this information in the same way that active calories are retrieved; simply change the identifier. Apple Documentation
HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.basalEnergyBurned)
Don't forget to include the additional permission to read this data as well.

iOS Swift PayPal Always In Sandbox

I have successfully integrated PayPal into my app. However, it seems to be stuck in Sandbox mode. Here is my code to initialize it:
PayPalMobile .initializeWithClientIdsForEnvironments([PayPalEnvironmentProduction: "APP-0XU423690N0796541"])
As can been seen, I'm not even specifying a sandbox ID.
My code to initiate the payment is:
let payPalConfig = PayPalConfiguration()
payPalConfig.merchantName = "MacCrafters Software"
let item1 = PayPalItem(name: "Donation", withQuantity: 1, withPrice: NSDecimalNumber(string: amountField.text!), withCurrency: "USD", withSku: "Donation")
let items = [item1]
let subtotal = PayPalItem.totalPriceForItems(items)
// Optional: include payment details
let shipping = NSDecimalNumber(string: "0.00")
let tax = NSDecimalNumber(string: "0.00")
let paymentDetails = PayPalPaymentDetails(subtotal: subtotal, withShipping: shipping, withTax: tax)
let total = subtotal.decimalNumberByAdding(shipping).decimalNumberByAdding(tax)
let payment = PayPalPayment(amount: total, currencyCode: "USD", shortDescription: "Donation", intent: .Sale)
payment.items = items
payment.paymentDetails = paymentDetails
if (payment.processable) {
let paymentViewController = PayPalPaymentViewController(payment: payment, configuration: payPalConfig, delegate: self)
presentViewController(paymentViewController!, animated: true, completion: nil)
}
At the bottom of the PayPal view it always says "Mock Data". I get the same results no matter if I'm in the simulator or on a device. What am I doing wrong?

How to get Local Currency for SKProduct | Display IAP Price in Swift

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.
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)
}
}
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))
}
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
Simply you just need to do the following
product.priceLocale.currencyCode
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.
Apple provides regularPrice sample code here:
https://developer.apple.com/documentation/storekit/in-app_purchase/offering_completing_and_restoring_in-app_purchases
extension SKProduct {
/// - returns: The cost of the product formatted in the local currency.
var regularPrice: String? {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = self.priceLocale
return formatter.string(from: self.price)
}
}
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)
}
}

Resources