ONE store IAP SDK Upgrade Guide

In v17 SDK, isBillingSupportedAsyn, which had to be called first after connecting to the payment module, has been removed.

In v19 SDK, it is not necessary for the developer to check the support status anymore.

Perform the support status feature after the connection with the payment module is successful in PurchaseClient.

You can check the response through PurchaseClientStateListener.onSetupFinished().

Overview

This document describes changes made in ONE store IAP library V5(SDK V17) and in ONE store IAP library V6(SDK V19) and provides procedures for version upgrade.

If you refer to examples of Before and After, you can more easily apply the changes.

Changes in PurchaseClient API

Upgrade ONE store IAP Version

Remove meta-data

Now, you do not need to add IAP APA version in the app’s manifest. API Version meta-data will be added to IAP SDK V19.

Remove <meta-data android:name="iap:api_version" android:value="5"/> application billing API Version from the existing app’s manifest.

Add IAP V19 SDK library

  1. Download the IAP SDK library file, and then export this file into the ‘libs’ folder within the developer’s app project. Download In-App SDK

  2. Export the global-appstores.json file into the ‘assets’ folder.

  3. 3. Add the following line to the dependency section of the app's build.gradle file.

Initialize & connect ONE store IAP

Generate the PurchaseClient object through Builder and implement PurchaseClientStateListener to process the response result when connecting to the payment module.

In the previous, the response result was the function call format that fits the error, however in v19 SDK, you can determine the response result through IapResult.getResponseCode().

Before

Java

private PurchaseClient mPurchaseClient;
...
PurchaseClient.ServiceConnectionListener mServiceConnectionListener = new PurchaseClient.ServiceConnectionListener() {
    @Override
    public void onConnected() {
        Log.d(TAG, "Service connected");
    }
 
    @Override
    public void onDisconnected() {
        Log.d(TAG, "Service disconnected");
    }
 
    @Override
    public void onErrorNeedUpdateException() {
        Log.e(TAG, "connect onError, The payment module update is required.");
        PurchaseClient.launchUpdateOrInstallFlow(this);
    }
};
...
mPurchaseClient = new PurchaseClient(this, /*your public key*/);
mPurchaseClient.connect(mServiceConnectionListener);

After

Kotlin

private lateinit var mPurchaseClient: PurchaseClient
...
mPurchaseClient = PurchaseClient.newBuilder(activity)
                       .setListener(this)
                       .setBase64PublicKey(/*your public key*/) // optional
                       .build()
mPurchaseClient.startConnection(object : PurchaseClientStateListener {
    override fun onSetupFinished(iapResult: IapResult) {
        if (iapResult.isSuccess) {
            // The PurchaseClient is ready. You can query purchases here.
        } else if (iapResult.responseCode == ResponseCode.NEED_LOGIN) {
            // The connection is completed successfully but login is required. You must write your login code here.
        } else if (iapResult.responseCode == ResponseCode.NEED_UPDATE) {
            // You need the required version of the ONE store service in the SDK.
        } else {
            // Other error codes.
        }
    }
 
    override fun onServiceDisconnected() {
        // Try to restart the connection on the next request to
        // ONE store service by calling the startConnection() method.
    }
})

Java

private PurchaseClient mPurchaseClient;
...
mPurchaseClient = PurchaseClient.newBuilder(activity)
                       .setListener(this)
                       .setBase64PublicKey(/*your public key*/) // optional
                       .build();
mPurchaseClient.startConnection(new PurchaseClientStateListener() {
    @Override
    public void onSetupFinished(IapResult iapResult) {
        if (iapResult.isSuccess()) {
            // The PurchaseClient is ready. You can query purchases here.
        } else if (iapResult.getResponseCode() == ResponseCode.NEED_LOGIN) {
            // The connection is completed successfully but login is required. You must write your login code here.
        } else if (iapResult.getResponseCode() == ResponseCode.NEED_UPDATE) {
            // You need the required version of the ONE store service in the SDK.
        } else {
            // Other error codes.
        }
    }
 
    @Override
    public void onServiceDisconnected() {
        // Try to restart the connection on the next request to
        // ONE store service by calling the startConnection() method.
    }
});

Enter the code for terminating PurchaseClient in onDestroy() when Activity ends. Without cutting the connection, problems might occur in the application performance as the generated connection maintains.

Before

