Google Play Developer API로 Play 스토어 리스팅 업데이트하기
edits.insert), 그 안에서 리스팅 텍스트와 이미지를 변경한 다음(edits.listings.update, edits.images.upload), edits.commit으로 검증 후 게시하거나 edits.abandon으로 폐기해요. commit 전까지는 아무것도 실제로 반영되지 않아요. 인증은 Google Cloud 서비스 계정을 사용하고, 거의 모두가 걸려 넘어지는 한 가지 단계는 서비스 계정을 Google Cloud IAM에서 역할만 주는 게 아니라 Play Console에도 초대해야 한다는 점이에요.Google Play Developer API(정식 명칭은 Android Publisher API)를 사용하면 Play Console을 열지 않고도 스토어 리스팅 — 제목, 설명, 스크린샷, 피처 그래픽 —을 변경할 수 있어요. CMS에서 현지화된 문구를 밀어 넣거나, 빌드 파이프라인에서 스크린샷을 동기화하거나, 수십 개 언어 리스팅을 한 번에 업데이트하려는 경우 딱 맞는 방법이에요. 아래는 이 작업을 제대로 처리하는 전체 흐름이고, 공식 문서가 깊숙이 숨겨둔 부분까지 포함하고 있어요.
edit은 트랜잭션이지, 실시간 반영이 아니에요
가장 많은 삽질을 줄여주는 핵심 개념은 이거예요. 실제 서비스 중인 리스팅을 직접 편집하는 일은 없어요. 앱의 현재 배포 상태 — 리스팅, 이미지, 트랙, 전부 —를 그대로 복사한 비공개 스테이징 사본인 edit을 여는 거예요. 모든 변경은 이 사본에 대해 이뤄지고요. 그런 다음 한꺼번에 commit하거나, abandon하면 아무 일도 일어나지 않은 것이 돼요.
Google의 표현은 직설적이에요. "edit 안에서 이뤄진 변경 사항은 edit이 commit되기 전까지 실제로 반영되지 않는다." commit 시 검증 오류가 없으면 edit 안의 모든 변경 사항이 한꺼번에 반영되어 현재 상태를 교체해요. 검증에 실패하면 API가 오류를 던지고 실제 리스팅은 그대로 유지돼요. 그러니까 생애주기는 정확히 네 단계예요.
edits.insert— edit을 생성하고editId를 받아요.- 수정 — 언어별 텍스트는
edits.listings.update, 스크린샷과 그래픽은edits.images.upload/deleteall. edits.commit— 모든 것을 검증한 후 원자적으로 전부 게시해요.edits.abandon— 초안을 버려요, 실제 리스팅은 변경되지 않아요.
설계할 때 반드시 지켜야 할 제약 하나. 한 계정은 동시에 하나의 edit만 열 수 있고, 누군가가 edit을 commit하거나 Play Console UI로 앱을 직접 수정하면 그 앱에 대한 다른 모든 열려 있는 edit은 무효화돼요. edit은 오래 붙잡고 있지 마세요 — 열고, 작성하고, commit하세요. 사람이 콘솔을 여기저기 클릭하는 동안 몇 시간씩 열어두지 마세요.
인증: 서비스 계정, 그리고 다들 잊어버리는 초대 단계
자동화된 업데이터에는 사용자 OAuth가 아니라 서비스 계정이 필요해요. 여기엔 서로 완전히 별개인 두 시스템이 관여해요.
- Google Cloud. 서비스 계정을 만들고, 프로젝트에서 Google Play Android Developer API를 활성화한 후 JSON 키를 다운로드하세요. 필요한 스코프는
https://www.googleapis.com/auth/androidpublisher하나뿐이에요. - Play Console. 사용자 및 권한으로 이동해서 새 사용자 초대를 클릭하고, 서비스 계정의 이메일(
...@...iam.gserviceaccount.com주소)을 붙여넣은 다음 해당 앱에 대한 접근 권한을 부여하세요. 그래야만 그 키로 리스팅을 건드릴 수 있어요.
전제 조건이 하나 더 있어요. 앱이 이미 존재하고 적어도 한 번의 릴리스(콘솔을 통해 업로드된 APK/AAB가 최소 하나)가 있어야 해요. 완전히 새로운 앱을 API만으로 처음부터 만들 수는 없어요.
네 가지 호출, REST로 보기
리스팅 텍스트 업데이트하기
edits.listings.update는 PUT — 해당 언어 리스팅의 전체 교체예요. 보낸 내용이 그대로 리스팅이 되고, 빠뜨린 필드는 유지되는 게 아니라 지워져요. 짧은 설명만 바꾸고 싶어도 제목과 전체 설명까지 함께 보내야 해요. 안 그러면 지워지니까요. 진짜로 부분 변경이 필요하다면 보낸 필드만 병합하는 별도의 edits.listings.patch가 있어요. 대부분의 파이프라인에는 전체 PUT이 더 깔끔해요. 어차피 소스 오브 트루스에서 완전한 리스팅을 렌더링하는 거니까, 통째로 교체하는 게 딱 맞는 방식이에요.
세 가지 텍스트 필드와 글자 수 제한: title은 최대 30자, shortDescription은 최대 80자, fullDescription은 최대 4000자예요. 언어당 하나의 리스팅 리소스가 있고, URL에 BCP-47 언어 태그(en-US, de-DE, ja-JP 등)로 구분돼요. 열 개 언어를 업데이트하려면 같은 edit 안에서 listings.update 호출을 열 번 하고, 그런 다음 commit 한 번으로 전부 함께 게시돼요.
스크린샷과 피처 그래픽 업로드하기
이미지는 언어별, 이미지 타입별로 첨부돼요. 이미지 타입은 열거형이고, 리스팅의 각 에셋 슬롯은 다음 값 중 하나에 대응돼요.
phoneScreenshots,sevenInchScreenshots,tenInchScreenshots— 폰과 태블릿 스크린샷 세트.tvScreenshots,wearScreenshots— Android TV와 Wear OS.featureGraphic— 리스팅 상단에 표시되는 1024×500 배너.icon,tvBanner— 앱 아이콘과 TV 배너.
edits.images.upload는 특정 언어와 타입의 이미지 하나를 edit에 추가해요. "배열 전체를 설정하는" 호출은 없기 때문에, 스크린샷을 교체하는 안정적인 방법은 먼저 해당 언어와 이미지 타입에 대해 edits.images.deleteall을 호출한 다음 원하는 순서대로 새 세트를 업로드하는 거예요. edits.images.list는 현재 edit 안에 있는 내용을 읽고, edits.images.delete는 정밀한 수정이 필요할 때 id로 이미지 하나를 삭제해요. commit하기 전까지는 전부 edit 안에 머물러요.
Commit — 그리고 "실제 반영"이 정확히 뜻하는 것
사람들이 놀라는 지점이라 정확히 짚어둘 만한 것들이 있어요.
- 새 빌드가 필요 없어요. 리스팅만 변경하는 edit을 commit할 때는 새 APK/AAB가 필요하지 않아요. 텍스트와 이미지는 메타데이터라서 기존 릴리스에 대해 몇 번이든 업데이트할 수 있어요. (앱에 이전 릴리스가 하나 존재하기만 하면 돼요.)
- Commit은 먼저 검증한 다음 게시해요. 스크린샷 크기가 잘못됐거나 필드가 너무 길면 commit이 실패하고 실제 리스팅은 절대 바뀌지 않아요. 수정 후 다시 commit하면 돼요.
- 즉시 반영되지 않아요. commit이 성공한 후에도 변경 사항이 화면에 나타나기까지 최대 몇 시간이 걸릴 수 있어요. Play Console에서 직접 수정할 때와 마찬가지예요. commit이 200을 반환했다고 해서 "이미 사용자에게 보인다"고 여기면 안 돼요.
- Abandon은 부담이 없어요. 시험 삼아 해봤는데 뭔가 이상하면
edits.abandon은 실제 리스팅에 아무런 영향 없이 초안을 폐기해요. 위험 없이 파이프라인을 검증할 때 유용해요.
코드 없는 경로: 디자인, 번역, 게시
위에서 소개한 API는 투입할 엔지니어링 시간이 있고 동기화할 소스 오브 트루스가 있을 때 적합한 도구예요. 하지만 에셋을 만들어주지는 않아요. 스크린샷을 디자인하고, 제목과 두 가지 설명을 작성하고, 이 모든 것을 언어별로 준비하는 건 여전히 직접 해야 해요. API는 넘겨준 것만 그대로 배포할 뿐이에요.
그 부분을 Mokbi가 해결해줘요. 브라우저에서 스크린샷을 디자인하고, 제목·짧은 설명·전체 설명을 함께 작성한 다음, 전체 리스팅을 한 번에 50개 언어로 번역해요. 그러면 위에서 말한 열 번의 listings.update 호출에 자리 표시자 텍스트가 아니라 실제로 현지화된 문구를 담아 보낼 수 있어요.
그럼 게시 자체는요? 그것도 Mokbi가 처리해요. Google Play의 경우 내부적으로 정확히 이 흐름(edits.insert → listings.update → 이미지 업로드 → commit)을 그대로 실행해서, 위 코드를 한 줄도 작성하지 않아도 현지화된 리스팅과 에셋이 실제로 반영돼요. App Store의 경우에는 App Store Connect 안에 버전을 채워 넣어 제출 준비 상태로 만들어 둬요. Apple은 최종 Submit을 사람이 직접 누르고 심사를 통과해야 하기 때문이에요. 스크린샷과 피처 그래픽을 디자인하고, 리스팅을 작성하고, 50개 언어로 번역하고, 실제로 게시하는 과정이 하나의 연속된 흐름이에요.