nika-blog

global service - in app purchase(iap) currency issue, react-native 본문

React Native

global service - in app purchase(iap) currency issue, react-native

nika0 2025. 1. 11. 21:57

*react-native 기준으로 작성한 코드입니다. 

 

나는 글로벌 서비스를 담당하는 개발자이다. 

글로벌 서비스를 개발하면서 마주할 수 있는 문제는 여러가지가 있으나 오늘은 그 중 currency 이슈에 대해 말해보려고 한다. 

 

각 나라 사람들은 다양한 통화를 사용한다. 

한국은 원화를, 일본은 엔화를, 미국은 USD를, 유럽은 유로를, 영국은 파운드를 사용한다. 

그 밖에 다양한 통화는 모두 QA 하기 벅찰 정도이다. 

 

그렇다면 다양한 통화에 대해 어떻게 대응해야 할까?

먼저 현재 유저가 어떤 통화를 사용하고 있는지에 대한 정보가 필요하다. 

회원가입 때 요청할 수도 있고, 결제할 때 확인할 수도 있을 것이다. 

오늘은 in app purchase(약어: iap)를 사용한 케이스에 대해 말해보려고 한다. 

 

in app purchase 는 ios, android app store 에 설정된 통화 기준으로 결제할 수 있는 서비스이다. 

자세한 것은 각 개발자 문서에서 활용하면 될 것이고..

 

in app purchase 로 결제 서비스를 제공하고 있는 회사라면, app 진입 후 iap 서버에 현재 제공하고 있는 product 정보를 불러오게 된다. iap 서버에서는 사용자의 currency 에 맞는 product 정보가 내려오는데 localizedPrice 는 string 형식으로 '9.99$' 와 같이 내려온다. 그렇다면 '9.99$' 는 3달동안 이용할 수 있는 price 이고 해당 가격의 unit price 를 구해야 하는 상황이라고 가정해보자. 

 

iap product 에서 제공한 number type 의 price 에서 이용가능한 기간인 (period) 로 나누면 될 것이다. 대략 아래와 같은 형식으로 계산할 수 있다.

 

const price = 9.99; //iap 서버 제공
const period = 3; //서버 제공
const result = Math.round(price/period); // 3.33

 

사용자한테는 다시 localized 된 금액, $3.33 으로 노출해야 한다고 가정하자(대부분의 경우에 그럴 것이다)

그렇다면 currency 정보를 이용해서 3,000₩, $3.33 등으로 가공해주는 formatPrice 과정을 거쳐야 할 것이다. 

 

react-natvie 에서는 아래와 같이 핸들링 가능하다. 

 

type FormatPriceItem = {
  currency: string,
  locale?: string,
};

export const formatPrice = (
  item: FormatPriceItem,
  price: number,
) => {
  if (Platform.OS === 'ios') {
    try {
      return formatPriceIos(item.locale, price);
    } catch (error) {
      reportError({
        data: {
          error,
          item,
          price,
        },
        level: 'debug',
        title: 'iOS formatPrice Failed',
      });
    }
  }
  return formatPriceIntl(getLocales()[0].languageTag, item.currency, price);
};

export const formatPriceIos = (
  locale: string | undefined,
  price: number,
) => {
  const result = NativeModules.LocalizationManager.formatPrice(price, locale);

  if (result) {
    return result;
  } else {
    throw Error('iOS formatPrice Failed');
  }
};

export const formatPriceIntl = (
  locale: string,
  currency: string,
  price: number,
) => {
  return new Intl.NumberFormat(locale, { currency: currency, style: 'currency' }).format(
    price,
  );
};

 

각 인자를 어떻게 구성할 수 있는지는 다음에 적도록 해야겠다..

어쨌든 오늘 말하고 싶은 이슈는 iap 준 데이터를 ui 노출을 위해서 local price, original price (할인률 적용 전 등)을 구해야 한다면 어떻게 localized 할지 고민해야 한다는 것이다. 

또한 서버에서는 현재 유저의 통화를 알 수 있고 client 에서 전달한다고 해도 모든 통화에 대해서 계산할 수 없기 때문에 client 에 일부 계산 로직 및 데이터 가공 로직이 필요하다는 것이다. (모든 데이터를 서버에 전달하고 서버에서 하는 방법도 있겠지만)