Search code examples
iosunity-game-enginein-app-purchase

How to get IOS app store country in Unity


Good time of the day

I am using Unity IAP version 2.2.2

I wanted to get IOS app store's country.

Here I see in Apple docs that product contains priceLocale to get locale. But in unity iap, product doesn't contains this field in product's information.

com.example.puzzles.annual: {"introductoryPrice":"0","introductoryPriceLocale":"USD","introductoryPriceNumberOfPeriods":"1","numberOfUnits":"1","unit":"1"}

How can I get iOS app store's country? P.S. IP location or getting country from isoCurrencyCode are not an option for me


Solution

  • To those who wants to get App store country on IOS.

    Create a c# class MyNativeBindings.cs

    public class MyNativeBindings
    {
        [DllImport("__Internal")]
        public static extern void LoadLocationInfo(string productId);
        [DllImport("__Internal")]
        public static extern string GetLocationCode();
    }
    

    Create ios native objective-c class MyNativeBindings.mm and move to Asset/Plugins/ios folder

    #import <StoreKit/StoreKit.h>
    #include <string>
    
    @class ProductRequestResponseDelegate;
    @interface ProductRequestResponseDelegate : NSObject  <SKProductsRequestDelegate>;
    @property (nonatomic) std::function<void(const std::string  &type, const std::string &country_code)> callback;
    
    -(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response;
    
    @end
    
    static ProductRequestResponseDelegate * g_delegate = nil;
    
    extern "C" {
    
        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
        // Helper method to create C string copy
        char* MakeStringCopy (NSString* nsstring)
        {
            if (nsstring == NULL) {
                return NULL;
            }
            // convert from NSString to char with utf8 encoding
            const char* string = [nsstring cStringUsingEncoding:NSUTF8StringEncoding];
            if (string == NULL) {
                return NULL;
            }
    
            // create char copy with malloc and strcpy
            char* res = (char*)malloc(strlen(string) + 1);
            strcpy(res, string);
            return res;
        }
    
        void LoadLocationInfo(const char* productId) {
            g_delegate = [[ProductRequestResponseDelegate alloc] init];
            g_delegate.callback = [](const std::string & type, const std::string & code) {
    //            NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
                [userDefaults registerDefaults:@{@"loc_type": [NSString stringWithUTF8String:type.c_str()]}];
                [userDefaults registerDefaults:@{@"loc_code": [NSString stringWithUTF8String:code.c_str()]}];
                NSLog(@"%@",[userDefaults objectForKey:@"loc_type"]);
                NSLog(@"%@",[userDefaults objectForKey:@"loc_code"]);
            };
            
            auto set = [[NSSet alloc] initWithObjects: [NSString stringWithUTF8String: productId], nil];
            
            auto request = [[SKProductsRequest alloc] initWithProductIdentifiers: set];
            request.delegate = g_delegate;
            [request start];
        }
    
        char* GetLocationType()
        {
            NSString *s = [userDefaults objectForKey:@"loc_type"];
            return MakeStringCopy(s);
        }
    
        char* GetLocationCode()
        {
            NSString *s = [userDefaults objectForKey:@"loc_code"];
            return MakeStringCopy(s);
        }
    }
    
    
    
    @implementation ProductRequestResponseDelegate
    
    -(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (!self.callback)
                return;
            
            auto products = [response products];
            
            if ([products count] == 0)
            {
                self.callback("", "");
                return;
            }
            
            auto product = [products firstObject];
            if (![product respondsToSelector: @selector(priceLocale)])
            {
                self.callback("", "");
                return;
            }
            
            auto locale = [product priceLocale];
            if ([locale respondsToSelector: @selector(countryCode)])
                self.callback("code", [[locale countryCode] UTF8String]);
            else
                self.callback("identifier", [[locale localeIdentifier] UTF8String]);
        });
    }
    
    
    
    @end
    
    1. You should call MyNativeBindings.LoadLocationInfo(productID) when IAP initialized.
    2. Then call MyNativeBindings.GetLocationCode() to get store country short code.