【iOS】StoreKit2的currencyCode獲取方案

StoreKit2的currencyCode獲取問題

我們在內購的時候,需要將countryCode、currencyCode、price這幾個參數(shù)讀取后發(fā)給后臺,用于貨幣校驗、價格校驗及統(tǒng)計。
StoreKit2有個坑爹的地方,就是在21年出來的時候,蘋果沒有提供currencyCode的API。

新的API可以直接獲取currencyCode

22年的時候終于出了一個API,可以通過下面的方式讀取countryCode

let products = try await Product.products(for: [productId])
let currencyCode = products.last?.priceFormatStyle.currencyCode

但是,這個新出的API并不能在Xcode13上編譯通過,只能在Xcode14及以上版本編譯通過。而目前開發(fā)使用的是Xcode13。
并且,蘋果提示這個API如果在iOS16之前使用(就是iOS15)在某些情況下可能出現(xiàn)一些問題(主要是StoreKit Testing和出現(xiàn)嚴重的服務器錯誤時)。

Product {

    /// The format style to use when formatting numbers derived from the price for the product.
    ///
    /// Use `displayPrice` when possible. Use `priceFormatStyle` only for localizing numbers
    /// derived from the `price` property, such as "2 products for $(`price * 2`)".
    /// - Important: When using `priceFormatStyle` on systems earlier than iOS 16.0,
    ///              macOS 13.0, tvOS 16.0 or watchOS 9.0, the property may return a format style
    ///              with a sentinel locale with identifier "xx\_XX" in some uncommon cases:
    ///              (1) StoreKit Testing in Xcode (workaround: test your app on a device running a
    ///              more recent OS) or (2) a critical server error.
    @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
    public var priceFormatStyle: Decimal.FormatStyle.Currency { get }

總的來說,因為目前開發(fā)的Xcode版本較低導致的編譯無法通過,所以我們需要嘗試尋找另外的方法來獲取currencyCode。

從Product的jsonRepresentation里面獲取currencyCode

其實蘋果本身是可以拿到currencyCode的,因為獲取商品信息成功之后,我們直接打印可以看到一個json,里面有我們需要的currencyCode。

let products = try await Product.products(for: [productId])
print("product=\(products.last!)")

以下為打印出來的內容(已脫敏處理):

product={
  "attributes" : {
    "description" : {
      "standard" : "????,800?? ??"
    },
    "icuLocale" : "en_TW@currency=TWD",
    "isFamilyShareable" : 0,
    "isMerchandisedEnabled" : 0,
    "isMerchandisedVisibleByDefault" : 0,
    "isSubscription" : 0,
    "kind" : "Consumable",
    "name" : "800??",
    "offerName" : "kr.app.gold1",
    "offers" : [
      {
        "assets" : [

        ],
        "buyParams" : "productType=A&price=330000&salableAdamId=1531111111&pricingParameters=STDQ&pg=default",
        "currencyCode" : "TWD",
        "price" : 330,
        "priceFormatted" : "NT$330.00",
        "type" : "buy"
      }
    ],
    "releaseDate" : "2009-06-17",
    "url" : "https://sandbox.itunes.apple.com/tw/app/800%EC%9B%90%EB%B3%B4/id1531111111?l=en"
  },
  "href" : "/v1/catalog/tw/in-apps/153111111?l=en-GB",
  "id" : "153111111",
  "type" : "in-apps"
}

可以看到1. icuLocale的值里面有currency相關內容,2. offers數(shù)組里面也有一個currencyCode參數(shù)。
那么,我們拿到這個json之后,再去讀取里面相關的內容,不就可以獲取到我們想要的currencyCode了?
這個json其實在product的jsonRepresentation屬性里面,我們轉化一下就可以拿到。
于是,我們通過下面的代碼可以拿到我們想要的currencyCode

let products = try await Product.products(for: [productId])
let product = products.last

// data->JSON->Dictionry
let decoded = try? JSONSerialization.jsonObject(with: product!.jsonRepresentation, options: [])
let jsonDict = decoded as? [String: Any] ?? [:]

let attributes = jsonDict["attributes"] as? [String: Any]
let offers = attributes?["offers"] as? [[String: Any]]

// 直接獲取currencyCode(目前采用了這種方案)
let currencyCode = offers?.first?["currencyCode"] as? String
print("currencyCode=\(currencyCode)")

// 獲取icuLocale字符串,然后截取字符串拿到currencyCode(略,目前未采用這種方案)
let icuLocale = attributes?["icuLocale"]
print("icuLocale=\(icuLocale)")

目前我們就是使用這種方案來獲取currencyCode的。目前已上線,并沒有出現(xiàn)什么問題,后續(xù)會繼續(xù)進行觀察。
但是這種方案畢竟不是官方提供的,里面的JSON格式可能會出現(xiàn)改變,所以,這種方案其實是有風險的。但是,以目前的情況來說,不失為一種好方案。

使用Storekit1來獲取currencyCode

StoreKit2獲取不到,但是StoreKit1肯定是可以拿到的,所以,有些人會使用StoreKit1來獲取currencyCode。
這種不失為一個好方案,但是這個API需要走一個網(wǎng)絡請求,相對較為耗時。

//獲取商品信息
NSSet *pidSets = [NSSet setWithObject:productId];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:pidSets];
request.delegate = self;
[request start];

#pragma mark - 獲取商品信息成功后回調
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    SKProduct *product = [response.products lastObject];
    NSLocale *priceLocale = product.priceLocale;
    //獲取本地貨幣簡碼
    NSString *currencyCode = nil;
    if (@available(iOS 10.0,*)) {
        currencyCode = priceLocale.currencyCode;
    } else {
        currencyCode = [[priceLocale.localeIdentifier componentsSeparatedByString:@"="] lastObject];
    }
    NSLog(@"currencyCode=%@",currencyCode);
}

總結

總的來說,StoreKit2獲取貨幣碼currencyCode的方案有3個:

1.使用priceFormatStyle.currencyCode進行獲取。官方API,但是需要Xcode14才能編譯通過。在2023.4之后推薦使用(那時候最低使用Xcode14)。
2.使用product的jsonRepresentation屬性,通過解析json的方式獲取。適配Xcode13和iOS15,如果未更新Xcode到14及以上,是較好的方案。缺點是非官方推薦方式,后續(xù)json里面的內容可能會有改動導致出錯。
3.使用StoreKit1的API獲取。好處是方案比較成熟,缺點是較為耗時,而且在StoreKit2里面使用,不太和諧。

推薦方案:
使用Xcode14的開發(fā)建議直接使用方案一。
目前不少開發(fā)仍在使用Xcode13,所以使用Xcode13的開發(fā)建議使用方案二。
另外可以嘗試iOS15使用方案二,iOS16及以上使用方案一(對于這樣做是否更好,未驗證過)。

參考鏈接

Missing currencyCode in StoreKit2
purchases-ios庫--github

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容