앱이 Google Play를 통해 배포되며 디지털 상품을 판매하거나 상품을 제공하려는 경우 Google Play 결제를 사용해야 합니다. Google Play 결제는 관리 및 Google Play에서 제공하는 카탈로그, 가격 및 정기 결제, 유용한 보고서, 결제 절차 사용자에게 이미 익숙한 스토어입니다.
신뢰할 수 있는 웹 활동을 사용하여 빌드하고 Google Play 스토어를 통해 제공되는 앱의 경우 이제 Payment Request API 및 Digital Goods API를 사용하여 Google Play 결제 Android 및 ChromeOS의 Chrome 101 이상에서 사용할 수 있습니다.
이 가이드에서는 PWA에 Google Play 결제 지원을 추가하고 Google Play 스토어에서 ChromeOS와 Play 스토어 모두에 배포됩니다.
두 가지 웹 플랫폼 API를 사용하여 PWA에 Play 결제 지원을 추가합니다. 이 Digital Goods API는 SKU 정보를 수집하고 구매 및 사용 권한을 확인하는 데 사용됩니다. 앱을 다운로드할 수 있습니다. Payment Request API는 Google Play 스토어를 구매 흐름을 완료할 수 있습니다.
Play 스토어에서 애플리케이션으로 수익을 창출하는 방법
애플리케이션이 Play 스토어에서 Google Play 결제를 사용해 수익을 창출할 수 있는 방법에는 두 가지가 있습니다.
- 인앱 구매를 통해 내구재 및 소모성 가상 상품을 모두 판매할 수 있습니다(예: 추가 상품). 기능을 사용하거나 광고를 삭제하는 등의 작업을 수행할 수 있습니다
- 정기 결제: 사용자가 요금을 반복적으로 지불하면 콘텐츠나 서비스에 지속적으로 액세스할 수 있도록 합니다. 뉴스 구독이나 멤버십 등입니다
요구사항
Google Play 결제를 설정하려면 다음이 필요합니다.
- 다음 조건을 충족하는 Google Play 개발자 계정 및 Google Payment 판매자 계정이 있어야 합니다. 서로 연결됨
- Play 스토어 등록정보와 공개, 비공개 테스트 또는 내부 테스트 트랙에 출시할 수 있습니다.
- Play 스토어에서 앱의 제품 및 정기 결제를 만들고 구성하기 위해
- 디지털 애셋 링크 구성이 작동하는 Bubblewrap 생성 프로젝트
Bubblewrap 프로젝트 업데이트
Bubblewrap이 설치되어 있지 않다면 설치해야 합니다. 자세한 내용은 시작하는 방법에 대한 자세한 내용은 빠른 시작 가이드를 참조하세요. 이미 버블랩이 있다면 버전 1.8.2 이상으로 업데이트해야 합니다.
Bubblewrap에는 플래그 뒤에 있는 기능도 있습니다. 포함
사용 설정하려면 twa-manifest.json
에서 프로젝트 구성을 수정해야 합니다.
프로젝트의 루트에 있고 alphaDependencies
및 playBilling
를 모두 사용 설정합니다.
기능:
...,
"enableNotifications": true,
"features": {
"playBilling": {
"enabled": true
}
},
"alphaDependencies": {
"enabled": true
},
...
구성 파일이 업데이트된 상태에서 bubblewrap update
를 실행하여
새 Android 패키지를 생성하고 이를 업로드하기 위해 bubblewrap build
를 추가하여 새 Android 패키지를 업로드합니다.
Play 스토어에 보냅니다.
Digital Goods API 및 Google Play 결제 사용 가능 여부를 감지하는 기능
Digital Goods API는 현재
신뢰할 수 있는 웹 활동이며
window
객체의 getDigitalGoodsService
:
if ('getDigitalGoodsService' in window) {
// Digital Goods API is supported!
}
Digital Goods API는 모든 브라우저에서 사용할 수 있으며 다양한 스토어를 지원합니다. 목표:
특정 매장 백엔드가 지원되는지 확인하려면
getDigitalGoodsService()
: 스토어 ID를 매개변수로 전달합니다. Google Play 스토어가 식별됨
https://play.google.com/billing
문자열로 변환합니다.
if ('getDigitalGoodsService' in window) {
// Digital Goods API is supported!
try {
const service =
await window.getDigitalGoodsService('https://play.google.com/billing');
// Google Play Billing is supported!
} catch (error) {
// Google Play Billing is not available. Use another payment flow.
return;
}
}
SKU 세부정보를 가져옵니다.
Digital Goods API는 getDetails()
를 제공하여 다음과 같은 정보를 검색할 수 있습니다.
제품명, 설명, 가장 중요한 가격은 결제 백엔드에서 가져오는 정보입니다.
그런 다음 사용자 인터페이스에서 이 정보를 사용하고 사용자에게 추가 세부정보를 제공할 수 있습니다.
const skuDetails = await service.getDetails(['shiny_sword', 'gem']);
for (item of skuDetails) {
// Format the price according to the user locale.
const localizedPrice = new Intl.NumberFormat(
navigator.language,
{style: 'currency', currency: item.price.currency}
).format(item.price.value);
// Render the price to the UI.
renderProductDetails(
item.itemId, item.title, localizedPrice, item.description);
}
구매 흐름 구축
PaymentRequest의 생성자는 두 가지 매개변수, 즉 결제 수단 목록과 결제 세부정보
신뢰할 수 있는 웹 활동 내에서 Google Play 결제 수단을 사용해야 합니다.
https://play.google.com/billing
를 식별자로 설정하고 제품 SKU를
데이터 멤버:
async function makePurchase(service, sku) {
// Define the preferred payment method and item ID
const paymentMethods = [{
supportedMethods: "https://play.google.com/billing",
data: {
sku: sku,
}
}];
...
}
결제 세부정보가 필요하지만 Play 결제에서는 이러한 값을 무시하고 값이 가짜 값으로 채워질 수 있도록 Play Console에서 SKU를 만들 때 설정된 값
const paymentDetails = {
total: {
label: `Total`,
amount: {currency: `USD`, value: `0`}
}
};
const request = new PaymentRequest(paymentMethods, paymentDetails);
결제 요청 객체에서 show()
를 호출하여 결제 흐름을 시작합니다. 프로미스가 성공한 경우
결제가 정상적으로 처리되었을 수 있습니다. 실패하면 사용자가 결제를 중단했을 가능성이 높습니다.
프라미스가 성공하면 구매를 확인하고 확인해야 합니다. 사기를 방지하려면 백엔드를 사용하여 이 단계를 구현해야 합니다. 자세한 내용은 백엔드에서 확인을 구현하는 방법을 알아보려면 Play 결제 문서를 참고하세요. 구매를 확인하지 않으면 3일이 지나면 사용자는 환불을 받게 되고 Google Play에서 구매를 취소합니다.
...
const request = new PaymentRequest(paymentMethods, paymentDetails);
try {
const paymentResponse = await request.show();
const {purchaseToken} = paymentResponse.details;
// Call backend to validate and acknowledge the purchase.
if (await acknowledgePurchaseOnBackend(purchaseToken, sku)) {
// Optional: tell the PaymentRequest API the validation was
// successful. The user-agent may show a "payment successful"
// message to the user.
const paymentComplete = await paymentResponse.complete('success');
} else {
// Optional: tell the PaymentRequest API the validation failed. The
// user agent may show a message to the user.
const paymentComplete = await paymentResponse.complete('fail');
}
} catch(e) {
// The purchase failed, and we can handle the failure here. AbortError
// usually means a user cancellation
}
...
원하는 경우 purchaseToken에 consume()
를 호출하여 구매를 소진된 것으로 표시할 수 있습니다.
다시 구매할 수 있습니다.
종합하면 구매 방법은 다음과 같습니다.
async function makePurchase(service, sku) {
// Define the preferred payment method and item ID
const paymentMethods = [{
supportedMethods: "https://play.google.com/billing",
data: {
sku: sku,
}
}];
// The "total" member of the paymentDetails is required by the Payment
// Request API, but is not used when using Google Play Billing. We can
// set it up with bogus details.
const paymentDetails = {
total: {
label: `Total`,
amount: {currency: `USD`, value: `0`}
}
};
const request = new PaymentRequest(paymentMethods, paymentDetails);
try {
const paymentResponse = await request.show();
const {purchaseToken} = paymentResponse.details;
// Call backend to validate and acknowledge the purchase.
if (await acknowledgePurchaseOnBackend(purchaseToken, sku)) {
// Optional: consume the purchase, allowing the user to purchase
// the same item again.
service.consume(purchaseToken);
// Optional: tell the PaymentRequest API the validation was
// successful. The user-agent may show a "payment successful"
// message to the user.
const paymentComplete =
await paymentResponse.complete('success');
} else {
// Optional: tell the PaymentRequest API the validation failed.
// The user agent may show a message to the user.
const paymentComplete = await paymentResponse.complete('fail');
}
} catch(e) {
// The purchase failed, and we can handle the failure here.
// AbortError usually means a user cancellation
}
}
기존 구매 상태 확인
Digital Goods API를 사용하면 사용자에게 기존 사용 권한 (인앱 구매)이 있는지 확인할 수 있습니다. (아직 소비되지 않은 구매 또는 진행 중인 구독) 다른 기기에서, 이전 설치를 통해 구매했거나, 프로모션 코드를 통해 구매했거나, 확인할 수 있습니다.
const service =
await window.getDigitalGoodsService('https://play.google.com/billing');
...
const existingPurchases = await service.listPurchases();
for (const p of existingPurchases) {
// Update the UI with items the user is already entitled to.
console.log(`Users has entitlement for ${p.itemId}`);
}
이전에 구매했지만 확인되지 않은 구매 내역을 확인하는 것도 좋습니다. 사용자가 Google에서 구매했는지 확인하기 위해 가능한 한 빨리 구매를 확인하는 것이 좋습니다. 사용 권한 앱에 제대로 반영되었는지 확인할 수 있습니다
const service =
await window.getDigitalGoodsService("https://play.google.com/billing");
...
const existingPurchases = await service.listPurchases();
for (const p of existingPurchases) {
await verifyOrAcknowledgePurchaseOnBackend(p.purchaseToken, p.itemId);
// Update the UI with items the user is already entitled to.
console.log(`Users has entitlement for ${p.itemId}`);
}
통합 테스트
개발용 Android 기기에서
테스트를 위해 개발용 Android 기기에서 Digital Goods API를 사용 설정할 수 있습니다.
- Android 9 이상을 사용하고 개발자 모드를 사용 설정해야 합니다.
- Chrome 101 이상을 설치합니다.
chrome://flags
로 이동한 다음 플래그 지정: <ph type="x-smartling-placeholder">- </ph>
#enable-debug-for-store-billing
- 사이트가 https 프로토콜을 사용하여 호스팅되는지 확인합니다. http를 사용하면 API가
undefined
이 됩니다.
ChromeOS 기기에서
Digital Goods API는 버전 89부터 ChromeOS 안정화 버전에서 사용할 수 있습니다. 그동안 Digital Goods API를 테스트할 수 있습니다.
- 기기의 Play 스토어에서 앱을 설치합니다.
- 사이트가 https 프로토콜을 사용하여 호스팅되는지 확인합니다. http를 사용하면 API가
undefined
이 됩니다.
테스트 사용자 및 품질 보증팀 사용
Play 스토어는 사용자 테스트 계정 및 테스트 SKU를 비롯한 테스트용 어포던스를 제공합니다. 자세한 내용은 Google Play 결제 테스트 문서를 참조하세요.
다음 단계
이 문서에서 설명한 것처럼 Play Billing API에는 서버 측 구성요소로 이루어져 있습니다.
- https://github.com/PEConn/beer에서 Peter Conn의 샘플을 살펴보세요.
- 구매 인증에 대한 Play 문서를 확인하세요.
- 제공되는 Google Play Developer API 클라이언트 라이브러리 중 하나를 사용해 보세요. 다국어 지원
- 애플리케이션에서 구독 모델을 구현하는 경우 Play 결제 정기 결제 문서
- 실시간 개발자 알림 (RTDN)을 구현하고 알림을 구독하여 상태를 폴링하는 대신 구독 상태가 변경되면 백엔드에 알림을 보냅니다. 재생.
linkedPurchaseToken
를 구현하여 중복 정기 결제를 방지합니다. 이 블로그 게시물 읽기 방법을 배웁니다.