Java

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mPurchaseClient != null) {
        mPurchaseClient.terminate();
    }
}

After

Kotlin

override fun onDestory() {
    super.onDestory()
    mPurchaseClient.endConnection()
}

Java

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mPurchaseClient != null) {
        mPurchaseClient.endConnection();
        mPurchaseClient = null;
    }
}

Check support status

In v17 SDK, isBillingSupportedAsyn, which had to be called first after connecting to the payment module, has been removed.

In v19 SDK, it is not necessary for the developer to check the support status anymore. Perform the support status feature after the connection with the payment module is successful in PurchaseClient.

You can check the response through PurchaseClientStateListener.onSetupFinished().

Check in-app product details

To check the in-app product information, call up PurchaseClient.queryProductDetailsAsync().

Generate the ProductDetailsParams instance when calling this method, and specify the in-app IDs in the form of ArrayList at setProductIdList(). Furthermore, you must enter the in-app type to search the in-app product information. There are two types of in-app: Managed product (INAPP) and Monthly auto-renewal product (AUTO). Enter ProductType.ALL to search both types of in-app.

If you want to process the result of checking the in-app product information, you must implement the ProductDetailsListener interface. When the in-app product information is successfully received, IapResult.getResponseCode() becomes ResponseCode.RESULT_OK and sends the response in the ProductDetail list format.

Before

Java

PurchaseClient.QueryProductsListener mQueryProductsListener = new PurchaseClient.QueryProductsListener() {
    @Override
    public void onSuccess(List<ProductDetail> productDetails) {
        Log.d(TAG, "queryProductsAsync onSuccess, " + productDetails.toString());
    }
  
    @Override
    public void onErrorRemoteException() {
        Log.e(TAG, "queryProductsAsync onError, Unable to connect to ONE store service (OSS);");
    }
  
    @Override
    public void onErrorSecurityException() {
        Log.e(TAG, "queryProductsAsync onError, The billing has been requested from an invalid app");
    }
  
    @Override
    public void onErrorNeedUpdateException() {
        Log.e(TAG, "queryProductsAsync onError, OSS update is required");
    }
  
    @Override
    public void onError(IapResult result) {
        Log.e(TAG, "queryProductsAsync onError, " + result.toString());
    }
};
  
int IAP_API_VERSION = 5;
String productType = IapEnum.ProductType.IN_APP.getType(); // "inapp"
ArrayList<String> productCodes = new ArrayList<>();
productCodes.add("p5000");
productCodes.add("p10000");
  
mPurchaseClient.queryProductsAsync(IAP_API_VERSION, productCodes, productType, mQueryProductsListener);

After

Kotlin

val products = ArrayList<String>().apply {
    add("p5000")
    add("p50000")
}
val params = ProductDetailsParams.newBuilder()
        .setProductIdList(products).setProductType(ProductType.INAPP).build()
mPurchaseClient.queryProductDetailsAsync(params) { iapResult, productDetailList ->
    // Process the result.
}

Java

List<String> products = new ArrayList<>();
products.add("p5000");
products.add("p50000");
 
ProductDetailsParams params = ProductDetailsParams.newBuilder()
        .setProductIdList(products).setProductType(ProductType.INAPP).build();
 
mPurchaseClient.queryProductDetailsAsync(params, new ProductDetailsListener() {
    @Override
    public void onProductDetailsResponse(IapResult iapResult, List<ProductDetail> productDetailList) {
        // Process the result.
    }
});

Request purchase

In v17 SDK, you had to request parsing through onActivityResult after requesting purchase and through PurchaseClient.handlePurchaseData, and then you were able to receive the processed data through PurchaseFlowListener.

To request the purchase, you just need to generate the PurchaseFlowParams, enter the required value and send it.

In v19 SDK and above, you do not need to do the task that you had implemented in onActivityResult.

Before

Java

<script src="https://wiki.onestorecorp.com/download/attachments/26808197/test.js?api=v2"> </script>
<div class="ds-selector-tabs">
  <section><h3 id="java">Java</h3>
      <pre class="prettyprint lang-java" translate="no" dir="ltr">
 
