1. 사용 예시
참고: 본 섹션은 규범적이지 않습니다.
1.1. 서비스 인스턴스 얻기
window.getDigitalGoodsService()
호출로 시작되며,
이 방법은 특정 컨텍스트(예: HTTPS, 앱, 브라우저, OS)에서만 제공될 수 있습니다. 만약
지원된다면, 서비스 제공자 URL과 함께 메서드를 호출할 수 있습니다. 이 메서드는
주어진 서비스 제공자를 사용할 수 없는 경우 promise를 reject로 반환합니다.
if ( window. getDigitalGoodsService=== undefined ) { // 이 환경에서는 Digital Goods API가 지원되지 않습니다. return ; } try { const digitalGoodsService= await window. getDigitalGoodsService( "https://example.com/billing" ); // 여기에서 서비스를 사용합니다. ... } catch ( error) { // 선호하는 서비스 제공자를 사용할 수 없습니다. // 일반 웹 기반 결제 플로우를 사용하세요. console. error( "Failed to get service:" , error. message); return ; }
1.2. 상품 상세 정보 조회
const details= await digitalGoodsService. getDetails([ 'shiny_sword' , 'gem' , 'monthly_subscription' ]); for ( itemof details) { const priceStr= new Intl. NumberFormat( locale, { style: 'currency' , currency: item. price. currency} ). format( item. price. value); AddShopMenuItem( item. itemId, item. title, priceStr, item. description); }
getDetails()
메서드는
주어진 항목 세트에 대한 서버측 상세 정보를 반환하며,
메뉴 등에서 사용자에게 구매 옵션과 가격을 구매 플로우 없이 보여줄 때 사용됩니다.
반환된 ItemDetails
시퀀스의 순서는 임의이며, 서버에 존재하지 않는 항목은 포함하지 않을 수 있습니다(즉, 입력과 출력이 1:1로 일치하지 않을 수 있음).
항목 ID는 상점 서버에 설정된 항목의 기본 키 문자열입니다. 항목 ID 목록을 가져오는 함수는 존재하지 않으며, 클라이언트 코드에 하드코딩하거나 개발자 서버에서 가져와야 합니다.
항목의 가격은 PaymentCurrencyAmount
타입으로,
사용자의 현재 지역과 통화로 아이템의 가격 정보를 제공합니다. 위의 예시처럼 Intl.NumberFormat을 사용해 현재 로케일에 맞게 포맷해야
합니다.
ItemDetails
오브젝트의 필드에 대한 자세한 정보는 아래 [ItemDetails 딕셔너리] 섹션을 참고하세요.
1.3. Payment Request API를 이용한 구매
const details= await digitalGoodsService. getDetails([ 'monthly_subscription' ]); const item= details[ 0 ]; new PaymentRequest( [{ supportedMethods: 'https://example.com/billing' , data: { itemId: item. itemId}}]);
구매 플로우는 Payment Request API를 사용합니다.
전체 결제 요청 코드는 생략하였으나, 사용자가 선택한 항목의 item ID를 해당 결제 메서드의
methodData의 data 필드에 상점별 형식으로 넘길 수 있습니다.
1.4. 기존 구매내역 확인
purchases= await digitalGoodsService. listPurchases(); for ( pof purchases) { VerifyOnBackendAndGrantEntitlement( p. itemId, p. purchaseToken); }
listPurchases()
메서드는
사용자가 현재 소유 중이거나 결제한 아이템들의 목록을 클라이언트가 조회할 수 있게 해줍니다.
권한(예: 구독, 프로모션 코드, 영구 업그레이드 등)이 활성 상태인지 확인하거나, 구매 도중 네트워크 오류 발생 시(예: 구매는 되었으나 백엔드 확인이 안 된 상태) 복구 목적으로
사용할 수 있습니다.
반환값에는 item ID 및 구매 토큰이 포함되며, 권한 부여 전에 개발자와 제공자 간의 직접 API로 검증할 수 있습니다.
1.5. 과거 구매내역 확인
const purchaseHistory= await digitalGoodsService. listPurchaseHistory(); for ( pof purchaseHistory) { DisplayPreviousPurchase( p. itemId); }
listPurchaseHistory()
메서드는
사용자가 지금까지 구매한 각 항목 타입의 최근 구매내역을 조회할 수 있도록 합니다. 만료되었거나 소비된 구매도 포함할 수 있습니다. 일부 상점에서는 이 내역을 보관하지 않을 수 있으며,
그런 경우 listPurchases()와
같은 데이터를 반환할 수 있습니다.
1.6. 구매 소비 처리
digitalGoodsService. consume( purchaseToken);
여러 번 구매할 수 있는 상품은 일반적으로 사용자가 다시 구매하기 전에 "소비됨(consumed)"으로 표시해야 합니다.
예를 들어, 일시적으로 플레이어를 강하게 해주는 게임 내 파워업은 소비성 구매의 한 예입니다. 이러한 처리는 consume()
메서드를 통해 할 수 있습니다.
더 확실하게 구매가 소진되었음을 검증하려면, 가능시 직접 제공자의 API를 통해 소비 처리를 권장합니다.
1.7. 서브도메인 iframe에서 사용
< iframe src= "https://sub.origin.example" allow= "payment" > < /iframe>
서브도메인 iframe에서 Digital Goods API의 사용을 허용하려면, iframe 요소에 allow 속성과 "payment"
키워드를 추가해야 합니다.
교차 출처(Cross-origin) iframe에서는 Digital Goods API를 사용할 수 없습니다. 보다 자세한 내용과 예시는 Permissions Policy 명세를 참고하세요.
2. API 정의
2.1. Window 인터페이스 확장
partial interface Window { [SecureContext ]Promise <DigitalGoodsService >getDigitalGoodsService (DOMString ); };serviceProvider
Window
오브젝트는 getDigitalGoodsService()
메서드를 노출할 수 있습니다.
Digital Goods를 지원하지 않는 유저 에이전트는 getDigitalGoodsService()를
Window
인터페이스에 노출하면 안 됩니다.
참고: 위 설명은 기능 감지를 허용하기 위한 것입니다.
getDigitalGoodsService()
가 존재한다면,
최소한 하나의 서비스 제공자와 동작할 수 있다고 합리적으로 기대할 수 있습니다.
2.1.1. getDigitalGoodsService() 메서드
참고: getDigitalGoodsService()
메서드는
주어진 serviceProvider
가 현재 컨텍스트에서 지원되는지 확인하기 위해 호출됩니다. 이 메서드는 Promise를 반환하고,
지원 시 DigitalGoodsService
오브젝트로 resolve되거나,
지원하지 않거나 에러가 발생하면 reject로 반환됩니다. serviceProvider
는 일반적으로 url 기반 결제 메서드 식별자입니다.
getDigitalGoodsService(serviceProvider)
메서드가 호출되면, 다음 순서대로 동작합니다:
-
document를 현재 설정 객체의 관련 글로벌 객체의 연결된
Document로 둔다. -
document가 완전히 활성(fully active) 상태가 아니라면 거부된 promise와
"InvalidStateError"DOMException을 반환한다. -
document의 origin이 상위 Origin과 동일하지 않으면 거부된 promise와
"NotAllowedError"DOMException을 반환한다. -
document가 "payment" 권한을 허용되지 않은 경우, 거부된 promise와
"NotAllowedError"DOMException을 반환한다. -
serviceProvider가 undefined이거나 null, 빈 문자열일 경우 거부된 promise와
TypeError을 반환한다. -
result를 can make digital goods service algorithm을 serviceProvider와 document로 수행한 결과로 둔다.
-
result가 false면 거부된 promise와
OperationError를 반환한다. -
resolve된 promise와 새로운
DigitalGoodsService를 반환한다.
2.1.2. Digital Goods Service 생성 가능 알고리즘
-
user agent는 serviceProvider, document 또는 외부 요인에 따라 true나 false를 반환할 수 있습니다.
참고: 유저 에이전트마다 서로 다른 컨텍스트에서 서로 다른 서비스 제공자를 지원할 수 있습니다.
2.2. DigitalGoodsService 인터페이스
[Exposed =Window ,SecureContext ]interface {DigitalGoodsService Promise <sequence <ItemDetails >>getDetails (sequence <DOMString >);itemIds Promise <sequence <PurchaseDetails >>listPurchases ();Promise <sequence <PurchaseDetails >>listPurchaseHistory ();Promise <undefined >consume (DOMString ); };purchaseToken dictionary {ItemDetails required DOMString ;itemId required DOMString ;title required PaymentCurrencyAmount ;price ItemType ;type DOMString ;description sequence <DOMString >;iconURLs DOMString ;subscriptionPeriod DOMString ;freeTrialPeriod PaymentCurrencyAmount ;introductoryPrice DOMString ; [introductoryPricePeriod EnforceRange ]unsigned long long ; };introductoryPriceCycles enum {ItemType ,"product" , };"subscription" dictionary {PurchaseDetails required DOMString ;itemId required DOMString ; };purchaseToken
2.2.1. getDetails() 메서드
getDetails(itemIds)
메서드가 호출되면, 아래 단계를 따릅니다:
-
만약 itemIds가 비어 있다면, 거부된 promise와
TypeError를 반환합니다. -
result를 디지털 상품 서비스에서 itemIds에 대한 정보를 요청한 결과로 둡니다.
참고: 이를 통해 사용자 에이전트에서 서비스 제공자별 동작으로 다양한 디지털 상품 제공자를 지원할 수 있습니다.
-
만약 result가 에러라면, 거부된 promise와
OperationError를 반환합니다. -
result의 각 itemDetails에 대하여:
-
itemDetails.itemId는 빈 문자열이 아니어야 합니다.
-
itemIds는 반드시 포함해야 합니다. itemDetails.itemId를.
-
itemDetails.title은 빈 문자열이 아니어야 합니다.
-
itemDetails.price는 정규 PaymentCurrencyAmount여야 합니다.
-
존재한다면, itemDetails.subscriptionPeriod는 iso-8601 기간이어야 합니다.
-
존재한다면, itemDetails.freeTrialPeriod는 iso-8601 기간이어야 합니다.
-
존재한다면, itemDetails.introductoryPrice는 정규 PaymentCurrencyAmount여야 합니다.
-
존재한다면, itemDetails.introductoryPricePeriod는 iso-8601 기간이어야 합니다.
-
-
resolve된 promise와 result를 반환합니다.
참고: result의 항목 순서가 itemIds와 일치해야 할 필요는 없습니다. 이는 누락되거나 유효하지 않은 항목이 출력 목록에서 건너뛸 수 있도록 허용하기 위함입니다.
2.2.2. listPurchases() 메서드
listPurchases() 메서드가 호출되면, 아래 단계를 따릅니다:
-
result를 디지털 상품 서비스에서 사용자의 구매 정보 요청 결과로 둡니다.
참고: 이를 통해 사용자 에이전트에서 서비스 제공자별 동작으로 다양한 디지털 상품 제공자를 지원할 수 있습니다.
-
만약 result가 에러라면, 거부된 promise와
OperationError를 반환합니다. -
result의 각 itemDetails에 대하여:
-
itemDetails.itemId는 빈 문자열이 아니어야 합니다.
-
itemDetails.purchaseToken은 빈 문자열이 아니어야 합니다.
-
-
resolve된 promise와 result를 반환합니다.
2.2.3. listPurchaseHistory() 메서드
listPurchaseHistory()
메서드가 호출되면, 아래 단계를 따릅니다:
-
result를 사용자가 지금까지 구매한 각 항목 타입의 최신 구매 정보 요청 결과로 둡니다.
-
만약 result가 에러라면, 거부된 promise와
OperationError를 반환합니다. -
result의 각 itemDetails에 대하여:
-
itemDetails.itemId는 빈 문자열이 아니어야 합니다.
-
itemDetails.purchaseToken은 빈 문자열이 아니어야 합니다.
-
-
resolve된 promise와 result를 반환합니다.
2.2.4. consume() 메서드
참고: 여기서 consume은 구매 내용을 소진(사용)하는 것을 의미합니다. 소비가 완료되면 사용자는 더 이상 해당 구매에 대해 권리가 없습니다.
consume(purchaseToken)
메서드가 호출되면, 아래 단계를 따릅니다:
-
purchaseToken이 빈 문자열이면, 거부된 promise와
TypeError를 반환합니다. -
result를 디지털 상품 서비스에 purchaseToken을 소비 처리하라고 요청한 결과로 둡니다.
참고: 이를 통해 사용자 에이전트에서 서비스 제공자별 동작으로 다양한 디지털 상품 제공자를 지원할 수 있습니다.
-
만약 result가 에러라면, 거부된 promise와
OperationError를 반환합니다. -
resolve된 promise와
undefined를 반환합니다.
2.3. ItemDetails 딕셔너리
이 섹션은 규범적이지 않습니다.
ItemDetails
딕셔너리는
serviceProvider
로부터 전달받은 디지털 아이템 정보를 나타냅니다.
-
itemId는 현재 앱 인벤토리 내 특정 디지털 아이템을 식별합니다. 앱 내에서 고유해야 하며, 모든 앱에서 고유할 필요는 없습니다. -
title은 사용자에게 보여질 아이템의 이름입니다.serviceProvider가 사용자를 위해 로컬라이즈한 값이어야 합니다. -
price는 아이템 가격이며, § 1.2 상품 상세 정보 조회 예시처럼 사용자에게 보여주도록 포맷이 가능합니다.serviceProvider가 로컬라이즈한 값이어야 합니다. -
description은 사용자에게 표시될 아이템의 상세 설명입니다.serviceProvider가 사용자를 위해 로컬라이즈한 값이어야 합니다. -
iconURLs는 아이템의 시각적 설명을 제공하는 아이콘 목록입니다. -
subscriptionPeriod는 아이템이 사용자에게 권한을 부여하는 기간을 ISO 8601 기간으로 지정합니다. 기간 만료 후 권한은 갱신되거나 사라집니다(이것은 Digital Goods API에서 관리하지 않습니다). 이 필드는 구독 상품에서만 사용되며, 1회성 구매에는 사용되지 않습니다. -
freeTrialPeriod는 아이템이 무료로 권한을 부여하는 기간을 ISO 8601 기간으로 지정합니다. 이후 기간이 지나면 유료로 전환되거나 권한을 잃게 됩니다(Digital Goods API에서 처리하지 않습니다). 이 필드는 구독에서만 사용됩니다. -
introductoryPrice는 아이템의 최초 가격이며, § 1.2 상품 상세 정보 조회 예시처럼 사용자에게 포맷하여 보여줄 수 있습니다.serviceProvider가 로컬라이즈한 값이어야 합니다. -
introductoryPricePeriod는 아이템이 ISO 8601 기간 동안introductoryPrice로 판매되는 기간입니다. 이후에는price로 변경됩니다. -
introductoryPriceCycles는introductoryPrice가 적용되는 구독 주기 횟수입니다.
2.4. PurchaseDetails 딕셔너리
이 섹션은 규범적이지 않습니다.
PurchaseDetails
딕셔너리는 사용자가 serviceProvider
로부터 구입한 디지털 아이템 정보를 나타냅니다.
-
itemId는 현재 앱 인벤토리 내 특정 디지털 아이템을 식별합니다. 앱 내에서는 고유하지만, 전체 앱에서 반드시 고유하지 않아도 됩니다.itemId와getDetails()메서드와 등가입니다. -
purchaseToken은serviceProvider가 생성한 구매 토큰입니다. 직접 서비스 제공자와 검증하는 데 사용할 수 있습니다(Digital Goods API의 일부가 아님).
3. Permissions Policy 통합
이 명세는 "정책 제어 기능"을 "payment" 문자열로 정의합니다. 기본 허용 목록은 'self'입니다.
참고: 문서(document)의 permissions policy는
해당 문서의 모든 콘텐츠가 DigitalGoodsService
인스턴스를 획득할 수 있는지 결정합니다. 비활성화된 경우, 해당 문서 내의 어떤 콘텐츠도 사용할 수 없으며,
getDigitalGoodsService()
호출 시 예외가 발생합니다.
4. 추가 정의
"payment" 권한은 [permissions-policy] 기능이며, payment-request 명세에서 정의됩니다.정규
PaymentCurrencyAmount
는 PaymentCurrencyAmount
amount에 대해 체크 및 정규화 과정을 거쳐
오류가 발생하지 않고 값이 바뀌지 않는 경우를 의미합니다.
iso-8601은 날짜와 시간 형식 표준입니다.