내 앱에 통합하기
Google Play 구독
자체 백엔드 없이 Google Play로 구독을 판매하는 Android 앱을 위한 기능입니다. 앱이 API 키와 함께 구매 토큰을 게이트웨이로 보내면, 게이트웨이가 서비스 계정으로 Google에 문의해 구독이 활성 상태인지 알려 줍니다. 확인은 무료입니다.
#시작하기 전에
- 사용자를 초대할 수 있도록 계정 소유자 또는 관리자인 Play Console 로그인 계정.
- Google Cloud 콘솔에서 프로젝트를 만들 수 있는 Google 계정(모든 Google 계정이 가능).
- 앱의 패키지 이름(applicationId, 예: com.example.app)과 Play Console에서 만든 구독 상품 하나 이상.
- 약 15분간의 설정 작업, 그리고 Google이 권한을 적용하기까지 최대 하루.
#1. 서비스 계정 JSON 받기
이 JSON 파일이 서비스 계정의 키입니다. 게이트웨이는 이 키로 Google에 내 앱의 구매 정보만 조회하며, 다른 용도로는 쓰지 않습니다. Google에서는 이를 서비스 계정 키라고 부르며, OAuth 클라이언트 파일(client_secret_….json)이 아닙니다.
- 1
Google Cloud 콘솔을 열고 프로젝트 선택
console.cloud.google.com상단의 프로젝트 선택기를 사용하세요. 어떤 프로젝트든 괜찮지만, Play 확인 전용으로 새로 만들면 관리가 깔끔합니다.
- 2
Play API 사용 설정
API 및 서비스(APIs & Services) → 라이브러리(Library) → Google Play Android Developer API → 사용(Enable)이름을 정확히 검색하세요. 버튼이 관리(Manage)로 표시되면 이미 사용 설정된 것입니다.
- 3
서비스 계정 만들기
IAM 및 관리자(IAM & Admin) → 서비스 계정(Service accounts) → 서비스 계정 만들기(Create service account)play-verify처럼 아무 이름이나 지정하세요. 프로젝트 역할이나 사용자 액세스를 부여하는 선택 단계는 건너뛰세요. Cloud 역할은 필요 없습니다. 완료(Done)를 클릭하세요.
- 4
JSON 키 다운로드
서비스 계정 열기 → 키(Keys) → 키 추가(Add key) → 새 키 만들기(Create new key) → JSON → 만들기(Create)브라우저가 .json 파일을 다운로드합니다. 안전하게 보관하세요. Google은 이 파일을 다시 보여 주지 않으며, 파일을 가진 사람은 누구나 앱의 구매 정보를 읽을 수 있습니다.
- 5
서비스 계정 이메일 복사
play-verify@your-project.iam.gserviceaccount.com 형태이며, 서비스 계정 페이지와 파일 안의 client_email에서 확인할 수 있습니다. 다음 단계에서 필요합니다.
새 키 만들기가 비활성화되어 있거나 거부되나요?
#2. Play Console에서 액세스 권한 부여
- 1
서비스 계정 초대
play.google.com/console → 사용자 및 권한(Users and permissions) → 새 사용자 초대(Invite new users)이메일 주소에 서비스 계정 이메일을 붙여 넣으세요. 서비스 계정은 초대를 수락할 필요가 없습니다.
- 2
다음 두 권한 부여
앱 권한(App permissions) → 앱 추가(Add app) → 내 앱 선택재무 데이터, 주문, 취소 설문조사 응답 보기(View financial data, orders, and cancellation survey responses)와 주문 및 구독 관리(Manage orders and subscriptions)를 선택하세요. 나머지는 모두 선택하지 마세요. 대신 계정 권한(Account permissions)에서 같은 두 항목을 선택하면 모든 앱에 적용됩니다.
- 3
초대 보내기
적용(Apply) → 사용자 초대(Invite user)이제 사용자 및 권한에 서비스 계정이 활성(Active) 상태로 표시됩니다.
이 권한이 필요한 이유
Google이 권한을 적용하는 데 최대 하루 소요
#3. API 키에 설정하기
- 1
앱이 사용하는 키 열기
콘솔 → API 키 → 편집앱 전용 키를 사용하세요(아래 참고).
- 2
Google Play 구독 확인 입력
Google Play 확인 설정앱 build.gradle의 applicationId와 정확히 같은 패키지 이름을 입력하고, 1단계의 JSON 파일을 선택한 뒤 저장하세요.
- 3
저장 결과 메시지 확인
게이트웨이는 파일을 저장하기 전에 Google에 시험 조회를 합니다. Google이 여전히 거부하면 대화상자에 무엇이 빠졌는지 표시되며, 보통 1단계의 API나 2단계의 권한입니다. 파일은 암호화되어 저장되고 다시 표시되지 않습니다. 바꾸려면 다시 업로드하세요.
앱 전용 키 사용
#4. 앱에서 확인하기
구매 직후에 확인하고, 앱을 열 때 저장해 둔 토큰으로 다시 확인하세요. 응답을 기다리느라 앱 시작을 막지 마세요. 마지막으로 저장한 결과를 먼저 보여 주고 확인 결과가 오면 업데이트하세요. 같은 토큰은 1분 캐시에서 응답합니다. 각 키는 기본적으로 분당 120회까지 확인할 수 있으며, 현재 한도는 키의 Google Play 설정에 표시되고 지원팀이 키별로 올릴 수 있습니다. 한도를 넘은 호출은 429를 반환하고 기록되지 않으므로, 마지막으로 저장한 응답을 유지하세요.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:in_app_purchase/in_app_purchase.dart';
const apiKey = 'sk-YOUR_KEY';
Future<Map<String, dynamic>?> checkSubscription(String purchaseToken) async {
final res = await http.post(
Uri.parse('https://www.aisplice.store/v1/google-play/verify'),
headers: {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/json',
// Request signing on for this key? Then this call must be signed too:
// ...signedHeaders('POST', '/v1/google-play/verify'),
},
body: jsonEncode({'purchase_token': purchaseToken}),
);
if (res.statusCode != 200) return null; // keep the last saved answer
return jsonDecode(res.body) as Map<String, dynamic>;
}
// In your purchaseStream listener:
Future<void> onPurchase(PurchaseDetails purchase) async {
if (purchase.status != PurchaseStatus.purchased &&
purchase.status != PurchaseStatus.restored) return;
final token = purchase.verificationData.serverVerificationData;
final status = await checkSubscription(token);
if (status != null && status['active'] == true) {
await saveEntitlement(token, status); // your local storage
unlockPaidFeatures();
}
if (purchase.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(purchase); // acknowledges on Android
}
}#5. 잠금 해제 기준 정하기
| 확인 결과 | 앱의 동작 | 일반적인 원인 |
|---|---|---|
| active: true, in_trial: true | 잠금 해제. expiry_time으로 “체험 종료” 시각을 표시합니다. | 무료 체험 |
| active: true | expiry_time까지 잠금 해제. | 결제 완료(아직 만료되지 않은 취소된 구독 포함) |
| subscribed: true, active: false | 잠그고 갱신 화면을 표시합니다. | 만료, 일시중지, 보류 |
| subscribed: false | 잠그고 구독 화면을 표시합니다. | 알 수 없는 토큰, 결제 대기 중 |
| HTTP 502 / 503 | 마지막으로 저장한 응답을 유지하고 나중에 다시 시도합니다. | Google 또는 서비스 계정이 응답하지 않음 |
응답과 함께 expiry_time을 저장하세요. 확인과 확인 사이에는 그 시각까지 구독을 사용 가능한 것으로 처리하면, 휴대폰이 오프라인이어도 계속 동작합니다.
#6. 모든 구매 확인 처리하기
확인되지 않은 구매는 3일 후 환불됨
#7. 앱 안의 키 보호하기
앱 안의 키는 캡처한 트래픽에서 읽어 낼 수 있습니다. 해당 키에 요청 서명을 켜서 복사된 키만으로는 쓸 수 없게 하고, 빌드를 난독화하며, 키에 한도 상한을 두세요.
서명은 해당 키의 모든 호출에 적용됨
#8. 처리 기록 확인하기
캐시된 응답과 실패를 포함한 모든 확인은 콘솔 → 요청 로그에 해당 키의 무료 “Google Play 확인”으로 표시됩니다. 전체 구매 토큰, 토큰 끝자리, 또는 사용자가 Google 영수증 이메일에서 보내 준 주문 ID(GPA.…)로 검색하세요.
- google_play_api_disabled: JSON 파일이 속한 프로젝트에서 1단계의 Play API가 사용 설정되지 않았습니다.
- google_play_permission_denied: 2단계의 초대가 없거나, 두 권한이 빠졌거나, 다른 앱에 대한 것이거나, 아직 활성화되지 않았습니다.
- google_play_credentials_invalid: Google Cloud에서 JSON 키가 삭제되었거나 사용 중지되었습니다. 새 키를 만들어 API 키에 업로드하세요.
- 저장 시 서비스 계정 키가 아니라고 나오면: OAuth 클라이언트 파일을 선택한 것입니다. 서비스 계정의 키(Keys) 탭에서 키를 다운로드하세요.
- 모든 확인에서 구매를 찾을 수 없다고 나오면: 키에 설정한 패키지 이름이 앱의 applicationId와 다르거나, 토큰이 다른 앱의 것입니다.
- 라이선스 테스터의 테스트 구매는 test_purchase: true를 반환합니다.
아직 해결되지 않았나요?
요청 ID나 오류 메시지를 보내 주시면 확인해 드리겠습니다.