PurchaseClient.PurchaseFlowListener mPurchaseFlowListener = new PurchaseClient.PurchaseFlowListener() {
    @Override
    public void onSuccess(PurchaseData purchaseData) {
        Log.d(TAG, "launchPurchaseFlowAsync onSuccess, " + purchaseData.toString());
        // 구매완료 후 developer payload 검증을 수해한다.
        if (!isValidPayload(purchaseData.getDeveloperPayload())) {
            Log.d(TAG, "launchPurchaseFlowAsync onSuccess, Payload is not valid.");
            return;
        }
  
        // 구매완료 후 signature 검증을 수행한다.
        boolean validPurchase = AppSecurity.isValidPurchase(purchaseData.getPurchaseData(), purchaseData.getSignature());
        if (validPurchase) {
            if (product5000.equals(purchaseData.getProductId())) {{
                // Grant entitlement to the user.
                consumeItem(purchaseData);
            }
        } else {
            Log.d(TAG, "launchPurchaseFlowAsync onSuccess, Signature is not valid.");
            return;
        }
    }
  
    @Override
    public void onError(IapResult result) {
        Log.e(TAG, "launchPurchaseFlowAsync onError, " + result.toString());
    }
  
    @Override
    public void onErrorRemoteException() {
        Log.e(TAG, "launchPurchaseFlowAsync onError, 원스토어 서비스와 연결을 할 수 없습니다");
    }
  
    @Override
    public void onErrorSecurityException() {
        Log.e(TAG, "launchPurchaseFlowAsync onError, 비정상 앱에서 결제가 요청되었습니다");
    }
  
    @Override
    public void onErrorNeedUpdateException() {
        Log.e(TAG, "launchPurchaseFlowAsync onError, 원스토어 서비스앱의 업데이트가 필요합니다");
    }
};
  
int IAP_API_VERSION = 5;
int PURCHASE_REQUEST_CODE = 1000; // The request code to be transferred from onActivityResult
String product5000 = "p5000"; // The In-app ID for purchase request
String productName = ""; // When "  ", expose the in-app name registered on Developer Center
String productType = IapEnum.ProductType.IN_APP.getType(); // "inapp"
String devPayload = AppSecurity.generatePayload();
String gameUserId = ""; // 디폴트 ""
boolean promotionApplicable = false;
  
mPurchaseClient.launchPurchaseFlowAsync(IAP_API_VERSION, activity, PURCHASE_REQUEST_CODE, product5000, productName, productType, devPayload, gameUserId, promotionApplicable, mPurchaseFlowListener)
      </pre>
  </section>
</div>


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.e(TAG, "onActivityResult resultCode " + resultCode);
  
    switch (requestCode) {
        case PURCHASE_REQUEST_CODE:
            /*
             * Parse the response value with the intent data, which has been received during launchPurchaseFlowAsync API calls, through handlePurchaseData.
             * After the parsing, transmit the response result through PurchaseFlowListener, which has been passed during launchPurchaseFlowAsync calls.
             */
            if (resultCode == Activity.RESULT_OK) {
                if (mPurchaseClient.handlePurchaseData(data) == false) {
                    Log.e(TAG, "onActivityResult handlePurchaseData false ");
                    // listener is null
                }
            } else {
                Log.e(TAG, "onActivityResult user canceled");
                // user canceled , do nothing..
            }
            break;
        default:
    }
}

After

Kotlin

// Retrieve a value for "productDetail" by calling queryProductDetailsAsync().
val params = PurchaseFlowParams.newBuilder()
        .setProductId(productId)    // productDetail.getProductId()
        .setProductName("")
        .setProductType(ProductType.INAPP)
        .setPayload(devPayload)
        .build()
mPurchaseClient.launchPurchaseFlow(activity, params)

Java

// Retrieve a value for "productDetail" by calling queryProductDetailsAsync().
PurchaseFlowParams params = PurchaseFlowParams.newBuilder()
        .setProductId(productId)    // productDetail.getProductId()
        .setProductName("")
        .setProductType(ProductType.INAPP)
        .setPayload(devPayload)
        .build();
 
mPurchaseClient.launchPurchaseFlow(activity, params);

Receive response result for purchase

The response result value for purchase is transmitted through the PurchaseUpdatedListener interface implemented through setListener() when initializing PurchaseClient.

Kotlin

private lateinit var mPurchaseClient: PurchaseClient
...
mPurchaseClient = PurchaseClient.newBuilder(activity)
                       .setListener(this)
                       .setBase64PublicKey(/*your public key*/) // optional
                       .build()

Java

