안드로이드 프레임워크·시스템 학습 노트 목차

배포·인앱·국제화 — Play Store·결제·업데이트·다국어

코드를 다 짰다고 끝이 아니다 — 사용자에게 안전하게 전달하고(배포), 수익화하고(인앱 결제), 끊김 없이 갱신하며(인앱 업데이트), 세계 사용자가 자기 언어로 쓰게(국제화) 해야 한다. 이 장은 출시와 운영의 마지막 단계다. (출처: Android — Publish / Play Billing / In-app updates / Localization.)

Play Store 배포 — 왜 단계적으로 내보내나

빌드([11])로 만든 AABPlay Console에 올려 배포한다. 그런데 새 버전을 전 세계 사용자에게 한 번에 푸는 것은 위험하다 — 치명적 버그가 있으면 수백만 명이 동시에 겪는다. 그래서 위험을 점진적으로 줄이는 두 장치가 있다.

다이어그램 로딩 중…
  • 출시 트랙내부(팀)→비공개(알파)→공개(베타)→프로덕션으로 점점 넓은 사용자에게 단계적으로 푼다. 각 단계에서 문제를 걸러 다음으로 넘긴다.
  • 단계적 출시(staged rollout) — 프로덕션도 *한 번에 100%가 아니라 1%→10%→50%→100%*로 늘린다. 1%에서 크래시율이 튀면 롤아웃을 멈추고 피해를 그 1%로 막는다.
  • Play App Signing앱 서명 키를 구글이 안전하게 보관하고, 개발자는 업로드 키만 관리한다. 왜 중요한가? — 서명 키를 잃어버리면 같은 앱으로 업데이트를 영영 못 올린다(사용자는 새 앱으로 재설치해야 한다). 구글이 키를 보관해 이 치명적 키 분실 위험을 없앤다.

인앱 결제 — 왜 서버 검증이 필수인가

수익화는 Google Play Billing으로 인앱 상품(소모성 코인/비소모성 잠금해제)·구독을 판다.

// 흐름(개념): 상품 조회 → 구매 다이얼로그 → 구매 결과 수신 → 서버 검증 → acknowledge → 권한 부여
billingClient.queryProductDetails(...)            // 상품·가격 가져오기
billingClient.launchBillingFlow(activity, ...)    // 구글 구매 다이얼로그
// onPurchasesUpdated 콜백 → 서버에서 영수증 검증 → acknowledge/consume

핵심은 — *구매를 반드시 서버에서 검증하고 acknowledge*해야 한다는 것이다. 왜? 클라이언트는 변조될 수 있어(루팅·해킹된 결제 모듈), "샀다"는 클라이언트 말만 믿으면 가짜 구매로 콘텐츠를 빼앗긴다. 서버가 구글에 영수증을 검증해야 진짜 구매다. 그리고 acknowledge를 안 하면 구글이 며칠 뒤 자동 환불해 버린다. 소모성(코인)은 consume해야 다시 살 수 있고, 구독은 상태를 서버와 동기화한다. 디지털 상품은 Play Billing 사용이 의무다(외부 결제 우회 제한).

인앱 업데이트·리뷰

  • 인앱 업데이트(In-App Updates) — 사용자가 스토어에 안 가도 앱 안에서 업데이트하게 한다. *유연(flexible)*은 백그라운드로 받고 사용자가 적당할 때 적용(일반 업데이트), *즉시(immediate)*는 업데이트할 때까지 화면을 막는다(중대한 보안·호환성 버그). 오래된 버전 사용자를 줄이는 도구다.
  • 인앱 리뷰(In-App Review)앱을 떠나지 않고 그 자리에서 평점·리뷰를 남기게 한다. 단 API가 빈도를 제한하니 과하게 띄우지 않는다(좋은 경험을 한 순간에 자연스럽게).

국제화(i18n)·현지화(l10n)

세계 사용자를 위해 문자열·형식·방향지역에 맞춘다. 출발점은 문자열을 코드에 박지 않는 것이다 — 박으면 번역이 불가능하다.

res/values/strings.xml         (기본·영어)
res/values-ko/strings.xml      (한국어)
res/values-ar/strings.xml      (아랍어 — RTL)
Text(stringResource(R.string.greeting, name))   // 하드코딩 금지 → 리소스로(시스템 언어에 맞춰 자동 선택)
  • 문자열 리소스코드에 하드코딩 금지, strings.xml을 *언어별 폴더(values-ko)*로 둔다. 시스템 언어에 맞춰 자동으로 맞는 폴더가 선택된다.
  • 복수형(plurals) — *"1개 / 3개"*처럼 언어마다 복수 규칙이 다르다(영어는 1/many, 일부 언어는 더 복잡). 직접 if로 처리하지 말고 plurals로 언어별 규칙에 맡긴다.
  • RTL(오른쪽→왼쪽) — 아랍어·히브리어는 글이 오른쪽에서 왼쪽으로 흐른다. 여백·정렬을 left/right 대신 *start/end*로 쓰면 RTL에서 자동으로 좌우가 뒤집힌다.
  • 형식날짜·숫자·통화는 로케일마다 표기가 다르다(1,000.5 vs 1.000,5). 직접 문자열로 조합하지 말고 *NumberFormat·DateTimeFormatter*에 맡긴다.
  • 앱별 언어(Android 13+)시스템 언어와 별개로 이 앱만 다른 언어를 사용자가 고를 수 있다.

정리 — 안전하게 내보내고, 수익화하고, 세계로

출시·운영의 핵심 — AAB를 트랙·단계적 출시로 안전하게 배포(Play App Signing으로 키 분실 위험 제거), 인앱 결제는 서버 검증·acknowledge 필수(클라이언트를 못 믿는다), 인앱 업데이트(유연/즉시)·리뷰로 갱신·피드백, 국제화는 문자열 리소스·plurals·RTL은 start/end·로케일 형식·앱별 언어. 점진 배포와 현지화신뢰받는 글로벌 앱의 마무리다.

한 줄 요약 — 배포: AAB→트랙(내부/알파/베타/프로덕션)·단계적 출시(%로 위험 차단)·Play App Signing(키 분실 방지). 인앱 결제: Play Billing(상품/구독)·서버 검증+acknowledge 필수(클라이언트 못 믿음·미ack는 환불). 인앱 업데이트(유연/즉시)·리뷰(빈도 제한). i18n: strings.xml 언어별·하드코딩 금지·plurals·RTL은 start/end·로케일 형식(NumberFormat)·앱별 언어(13+).

(출처: Android — Publishing overview / Play Billing / In-app updates / Localize your app / Per-app language / Play Console.)

위치·센서 — FusedLocation·SensorManager·권한