← 모든 확장

네이티브 확장

KlugBilling

com.klug.billing

APM이 필요 없습니다. 다운로드해서 바로 사용하세요. 이보다 더 간단할 수 없습니다. Adobe AIR SDK만 업데이트하면 됩니다. 도움이 필요하시면 저희가 도와드립니다.

App Store와 Google Play에서 AIR 앱의 인앱 구매와 구독을 두 스토어 공통의 하나의 ActionScript API로 제공합니다.

iOS Android 프로덕션 운영 중 연 €19부터 · 구매

개요

KlugBilling은 AIR 앱에서 일회성 상품과 구독을 판매합니다. iPhone과 iPad에서는 App Store와, Android에서는 Google Play와 통신하며, ActionScript 코드는 두 스토어 모두 동일하게 유지됩니다.

현지화된 제목과 가격으로 상품을 불러오고, 스토어의 구매 시트를 열며, 거래의 모든 단계를 보고하고, 상품을 제공한 뒤 거래를 종료합니다. 이전 구매 복원, iOS 앱 영수증, Google Play의 서명된 구매 데이터도 포함되어 있어 서버에서 모든 판매를 검증할 수 있습니다.

Android에서 KlugBilling은 최신 Google Play Billing Library 8을 사용합니다. 앱 패키징 시 자동으로 추가되며, 신규 앱과 업데이트에 대한 Google Play의 요구 사항을 충족합니다.

KlugBilling은 개념 증명인 저희 앱의 iOS 및 Android 구독을 판매하고 있습니다.

기능

  • 독립형: ANE 하나로 충분하며, 코어 라이브러리나 의존성 ANE를 추가할 필요가 없음
  • App Store와 Google Play를 위한 하나의 API
  • 일회성 상품과 자동 갱신 구독
  • 스토어에서 바로 가져오는 현지화된 제목, 설명, 가격
  • 구독 기간, 혜택, 가격 단계
  • 모든 거래 상태를 이벤트로 제공: 구매 중, 구매 완료, 실패, 취소, 복원, 보류
  • 구매 복원(iOS) 및 보유 구매 목록 조회(Android)
  • 서버 측 검증용 데이터: iOS 앱 영수증, Google의 서명된 구매 데이터와 서명
  • Android: 구매를 Play 공개 키로 확인

지원 플랫폼

iOS iPhone · iPad · App Store
Android 휴대폰 · 태블릿 · 폴더블 · Google Play Billing Library 8

다른 플랫폼에서는 InAppBilling.isSupported가 false를 반환하므로, 같은 코드를 크로스 플랫폼 앱에 그대로 둘 수 있습니다.

시작하기

애플리케이션 디스크립터에 확장을 추가합니다:

app.xml
<extensions>
    <extensionID>com.klug.billing</extensionID>
</extensions>

매니페스트 항목이나 액티비티는 필요 없습니다. App Store Connect와 Google Play Console에서 같은 상품 ID로 상품을 만들고, Play Console(수익 창출 설정)에서 앱의 base64 공개 키를 복사하세요.

코드 예제

저희 앱에서 실행되는 API에서 가져온 네 가지 완전한 흐름입니다. 모든 호출은 즉시 반환되며, 결과는 InAppBilling.service의 이벤트로 전달됩니다. 전체 문서 →

1 · 스토어에 연결
Store.as
import com.klug.billing.*;
import com.klug.billing.events.*;

var store:InAppBillingService = InAppBilling.service;

if ( InAppBilling.isSupported )   // iOS, Android
{
    store.addEventListener( InAppBillingEvent.SETUP_SUCCESS, onSetup );
    store.addEventListener( InAppBillingEvent.SETUP_FAILURE, onSetupFailed );
    store.addEventListener( PurchaseEvent.PURCHASES_UPDATED, onPurchasesUpdated );   // see 3

    var service:BillingService = new BillingService();
    if ( store.platform == "android" )
        service.setServiceType( InAppBillingServiceTypes.GOOGLE_PLAY_INAPP_BILLING )
               .setGooglePlayPublicKey( "MIIBIjANBgkqh..." );   // from the Play Console, Android only
    else
        service.setServiceType( InAppBillingServiceTypes.APPLE_INAPP_PURCHASE );
    store.setup( service );
}

function onSetup( e:InAppBillingEvent ):void
{
    store.checkAvailability( function( result:String ):void {
        if ( result == InAppBillingAvailability.AVAILABLE ) loadProducts();   // see 2
        else hideShop();   // e.g. purchases disabled by Screen Time
    });
}
2 · 현지화된 가격으로 상품 표시
Products.as
function loadProducts():void
{
    store.addEventListener( ProductEvent.PRODUCTS_LOADED, onProducts );
    store.addEventListener( ProductEvent.PRODUCTS_FAILED, function( e:ProductEvent ):void {
        trace( "store not reachable: " + e.message );
    });
    // one-time products first, subscriptions second
    store.getProducts( [ "com.example.removeads" ],
                       [ "com.example.pro.monthly", "com.example.pro.yearly" ] );
}

function onProducts( e:ProductEvent ):void
{
    for each ( var p:Product in e.products )
    {
        // e.g. "Pro Yearly · 19,99 €" in the user's currency and language
        addShopButton( p.id, p.title + " · " + p.priceString );   // your app function
    }
}
3 · 구매, 제공, 완료
Purchase.as
function buy( productId:String ):void
{
    var request:PurchaseRequest = new PurchaseRequest().setProductId( productId );
    if ( store.checkPurchaseRequestValid( request ) ) store.makePurchase( request );
}