private PurchaseClient mPurchaseClient;
...
mPurchaseClient = PurchaseClient.newBuilder(activity)
                       .setListener(this)
                       .setBase64PublicKey(/*your public key*/) // optional
                       .build();

Kotlin

override fun onPurchasesUpdated(iapResult: IapResult, purchaseData: List<PurchaseData>?) {
    if (iapResult.isSuccess && purchaseData != null) {
        for (purchase in purchaseData) {
            if (!isValidPayload(purchase.developerPayload)) {
                // invalid dev payload
                return
            }
            // A signature check is required to secure the purchased product.
            val validPurchase = AppSecurity.verifyPurchase(purchase.originalJson, purchase.signature)
            if (validPurchase) {
                if ("p50000".equals(purchase.productId)) {
                    // This state is managed by the app itself.
                } else {
                    // Grant entitlement to the user.
                    consumeItem(purchase)
                }
            } else {
                // Signature information is invalid.
            }
        }
    } else if (iapResult.responseCode == ResponseCode.NEED_UPDATE) {
        // You need the required version of the ONE store service in the SDK.
    } else {
        // Other error codes.
    }
}

Java

@Override  
public void onPurchasesUpdated(IapResult iapResult, List<PurchaseData> purchaseData) {
    if (iapResult.isSuccess() && purchaseData != null) {
        for (PurchaseData p : purchaseData) {
            if (!isValidPayload(p.getDeveloperPayload())) {
                // invalid dev payload
                return;
            }
            // A signature check is required to secure the purchased product.
            boolean validPurchase = AppSecurity.verifyPurchase(p.getOriginalJson(), p.getSignature());
            if (validPurchase) {
                if ("p50000".equals(p.getProductId())) {
                    // This state is managed by the app itself.
                } else {
                    // Grant entitlement to the user.
                    consumeItem(p);
                }
            } else {
                // Signature information is invalid.
            }
        }
    } else if (iapResult.getResponseCode() == ResponseCode.NEED_UPDATE) {
        // You need the required version of the ONE store service in the SDK.
    } else {
        // Other error codes.
    }
}

Acknowledge purchase

If ONE store IAP library v6 (SDK V19) and above is used, purchase must be acknowledged within 3 days. Otherwise, the purchase amount will be refunded.

You can acknowledge the purchase by using one of the following methods.

  • If the in-app is consumable, use PurchaseClient.consumeAsync().

  • If the in-app is not consumable, use PurchaseClient.acknowledgeAsync().

As for Monthly auto-renewal product, you need to acknowledge the purchase only for the first billing.

The PurchaseData object includes the isAcknowledged() method, which shows if the purchase is acknowledged. If you use this method before acknowledging the purchase, you can figure out if the purchase has already been acknowledged.

Consume Managed product

Managed product cannot be re-purchased until the purchased in-app is consumed.

Before

Java

PurchaseClient.ConsumeListener mConsumeListener = new PurchaseClient.ConsumeListener() {
    @Override
    public void onSuccess(PurchaseData purchaseData) {
        Log.d(TAG, "consumeAsync onSuccess, " + purchaseData.toString());
        // 상품소비 성공, 이후 시나리오는 각 개발사의 구매완료 시나리오를 진행합니다.
    }
  
    @Override
    public void onErrorRemoteException() {
        Log.e(TAG, "consumeAsync onError, 원스토어 서비스와 연결을 할 수 없습니다");
    }
  
    @Override
    public void onErrorSecurityException() {
        Log.e(TAG, "consumeAsync onError, 비정상 앱에서 결제가 요청되었습니다");
    }
  
    @Override
    public void onErrorNeedUpdateException() {
        Log.e(TAG, "consumeAsync onError, 원스토어 서비스앱의 업데이트가 필요합니다");
    }
  
    @Override
    public void onError(IapResult result) {
        Log.e(TAG, "consumeAsync onError, " + result.toString());
    }
};
  
  
int IAP_API_VERSION = 5;
PurchaseData purchaseData; // 구매내역조회 및 구매요청 후 전달받은 PurchaseData
mPurchaseClient.consumeAsync(IAP_API_VERSION, purchaseData, mConsumeListener);

After

Kotlin

// Enter the purchaseData received through onPurchasesUpdated() or onPurchasesResponse().
val params = ConsumeParams.newBuilder().setPurchaseData(purchaseData).build()
mPurchaseClient.consumeAsync(params) { iapResult, purchaseData ->
    if (iapResult.isSuccess) {
        // Process the result.
    } else if (iapResult.responseCode == ResponseCode.NEED_UPDATE) {
        // You need the required version of the ONE store service in the SDK.
    } else {
        // Other error codes.
    }
}

