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
V5 (SDK V17)
V6(SDK V19)
Connect to billing module
connect
startConnection
Disconnect with billing module
terminate
endConnection
Check support status
isBillingSupportedAsync
X
Purchase in-app
launchPurchaseFlowAsync
launchPurchaseFlow
Consume in-app
consumeAsync
consumeAsync
Acknowledge in-app purchase
X
acknowledgeAsync
Purchase history of unconsumed in-app
(including monthly automatic payment)
queryPurchasesAsync
queryPurchasesAsync
In-app product details
queryProductsAsync
queryProductDetailsAsync
Change monthly automatic payment status
manageRecurringProductAsync
manageRecurringProductAsync
Update or install billing module
launchUpdateOrInstallFlow
launchUpdateOrInstallFlow
Call ONE store login
launchLoginFlowAsync
launchLoginFlowAsync
Check market identification code
X
getStoreInfoAsync
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.
<application> ... <meta-data android:name="iap:api_version"
android:value="5"/> ...</application>
Add IAP V19 SDK library
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
Export the global-appstores.json file into the โassetsโ folder.
3. Add the following line to the dependency section of the app's build.gradle file.
dependencies { ... implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])}
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