// every step of every transaction, also open ones from earlier sessions
function onPurchasesUpdated( e:PurchaseEvent ):void
{
    for each ( var p:Purchase in e.data )
    {
        switch ( p.transactionState )
        {
            case Purchase.STATE_PURCHASED:
            case Purchase.STATE_RESTORED:
                // iOS: p.transactionReceipt (app receipt)
                // Android: p.originalMessage + p.signature (Google's signed purchase data)
                verifyOnServer( p, function():void {   // your server call
                    unlock( p.productId );              // your app function
                    store.finishPurchase( p );          // close it, or the store sends it again
                });
                break;
            case Purchase.STATE_FAILED:
            case Purchase.STATE_CANCELLED:
                store.finishPurchase( p );
                break;
            case Purchase.STATE_DEFERRED:
                showHint( "Waiting for approval" );   // e.g. Ask to Buy
                break;
        }
    }
}
4 · 이전 구매 복원
Restore.as
function restore():void
{
    if ( store.isGetPurchasesSupported )   // Android: list what the Google account owns
    {
        store.addEventListener( PurchaseEvent.GET_PURCHASES_COMPLETE, function( e:PurchaseEvent ):void {
            for each ( var p:Purchase in e.data ) unlock( p.productId );
        });
        store.getPurchases();
    }
    else   // iOS: restored transactions arrive in onPurchasesUpdated with STATE_RESTORED
    {
        store.addEventListener( PurchaseEvent.RESTORE_PURCHASES_SUCCESS, function( e:PurchaseEvent ):void {
            showHint( "Purchases restored" );
        });
        store.restorePurchases();
    }
}

API 개요

InAppBilling.isSupportediOS와 Android에서는 true, 그 외에는 false입니다.
InAppBilling.service단일 스토어 서비스이며, 아래의 모든 호출과 이벤트가 여기서 이루어집니다.
setup(service)BillingService로 지정된 스토어에 연결합니다. 결과: SETUP_SUCCESS 또는 SETUP_FAILURE.
checkAvailability(callback)AVAILABLE, NOT_AVAILABLE 또는 STORE_UPGRADE_REQUIRED.
canMakePayments기기에서 구매가 비활성화되어 있으면 false입니다.
getProducts(productIds, subscriptionIds)스토어 데이터를 불러옵니다. 결과: PRODUCTS_LOADED, INVALID_PRODUCT 또는 PRODUCTS_FAILED.
getProduct(id)불러온 Product: title, description, price, priceString, currencyCode, subscriptionPeriod, subscriptionOffers.
makePurchase(request)PurchaseRequest에 대해 스토어의 구매 시트를 엽니다. 구독 혜택은 선택 사항입니다.
finishPurchase(purchase)제공 후 거래를 종료합니다. 결과: FINISH_SUCCESS 또는 FINISH_FAILED.
getPendingPurchases()스토어에 아직 열려 있는 거래.
restorePurchases()iOS: Apple ID의 이전 구매를 복원합니다.
getPurchases()Android: Google 계정의 구매 목록을 가져옵니다.
applicationReceiptiOS: 서버용 base64 형식의 앱 영수증이며, refresh()로 새로 고칠 수 있습니다.
dispose()스토어와의 연결을 끊습니다.

이벤트

InAppBillingEventSETUP_SUCCESS, SETUP_FAILURE, RESTORE_PURCHASES_SUCCESS, RESTORE_PURCHASES_FAILED
ProductEventPRODUCTS_LOADED (products), INVALID_PRODUCT, PRODUCTS_FAILED
PurchaseEventPURCHASES_UPDATED (data = Purchase 객체), PURCHASE_FAILED, FINISH_SUCCESS, FINISH_FAILED, RESTORE_PURCHASES_SUCCESS, RESTORE_PURCHASES_FAILED, GET_PURCHASES_COMPLETE, GET_PURCHASES_FAILED
AvailabilityEventCOMPLETE, 이용 가능 여부 결과 포함
ApplicationReceiptEventREFRESH_SUCCESS, REFRESH_FAILED

KlugBilling 구매

AIR 애플리케이션 1개에 대한 연간 라이선스이며 12개월간 모든 업데이트를 제공합니다. 결제 후 확장, ActionScript 라이브러리, 문서를 이메일로 보내 드리며, 보통 영업일 기준 1일 이내입니다. 라이선스 및 약관

심플
€19 / 년
  • AIR 애플리케이션 1개에 대한 라이선스
  • 12개월간 모든 업데이트
  • 지원 없음
심플 구매
스탠더드
€149 / 년
  • AIR 애플리케이션 1개에 대한 라이선스
  • 12개월간 모든 업데이트
  • 7일 이내 이메일 답변
스탠더드 구매
프라이어리티
€299 / 년
  • AIR 애플리케이션 1개에 대한 라이선스
  • 12개월간 모든 업데이트
  • 48시간 이내 이메일 답변
프라이어리티 구매
세금은 Link(Stripe)가 결제 시 계산합니다. 결제 중에 AIR 앱의 애플리케이션 ID를 입력합니다.

요구 사항

AIR SDK51.x (HARMAN)
iOSiOS 13 이상, App Store Connect에 등록된 상품
AndroidAndroid 6.0 (API 23) 이상, Google Play Console에 등록된 상품
Google PlayPlay Billing Library 8.3, 패키징 시 추가됨
서버(권장)iOS 앱 영수증 또는 Google의 서명된 구매 데이터를 검증