Java

// Enter the purchaseData received through onPurchasesUpdated() or onPurchasesResponse().
ConsumeParams params  = ConsumeParams.newBuilder().setPurchaseData(purchaseData).build();
mPurchaseClient.consumeAsync(params, new ConsumeListener() {
    @Override
    public void onConsumeResponse(IapResult iapResult, PurchaseData purchaseData) {
        if (iapResult.isSuccess()) {
            // Process the result.
        } else if (iapResult.getResponseCode() == ResponseCode.NEED_UPDATE) {
            // You need the required version of the ONE store service in the SDK.
        } else {
            // Other error codes.
        }
    }
});

Change Monthly auto-renewal product status

The action value received from onRecurringResponse() transmits the currently-applied value. You can check it in PurchaseClient.RecurringAction.

In addition, PurchaseData transmitted as the response result is the data received at the time of request, and therefore you need to receive once again the changed data through ‘Check purchase history’ and then you can check the changed RecurringState value.

Before

Java

PurchaseClient.ManageRecurringProductListener mManageRecurringProductListener = new PurchaseClient.ManageRecurringProductListener() {
    @Override
    public void onSuccess(PurchaseData purchaseData, String manageAction) {
        Log.d(TAG, "manageRecurringProductAsync onSuccess, " + manageAction + " " + purchaseData.toString());
    }
  
    @Override
    public void onErrorRemoteException() {
        Log.e(TAG, "manageRecurringProductAsync onError, 원스토어 서비스와 연결을 할 수 없습니다");
    }
  
    @Override
    public void onErrorSecurityException() {
        Log.e(TAG, "manageRecurringProductAsync onError, 비정상 앱에서 결제가 요청되었습니다");
    }
  
    @Override
    public void onErrorNeedUpdateException() {
        Log.e(TAG, "manageRecurringProductAsync onError, 원스토어 서비스앱의 업데이트가 필요합니다");
    }
  
    @Override
    public void onError(IapResult result) {
        Log.e(TAG, "manageRecurringProductAsync onError, " + result.toString());
    }
};
  
  
int IAP_API_VERSION = 5;
PurchaseData purchaseData; // 구매내역조회 및 구매요청 후 전달받은 PurchaseData
String action = IapEnum.RecurringAction.CANCEL.getType(); // "cancel"
mPurchaseClient.manageRecurringProductAsync(IAP_API_VERSION, purchaseData, action, mManageRecurringProductListener);

After

Kotlin

// Enter the purchaseData received through onPurchasesUpdated() or onPurchasesResponse().
val params = RecurringProductParams.newBuilder()
                .setPurchaseData(purchaseData)
                .setRecurringAction(recurringAction)
                .build()
mPurchaseClient.manageRecurringProductAsync(params) { iapResult, purchaseData, action ->
    if (iapResult.isSuccess) {
        Log.d(TAG, "manageRecurringProductAsync onRecurringResponse, $action ${purchaseData?.toString()}")
         
        if (RecurringAction.CANCEL.equals(action, true)) {
            ...
        } else {
            ...
        }
 
    }
    ...
}

Java

// Enter the purchaseData received through onPurchasesUpdated() or onPurchasesResponse().
RecurringProductParams params = RecurringProductParams.newBuilder()
                                    .setPurchaseData(purchaseData)
                                    .setRecurringAction(recurringAction)
                                    .build();
