iOS app with iTunes store - get currency code (not priceLocal) - ios

We have an iOS app with in-app purchase and we want to track transactions with Google Analytics (enhanced ecommerce). We already have the proper handling for priceLocal, that's not the issue... we need to tell GA the specific currency code in use by the user. This info doesn't seems to be available directly and we would rather not do our own lookup.
Current code abstract:
// Set locale
NSLocale *storeLocale = product.priceLocale;
// instead of storeCountry we need storeCurrency, like USD, CAD, EUR, GBP...
NSString *storeCountry = (NSString *)CFLocaleGetValue((CFLocaleRef)storeLocale, kCFLocaleCountryCode);
[ecommerced setObject:storeCountry forKey:#"currencyCode"];

I haven't run this code to see if it works but this is how to get what you want.
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setNumberStyle: NSNumberFormatterCurrencyStyle];
[formatter setLocale: storeLocale];
NSLog("The currency code is: %#", formatter.currencyCode);
NSNumberFormatter Documentation

Related

What is the proper way to convert date object with separate timezone into NSDate

My app ingests data from a web service (PHP) which provides dates in this format:
endDate = {
date = "2020-09-30 16:16:08.000000";
timezone = "-04:00";
"timezone_type" = 1;
};
This is the code I have been using to convert to NSDate, and it works as far as I can tell, in every test, but it fails on a few devices according to user reports and debug logs.
Note that the correct conversion of this date determines if content is unlocked in the app, so when it fails, customers contact us about it.
NSDictionary* dateDict = [responseDict objectForKey:#"endDate"];
NSString* strEndDate = [dateDict objectForKey:#"date"];
NSString* strOffset = [dateDict objectForKey:#"timezone"];
NSTimeInterval zoneSeconds = 0;
NSRange rng = [strOffset rangeOfString:#":"];
if (rng.location != NSNotFound && rng.location >= 1)
{
NSString* hoursOnly = [strOffset substringToIndex:rng.location];
NSInteger offsetValue = [hoursOnly integerValue];
zoneSeconds = (3600 * offsetValue);
}
NSDateFormatter* df = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:zoneSeconds];
[df setTimeZone:timeZone];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss.000000"];
NSDate* newEndDate = [df dateFromString:strEndDate];
However, debug logs from a few users show that the dateFromString call is failing and returning nil.
We have one user who has 2 iOS devices, and using the same account (same date) the app performs as expected on one of them, but fails on the other. Same Apple ID, both running iOS12. Debug logs show both devices received the same date from the server, yet one of them failed to convert the date from a string to NSDate.
My assumption so far is that there is some setting or configuration on the device(s) where this fails that is different. But I have fiddled with calendar and date settings all day, and cannot get this to fail. I know the user in question has both devices configured to the same time zone.
Is there a better, more correct way to do this date conversion which might be more robust?
When using an arbitrary date format it's highly recommended to set the locale of the date formatter to the fixed value en_US_POSIX.
Rather than calculating the seconds from GMT it might be more efficient to strip the milliseconds with regular expression, append the string time zone and use an appropriate date format.
This code uses more contemporary syntax to set date formatter properties with dot notation and dictionary literal key subscription
NSDictionary *dateDict = responseDict[#"endDate"];
NSString *strEndDate = dateDict[#"date"];
NSString *strTimeZone = dateDict[#"timezone"];
NSString *dateWithoutMilliseconds = [strEndDate stringByReplacingOccurrencesOfString:#"\\.\\d+" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, strEndDate.length)];
NSString *dateWithTimeZone = [NSString stringWithFormat:#"%#%#", dateWithoutMilliseconds, strTimeZone];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.locale = [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"];
df.dateFormat = #"yyyy-MM-dd HH:mm:ssZZZZZ"];
NSDate *newEndDate = [df dateFromString:dateWithTimeZone];
The question was actually similar to (What is the best way to deal with the NSDateFormatter locale "feechur"?) as was suggested originally, but it was this other question (NSDateFormatter fails to return a datetime for UK region with 12 hour clock set) which really made it click for me - its the UK region with the 12hour clock which causes the code to fail, but the dateFormatter was easily fixed by simply setting the locale to "un_US_POSIX" as suggested in the answer to that question (it was also suggested below by vadian - I did not try his code however). Thank you to everyone who contributed hints and leads!

How to show the price in proper currency in different country with IAP

It means that when people is going to buy something in my game , and I should show them the price of the object first before they click the "buy" button , but in different countries we need use different currency , if the user is in USA , he should see the price is $0.99 , and in another country I should show them their local currency with the price , so how can I do it in code in my project .
I am sorry , but I am new to IOS , so really hope to get your help , thank you so much
Once you get your products from Apple, you can get the price in the local currency from the SKProduct - https://developer.apple.com/library/ios/documentation/StoreKit/Reference/SKProduct_Reference/#//apple_ref/occ/instp/SKProduct/price - that you can then display to the user in your purchase interface.
More details (including a code sample with formatting): http://bendodson.com/weblog/2014/12/10/skproduct-localized-price-in-swift/
Here is an Objective C solution for your needs - you can include Objective C Header into your swift project and use it.
- (NSString *) getLocalizedCurrencyString : (NSNumber *) amount :(NSLocale *)priceLocale
{
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setLocale:priceLocale];
[currencyFormatter setMaximumFractionDigits:2];
[currencyFormatter setMinimumFractionDigits:2];
[currencyFormatter setAlwaysShowsDecimalSeparator:YES];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *localizedCurrency = [currencyFormatter stringFromNumber:amount];
return localizedCurrency;
}
Usage:
let priceLocale: NSLocale = product.priceLocale as NSLocale
let price: NSString = IAPHelper.sharedInstance().getLocalizedCurrencyString(product.price, priceLocale)
where IAPHelper is the Objective C class holding IAP code.

Evernote search with date range

My objective is to display all notes created on date A, date B, date C etc.
I'm building an Evernote Query as such:
//for all notes created on 2015 May 11
ENNoteSearch *searchMayEleven = [ENNoteSearch noteSearchWithSearchString: #"created:20150511 -created:20150512"];
[[ENSession sharedSession] findNotesWithSearch:searchMayEleven
inNotebook:nil
orScope:ENSessionSearchScopeAll
sortOrder:ENSessionSortOrderRecentlyCreated
maxResults:100
completion:^(NSArray *findNotesResults, NSError *findNotesError) {
//completion block
}]];
My results, however, fetch notes that are created on 12 May as well as 11 May.
1) I deduce that I have to set a timezone in my Evernote Session. Based on your experience, is this a valid deduction?
2) If so, I haven't been able to find a way to do so after reading through the documentation. Is it even possible?
3) Would you advice an alternative approach? Perhaps using the notestore instead?
In Evernote your dates are being kept in UTC.
When you make the search you need to create an Evernote search grammar that's relative to the timezone that you're interested in. In your case the timezone of the client or of the iPhone.
To get the user timezone:
ENSession * session = [ENSession sharedSession];
EDAMUser * user = session.user;
where the EDAMUser class has this structure:
#interface EDAMUser : FATObject
#property (nonatomic, strong) NSNumber * id; // EDAMUserID
#property (nonatomic, strong) NSString * username;
...
#property (nonatomic, strong) NSString * timezone;
For example my user timezone is: America/Montreal so on EST.
In order to get all the notes created May 11th you need to construct this Evernote search grammar:
#"created:20150511T040000Z -created:20150512T040000Z"
notice the ...T040000Z at the end.
So the conclusion is that you need to include the "definition" of the date from the client's perspective otherwise the query will work on UTC.
Here is an example of how to build the Evernote grammar search for the current day:
-(NSString *)buildQueryStringForDate: (NSDate *)date {
NSDateFormatter * formatter = [NSDateFormatter new];
[formatter setDateFormat:#"yyyyMMdd'T'HHmmss'Z'"];
formatter.timeZone = [NSTimeZone timeZoneWithName:#"UTC"];
formatter.locale = [NSLocale systemLocale];
DateRange * dateRange = [DateRange rangeForDayContainingDate:[NSDate new]];
return [NSString stringWithFormat:#"created:%# -created:%#", [formatter stringFromDate:dateRange.startDate], [formatter stringFromDate:dateRange.endDate]];
}
The code for [DateRange rangeForDayContainingDate:[NSDate new]] can be found here: How can I generate convenient date ranges based on a given NSDate?
I hope this helps.
It sounds like this might be a time zone issue. The fact that notes from the previous day are being surfaced could be explained by the fact that the search you are performing checks the time as reported by the client (usually the local time zone of the client) and not UTC or any well-defined time zone.
Your existing search grammar: created:20150511 -created:20150512 should return notes created after May 11 and before May 12th utilizing the time and date on the client that was used when the note was created. To force the search to use absolute time for when a note was created and not the created time as reported by the Evernote client you must use the Z postfix to the date-time stamp as seen in the following search grammar which will you return notes created only on May 15, 2015 UTC:
created:20150511T000000Z -created:20150512T000000Z
Sources
https://dev.evernote.com/doc/articles/search_grammar.php
https://dev.evernote.com/doc/reference/Types.html#Struct_Note
Given the time constraint on hand, I am deploying the following solution:
-(NSString *)buildQueryStringForDate: (NSDate *)date {
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
NSDate *dateAfter = [date dateByAddingDays:1];
NSTimeZone *currentTimeZone = [NSTimeZone localTimeZone];
[dateFormat setDateFormat: #"'created:'YYYYMMdd'T'HHmmss"];
[dateFormat setTimeZone:currentTimeZone];
NSString *searchString = [NSString stringWithFormat: #"%# -%#", [dateFormat stringFromDate:[date dateByAddingTimeInterval: currentTimeZone.secondsFromGMT]], [dateFormat stringFromDate:[dateAfter dateByAddingTimeInterval: currentTimeZone.secondsFromGMT]]];
NSLog(#"%#",searchString);
return searchString;
}
In all, it's a hack using NSDate instance method of secondsFromGMT to offset the timezone difference. Does not really use the correct concepts. but it'd have to do for now.
Any comments will be warmly welcomed :)

iOS get locale based description of number

Not sure if this is possible, but for my app I would like to get a locale based string that describes a number.
For example, if I had the number 10,000,000.
In english, I would expect the phrase "Ten Million". However, in Hindi, it would be One crore. Is there any properties in NSNumberFormatter, or NSLocale that could help me with this?
I have checked the docs (NSNumberFormatter, NSLocale), and havent found what I'm looking for yet. Obviously I could write some code to handle these two cases, but I'd like a way that could work for any locale.
Edit: Thanks to leo for the answer! Here is a small snippet of code that will get anyone looking for the same thing started:
NSNumberFormatter formatter = [[NSNumberFormatter alloc] init];
[self.formatter setNumberStyle:NSNumberFormatterSpellOutStyle];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"hi_hi"];
[self.formatter setLocale:locale];
NSNumber * myNumber = [NSNumber numberWithInt:10000];
self.numberLabel.text = [self.formatter stringFromNumber:myNumber];
What you are looking for is the NSNumberFormatterSpellOutStyle style.
NSString* spelledOutString = [NSNumberFormatter localizedStringFromNumber:#10000000 numberStyle:NSNumberFormatterSpellOutStyle];

NSLocale Language Issue

So in my app I am trying to get the devices currently set language and its acronym. So I do this:
NSString *fullLanguage = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[[NSLocale preferredLanguages] objectAtIndex:0]];
NSString *abrlanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
However some users report that the language is returning something like: en_UK or something similar, which in turn is messing up the functionality of my app.
Anyway is there a way to get the currently set language of the device regardless if the devices regional settings?
Thanks!
To get the language code, use:
NSString *languageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
NSLog(#"%#", languageCode); // Prints "en"
To get the full name of the language:
NSString *languageName = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:languageCode];
NSLog(#"%#", languageName); // Prints "English"
Note that you were using the region code (which provides for regional variations of languages), and could be gotten easier like this:
NSString *regionCode = [[NSLocale currentLocale] objectForKey:NSLocaleIdentifier];
NSLog(#"%#", regionCode); // Prints "en_US"
Region codes start with the language code, followed by the underscore, and then the regional variation. (This is standardized per Apple's documentation.)
Also, if you use currentLocale, know that it is not updated as the users preferences are changed. Use autoupdatingCurrentLocale instead if you want to keep it in sync if they change.

Resources