目录

Purchase Implementation

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.

Checking the Support for HUAWEI IAP

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.

Showing Products

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:

  1. Construct a ProductInfoReq object, send an obtainProductInfo request, and set callback listeners OnSuccessListener and OnFailureListener to receive the request result. Pass the product ID that has been defined and taken effect in AppGallery Connect to the ProductInfoReq object, and specify priceType for a product.

    Only one type of product can be queried by each call of obtainProductInfo.

  2. If the request is successful, IAP will return a ProductInfoResult object. Using the getProductInfoList method of this object, your app can obtain the list of ProductInfo objects, each of which contains the information about a product, including the price, name, and description. Based on the information, the list of products that are available for purchase will be shown to users.

    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.
        }
    }

Initiating a Purchase

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:

  1. Construct a PurchaseIntentReq object to send a createPurchaseIntent request. Pass the product ID that has been defined and taken effect in AppGallery Connect to the PurchaseIntentReq object. If the request is successful, your app will receive a PurchaseIntentResult object, and its getStatus method will return a Status object. Your app will display the checkout screen of HUAWEI IAP using the startResolutionForResult method of the Status object.

    The Status object does not support serialization. Please do not serialize the Status object returned by IAP APIs.

    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.
        }
    }

  2. After your app opens the checkout screen of HUAWEI IAP and the user completes the payment process (that is, successfully purchases a product or cancels the purchase), HUAWEI IAP will return the payment result to your app through onActivityResult. You can use the parsePurchaseResultInfoFromIntent method to obtain the PurchaseResultInfo object that contains the result information.

    • For a successful purchase, you can obtain InAppPurchaseData and its signature from the PurchaseResultInfo object. Then, use the IAP public key given to your app by AppGallery Connect to verify the signature. 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. For details about how to get the public key and perform verifications, please refer to (Mandatory) Verifying InAppPurchaseData.

      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.

    • When a user purchases a consumable, if any of the following payment exceptions is returned, check whether the delivery is successful. For details, please refer to (Mandatory) Redelivery Process for Consumables.
      • Payment failure (OrderStatusCode.ORDER_STATE_FAILED).
      • A user has purchased the product (OrderStatusCode.ORDER_PRODUCT_OWNED).
      • The default code is returned (OrderStatusCode.ORDER_STATE_DEFAULT_CODE), as no specific code is available.
        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 -> {
                    }
                }
            }
        }

Confirming a Purchase

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.

Delivering a Non-Consumable

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:

  1. Call obtainOwnedPurchases to obtain the data of non-consumables that a user has purchased.
  2. Specify priceType as 1 in OwnedPurchasesReq.
  3. Check the consistency of the information including productId, price, and currency in each InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step to make sure that the product that a user has successfully paid for can be delivered to the user as expected. Find relevant instructions in (Mandatory) Verifying InAppPurchaseData.
  4. If relevant information is consistent between HUAWEI IAP and your app, parse purchaseState from each InAppPurchaseData to check the payment state. If the payment is successful, deliver the product.

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.
    }
}

Offering Services of a Subscription

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:

  1. Call obtainOwnedPurchases to obtain the data of subscriptions that a user has purchased. Specify priceType as 2 in OwnedPurchasesReq.
  2. Check the consistency of the information including productId, price, and currency in each InAppPurchaseData between HUAWEI IAP and your app. This is a mandatory step to make sure that the product that a user has successfully paid for can be delivered to the user as expected. Find relevant instructions in (Mandatory) Verifying InAppPurchaseData.
  3. If relevant information is consistent between HUAWEI IAP and your app, parse purchaseState and subIsvalid from each InAppPurchaseData to check the payment state. If the payment is successful, deliver the product.
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.

(Optional) Viewing the Purchase History

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.
    }
}