mPurchaseClient.manageRecurringProductAsync(params, new RecurringProductListener() {
    @Override
    public void onRecurringResponse(IapResult iapResult, PurchaseData purchaseData, @RecurringAction String action) {
        if (iapResult.isSuccess()) {
            Log.d(TAG, "manageRecurringProductAsync onSuccess, " + action + " " + purchaseData.toString());
 
            if (RecurringAction.CANCEL.equalsIgnoreCase(action)) {
                ...
            } else {
                ...
            }
 
        ...
    }
});

Request ONE store login

In v17 SDK, you were able to receive the value with LoginFlowListener only by performing PurchaseClient.handLoginData() again with the value, which has been delivered with onActivityResult after the login request.

In v19 SDK and above, you do not need to do the task that you had implemented in onActivityResult.

Before

Java

PurchaseClient.LoginFlowListener mLoginFlowListener = new PurchaseClient.LoginFlowListener() {
    @Override
    public void onSuccess() {
        Log.d(TAG, "launchLoginFlowAsync onSuccess");
        // 개발사에서는 로그인 성공시에 대한 이후 시나리오를 지정하여야 합니다.
    }
  
    @Override
    public void onError(IapResult result) {
        Log.e(TAG, "launchLoginFlowAsync onError, " + result.toString());
    }
  
    @Override
    public void onErrorRemoteException() {
        Log.e(TAG, "launchLoginFlowAsync onError, 원스토어 서비스와 연결을 할 수 없습니다");
    }
  
    @Override
    public void onErrorSecurityException() {
        Log.e(TAG, "launchLoginFlowAsync onError, 비정상 앱에서 결제가 요청되었습니다");
    }
  
    @Override
    public void onErrorNeedUpdateException() {
        Log.e(TAG, "launchLoginFlowAsync onError, 원스토어 서비스앱의 업데이트가 필요합니다");
    }
  
};
  
  
int IAP_API_VERSION = 5;
int LOGIN_REQUEST_CODE = 2000; // onActivityResult 로 전달받을 request code
  
mPurchaseClient.launchLoginFlowAsync(IAP_API_VERSION, "호출Activity".this, LOGIN_REQUEST_CODE, mLoginFlowListener);

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.e(TAG, "onActivityResult resultCode " + resultCode);
  
    switch (requestCode) {
        case LOGIN_REQUEST_CODE:
 
            /*
             * launchLoginFlowAsync API 호출 시 전달받은 intent 데이터를 handleLoginData를 통하여 응답값을 파싱합니다.
             * 파싱 이후 응답 결과를 launchLoginFlowAsync 호출 시 넘겨준 LoginFlowListener 를 통하여 전달합니다.
             */
 
            if (resultCode == Activity.RESULT_OK) {
                if (mPurchaseClient.handleLoginData(data) == false) {
                    Log.e(TAG, "onActivityResult handleLoginData false ");
                    // listener is null
                }
            } else {
                Log.e(TAG, "onActivityResult user canceled");
 
                // user canceled , do nothing..
            }
            break;
        default:
    }
}

After

Kotlin

mPurchaseClient.launchLoginFlowAsync(activity) { iapResult ->
    if (iapResult.isSuccess) {
        // You need to specify the scenario after successful login.
    }
    ...
}

Java

mPurchaseClient.launchLoginFlowAsync(activity, new IapResultListener() {
    @Override
    public void onResponse(IapResult iapResult) {
        if (iapResult.isSuccess()) {
            // You need to specify the scenario after successful login.
        }
        ...
    }
});

Install ONE store service (OSS)

In v17 SDK, the flow was disconnected after having executed AppInstaller.launchUpdateOrInstallFlow. However, in v19 SDK and above, you can receive the response when the installation of OSS is completed.

Before

Java

AppInstaller.launchUpdateOrInstallFlow(activity)

After

Kotlin

mPurchaseClient.launchUpdateOrInstallFlow(activity) { iapResult ->
    if (iapResult.isSuccess) {
        // If the installation is completed successfully,
        // you should try to reconnect with the ONE store service.
        startConnection()
    } else {
        ...
    }
}

Java

mPurchaseClient.launchUpdateOrInstallFlow(activity, new IapResultListener() {
    @Override
    public void onResponse(IapResult iapResult) {
        if (iapResult.isSuccess()) {
        // If the installation is completed successfully,
        // you should try to reconnect with the ONE store service.
            startConnection();
        } else {
            ...
        }
    }
});

Obtain market identification code

For IAP library V6 and above, the market identification code is necessary to use Server API.

You can obtain the market identification code through getStoreInfoAsync().

The following example shows how to obtain the market identification code.

Kotlin

val client: PurchaseClient = ...
val listener: StoreInfoListener = ...
 
client.getStoreInfoAsync { iapResult, storeCode ->
    // Save storecode and use it in Server to Server API.
}

Java

PurchaseClient client = ...
 
client.getStoreInfoAsync(new StoreInfoListener() {
    @Override
    public void onStoreInfoResponse(IapResult iapResult, String storeCode) {
        // Save storecode and use it in Server to Server API.
    }
});

Last updated