This section describes how to develop an app that has HUAWEI IAP integrated, helping you quickly understand IAP APIs your app can call and how to call them.
Before using HUAWEI IAP in your app, send an isEnvReady request to HMS Core (APK) to check whether the currently signed-in HUAWEI ID is located in the country/region where HUAWEI IAP is available.
If your app does not connect to the HUAWEI ID sign-in API, use the isEnvReady API to sign in first.
Perform the following steps for your development:
Send an isEnvReady request and set two callback listeners to receive the request result.
If the result code is OrderStatusCode.ORDER_HWID_NOT_LOGIN (no HUAWEI ID signed in), use the getStatus method of the IapApiException object to obtain a Status object, and use the startResolutionForResult method of this Status object to bring up the HUAWEI ID sign-in screen. Then, obtain the result in the onActivityResult method of Activity. Parse returnCode from the intent returned by onActivityResult. If the value of returnCode is OrderStatusCode.ORDER_STATE_SUCCESS, the country/region where the currently signed-in HUAWEI ID is located supports IAP. Otherwise, an exception occurs.
Java
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
Task<IsEnvReadyResult> task = Iap.getIapClient(activity).isEnvReady();
task.addOnSuccessListener(new OnSuccessListener<IsEnvReadyResult>() {
@Override
public void onSuccess(IsEnvReadyResult result) {
// Obtain the execution result.
String carrierId = result.getCarrierId();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
if (status.getStatusCode() == OrderStatusCode.ORDER_HWID_NOT_LOGIN) {
// HUAWEI ID is not signed in.
if (status.hasResolution()) {
try {
// 6666 is a constant defined by yourself.
// Open the sign-in screen returned.
status.startResolutionForResult(activity, 6666);
} catch (IntentSender.SendIntentException exp) {
}
}
} else if (status.getStatusCode() == OrderStatusCode.ORDER_ACCOUNT_AREA_NOT_SUPPORTED) {
// The current country/region does not support HUAWEI IAP.
}
} else {
// Other external errors.
}
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 6666) {
if (data != null) {
// Call the parseRespCodeFromIntent method to obtain the result of the API request.
int returnCode = IapClientHelper.parseRespCodeFromIntent(data);
}
}
} Kotlin
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
val task = Iap.getIapClient(activity).isEnvReady
task.addOnSuccessListener { result ->
// Obtain the execution result.
val carrierId = result.carrierId
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
if (status.getStatusCode() === OrderStatusCode.ORDER_HWID_NOT_LOGIN) {
// HUAWEI ID is not signed in.
if (status.hasResolution()) {
try {
// 6666 is a constant defined by yourself.
// Open the sign-in screen returned.
status.startResolutionForResult(activity, 6666)
} catch (exp: SendIntentException) {
}
}
} else if (status.getStatusCode() === OrderStatusCode.ORDER_ACCOUNT_AREA_NOT_SUPPORTED) {
// The current country/region does not support HUAWEI IAP.
}
} else {
// Other external errors.
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 6666) {
if (data != null) {
// Call the parseRespCodeFromIntent method to obtain the result of the API request.
val returnCode = IapClientHelper.parseRespCodeFromIntent(data)
}
}
} To show products configured in AppGallery Connect to your users, call the obtainProductInfo API in your app to obtain details of these products.
Perform the following steps for your development:
Java
List<String> productIdList = new ArrayList<>();
// Only those products already configured in AppGallery Connect can be queried.
productIdList.add("ConsumeProduct1001");
ProductInfoReq req = new ProductInfoReq();
// priceType: 0: consumable; 1: non-consumable; 2: subscription
req.setPriceType(0);
req.setProductIds(productIdList);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the obtainProductInfo API to obtain the details of the product configured in AppGallery Connect.
Task<ProductInfoResult> task = Iap.getIapClient(activity).obtainProductInfo(req);
task.addOnSuccessListener(new OnSuccessListener<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
// Obtain the product details returned upon a successful API call.
List<ProductInfo> productList = result.getProductInfoList();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
}
}); Kotlin
val productIdList: MutableList<String> = ArrayList()
// Only those products already configured in AppGallery Connect can be queried.
productIdList.add("ConsumeProduct1001")
val req = ProductInfoReq()
// priceType: 0: consumable; 1: non-consumable; 2: subscription
req.setPriceType(0)
req.productIds = productIdList
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
// Call the obtainProductInfo API to obtain the details of the product configured in AppGallery Connect.
val task = Iap.getIapClient(activity).obtainProductInfo(req)
task.addOnSuccessListener { result ->
// Obtain the product details returned upon a successful API call.
val productList = result.getProductInfoList()
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val returnCode = apiException.statusCode
} else {
// Other external errors.
}
} AppGallery Connect allows for purchases of consumables, non-consumables, and subscriptions. Your app can send a purchase request by calling the createPurchaseIntent API. Perform the following steps for your development:
Java
// Construct a PurchaseIntentReq object.
PurchaseIntentReq req = new PurchaseIntentReq();
// Only those products already configured in AppGallery Connect can be purchased through the createPurchaseIntent API.
req.setProductId("CProduct1");
// priceType: 0: consumable; 1: non-consumable; 2: subscription
req.setPriceType(0);
req.setDeveloperPayload("test");
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the createPurchaseIntent API to create a managed product order.
Task<PurchaseIntentResult> task = Iap.getIapClient(activity).createPurchaseIntent(req);
task.addOnSuccessListener(new OnSuccessListener<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
// Obtain the order creation result.
Status status = result.getStatus();
if (status.hasResolution()) {
try {
// 6666 is a constant defined by yourself.
// Open the checkout screen returned.
status.startResolutionForResult(activity, 6666);
} catch (IntentSender.SendIntentException exp) {
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
}
}); Kotlin
// Construct a PurchaseIntentReq object.
val req = PurchaseIntentReq()
// Only those products already configured in AppGallery Connect can be purchased through the createPurchaseIntent API.
req.setProductId("CProduct1")
// priceType: 0: consumable; 1: non-consumable; 2: subscription
req.setPriceType(0)
req.setDeveloperPayload("test")
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
// Call the createPurchaseIntent API to create a managed product order.
val task = Iap.getIapClient(activity).createPurchaseIntent(req)
task.addOnSuccessListener { result ->
// Obtain the order creation result.
val status: Status = result.status
if (status.hasResolution()) {
try {
// 6666 is a constant defined by yourself.
// Open the checkout screen returned.
status.startResolutionForResult(activity, 6666)
} catch (exp: SendIntentException) {
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// Other external errors.
}
}
You can use the InAppPurchaseData class of the IAP SDK to parse an InAppPurchaseData string to generate an InAppPurchaseData object from which you can obtain relevant information.
Java
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 6666) {
if (data == null) {
Log.e("onActivityResult", "data is null");
return;
}
// Call the parsePurchaseResultInfoFromIntent method to parse the payment result.
PurchaseResultInfo purchaseResultInfo = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data);
switch(purchaseResultInfo.getReturnCode()) {
case OrderStatusCode.ORDER_STATE_CANCEL:
// The user cancels the purchase.
break;
case OrderStatusCode.ORDER_STATE_FAILED:
case OrderStatusCode.ORDER_STATE_DEFAULT_CODE:
case OrderStatusCode.ORDER_PRODUCT_OWNED:
// Check whether the delivery is successful.
break;
case OrderStatusCode.ORDER_STATE_SUCCESS:
// The payment is successful.
String inAppPurchaseData = purchaseResultInfo.getInAppPurchaseData();
String inAppPurchaseDataSignature = purchaseResultInfo.getInAppDataSignature();
// Verify the signature using your app's IAP public key.
// If the verification is successful, check the consistency of the information including productId, price, and currency in InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step. If relevant information is consistent, deliver the product.
// Call the consumeOwnedPurchase API to consume the product after delivery if the product is a consumable.
break;
default:
break;
}
}
} Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 6666) {
if (data == null) {
Log.e("onActivityResult", "data is null")
return
}
// Call the parsePurchaseResultInfoFromIntent method to parse the payment result.
val purchaseResultInfo = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data)
when (purchaseResultInfo.returnCode) {
OrderStatusCode.ORDER_STATE_CANCEL -> {
}
OrderStatusCode.ORDER_STATE_FAILED, OrderStatusCode.ORDER_PRODUCT_OWNED, OrderStatusCode.ORDER_STATE_DEFAULT_CODE -> {
}
OrderStatusCode.ORDER_STATE_SUCCESS -> {
// The payment is successful.
val inAppPurchaseData = purchaseResultInfo.inAppPurchaseData
val inAppPurchaseDataSignature = purchaseResultInfo.inAppDataSignature
}
else -> {
}
}
}
} After a user pays for a purchase, your app checks whether the payment is successful based on the purchaseState field in InAppPurchaseData. If purchaseState is 0 (already paid), your app will deliver the purchased product or service to the user, and then send a delivery confirmation request to HUAWEI IAP.
After the consumable is successfully delivered and its purchaseToken is obtained, your app needs to use the consumeOwnedPurchase API to consume the product and tell the Huawei IAP server to update the delivery status of the consumable. purchaseToken is passed in the request to call the consumeOwnedPurchase API. If the consumption is successful, the IAP server will reset the product status to available for purchase. Then, the user can buy it again.
Java
// Construct a ConsumeOwnedPurchaseReq object.
ConsumeOwnedPurchaseReq req = new ConsumeOwnedPurchaseReq();
String purchaseToken = "";
try {
// Obtain purchaseToken from InAppPurchaseData.
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
purchaseToken = inAppPurchaseDataBean.getPurchaseToken();
} catch (JSONException e) {
}
req.setPurchaseToken(purchaseToken);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the consumeOwnedPurchase API to consume the product after delivery if the product is a consumable.
Task<ConsumeOwnedPurchaseResult> task = Iap.getIapClient(activity).consumeOwnedPurchase(req);
task.addOnSuccessListener(new OnSuccessListener<ConsumeOwnedPurchaseResult>() {
@Override
public void onSuccess(ConsumeOwnedPurchaseResult result) {
// Obtain the execution result.
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
}
}); Kotlin
// Construct a ConsumeOwnedPurchaseReq object.
val req = ConsumeOwnedPurchaseReq()
var purchaseToken = ""
try {
// Obtain purchaseToken from InAppPurchaseData.
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
purchaseToken = inAppPurchaseDataBean.purchaseToken
} catch (e: JSONException) {
}
req.setPurchaseToken(purchaseToken)
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
// Call the consumeOwnedPurchase API to consume the product after delivery if the product is a consumable.
val task = Iap.getIapClient(activity).consumeOwnedPurchase(req)
task.addOnSuccessListener {
// Obtain the execution result.
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// Other external errors.
}
} If your app provides non-consumables for users, it can call the obtainOwnedPurchases API during app launch to obtain the data about non-consumables that a user has purchased. For the data format, please refer to the description of InAppPurchaseData. If any purchase data is returned, confirm the purchaseState field of each purchase. If the value of purchaseState is 0, your app needs to deliver the product.
Perform the following steps for your development:
You can use the InAppPurchaseData class of the IAP SDK to parse an InAppPurchaseData string to generate an InAppPurchaseData object from which you can obtain relevant information.
Java
// Construct an OwnedPurchasesReq object.
OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
// Set priceType to 1 (non-consumable).
ownedPurchasesReq.setPriceType(1);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the obtainOwnedPurchases API.
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// Obtain the execution result.
if (result != null && result.getInAppPurchaseDataList() != null) {
for (int i = 0; i < result.getInAppPurchaseDataList().size(); i++) {
String inAppPurchaseData = result.getInAppPurchaseDataList().get(i);
String inAppSignature = result.getInAppSignature().get(i);
// Use the IAP public key to verify the signature of inAppPurchaseData.
// If the verification is successful, check the consistency of the information including productId, price, and currency in InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step.
// If relevant information is consistent between HUAWEI IAP and your app, check the payment state.
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
int purchaseState = inAppPurchaseDataBean.getPurchaseState();
} catch (JSONException e) {
}
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
}
}); Kotlin
// Construct an OwnedPurchasesReq object.
val ownedPurchasesReq = OwnedPurchasesReq()
// Set priceType to 1 (non-consumable).
ownedPurchasesReq.setPriceType(1)
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
// Call the obtainOwnedPurchases API.
val task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq)
task.addOnSuccessListener { result ->
// Obtain the execution result.
if (result != null && result.getInAppPurchaseDataList() != null) {
for (i in result.getInAppPurchaseDataList().indices) {
val inAppPurchaseData = result.getInAppPurchaseDataList()[i]
val inAppSignature = result.getInAppSignature()[i]
// Use the IAP public key to verify the signature of inAppPurchaseData.
// If the verification is successful, check the consistency of the information including productId, price, and currency in InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step.
// If relevant information is consistent between HUAWEI IAP and your app, check the payment state.
try {
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
val purchaseState = inAppPurchaseDataBean.purchaseState
} catch (e: JSONException) {
}
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// Other external errors.
}
} Before your app offers services of a subscription, check its status first.
To do this, your app needs to obtain purchase data InAppPurchaseData in either of the following ways:
For some subscriptions (such as video memberships), users have access to services or content only of the current active period, that is, only when purchaseState is 0 and InApppurchaseData.subIsvalid is true.
Perform the following steps for your development:
Java
// Construct an OwnedPurchasesReq object.
OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
// Set priceType to 2 (subscription).
ownedPurchasesReq.setPriceType(2);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the obtainOwnedPurchases API.
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// Obtain the execution result.
if (result != null && result.getInAppPurchaseDataList() != null) {
for (int i = 0; i < result.getInAppPurchaseDataList().size(); i++) {
String inAppPurchaseData = result.getInAppPurchaseDataList().get(i);
String inAppSignature = result.getInAppSignature().get(i);
// Use the IAP public key to verify the signature of inAppPurchaseData.
// If the verification is successful, check the consistency of the information including productId, price, and currency in InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step.
// If relevant information is consistent between HUAWEI IAP and your app, check the payment state and subscription state.
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
int purchaseState = inAppPurchaseDataBean.getPurchaseState();
boolean isSubValid = inAppPurchaseDataBean.isSubValid();
} catch (JSONException e) {
}
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
}
}); Kotlin
// Construct an OwnedPurchasesReq object.
val ownedPurchasesReq = OwnedPurchasesReq()
// Set priceType to 2 (subscription).
ownedPurchasesReq.setPriceType(2)
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
// Call the obtainOwnedPurchases API.
val task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq)
task.addOnSuccessListener { result ->
// Obtain the execution result.
if (result != null && result.getInAppPurchaseDataList() != null) {
for (i in result.getInAppPurchaseDataList().indices) {
val inAppPurchaseData = result.getInAppPurchaseDataList()[i]
val inAppSignature = result.getInAppSignature()[i]
// Use the IAP public key to verify the signature of inAppPurchaseData.
// If the verification is successful, check the consistency of the information including productId, price, and currency in InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step.
// If relevant information is consistent between HUAWEI IAP and your app, check the payment state and subscription state.
try {
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
val purchaseState = inAppPurchaseDataBean.purchaseState
val isSubValid = inAppPurchaseDataBean.isSubValid
} catch (e: JSONException) {
}
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// Other external errors.
}
} For some subscriptions, users always have access to services or content that has been offered to them in all the previous periods and also the current active period. A typical example is magazine subscription. Users can access all magazines that they have purchased in the past or currently. If your app requires the subscription renewal data of previous periods, query the receipts of all subscriptions through IapClient.obtainOwnedPurchaseRecord. The receipt format is the same as that in InAppPurchaseData.
If a subscription is in purchased state and the validity period of the subscription matches the valid service provisioning period of your app server, the subscription-related services must be provided.
For all subscriptions, your app determines whether to provide services in this way.
Call obtainOwnedPurchaseRecord to obtain the data of all consumed products of a user. For subscriptions, you can call this API to obtain users' subscription receipts.
Java
// Construct an OwnedPurchasesReq object.
OwnedPurchasesReq req = new OwnedPurchasesReq();
// Set priceType to 0 (consumable) or 2 (subscription).
req.setPriceType(0);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the obtainOwnedPurchaseRecord API.
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchaseRecord(req);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// Obtain the execution result.
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
}
}); Kotlin
// Construct an OwnedPurchasesReq object.
val req = OwnedPurchasesReq()
// Set priceType to 0 (consumable) or 2 (subscription).
req.setPriceType(0)
// Obtain the Activity object that calls the API.
val activity: Activity = getActivity()
// Call the obtainOwnedPurchaseRecord API.
val task = Iap.getIapClient(activity).obtainOwnedPurchaseRecord(req)
task.addOnSuccessListener {
// Obtain the execution result.
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val returnCode = apiException.statusCode
} else {
// Other external errors.
}
}