1

IAP沙盒测试中,消耗品和非消耗品购买一次后不能再购买。结果,支付页面无法显示。onActivityResult中,IAP SDK返回代码

ORDER_PRODUCT_OWNED 60051

这是一个普遍的问题还是我做错了什么?

4

3 回答 3

3

错误代码60051表示用户未能购买产品,因为用户已经拥有该产品。

解决方法:使用obtainOwnedPurchases接口查看用户是否购买了商品。

对于已购买的消耗品,发货后调用consumeOwnedPurchase接口进行消耗。食用后可下次购买。如果产品是非消耗品或订阅产品,则无法再次购买该产品。

查询所有已购买的应用内商品信息,包括消耗品、非消耗品和自动续订订阅。

  • 如果返回耗材信息,可能会因为某些异常导致耗材无法送达。在这种情况下,您的应用需要检查耗材是否已送达。如果没有,则应用需要交付它们并调用 consumeOwnedPurchase API 来消费它们。
  • 如果返回非消耗品信息,则不需要消耗非消耗品。
  • 如果返回订阅信息,则返回用户在应用中的所有现有订阅关系。
  • 如果 purchaseState 为0,则表示产品已购买
  • 如果 purchaseState 为1,则表示产品为CANCELED
  • 如果 purchaseState 为2,则表示产品为PURCHASED

代码:

public void checkUserOwnedTheProduct(final Context context) {
        OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
        ownedPurchasesReq.setPriceType(productType);
        Task<OwnedPurchasesResult> task = Iap.getIapClient(context).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);
                        boolean success = CipherUtil.doCheck(inAppPurchaseData, inAppSignature, Key.getPublicKey());
                        if (success) {
                            try {
                                InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
                                int purchaseState = inAppPurchaseDataBean.getPurchaseState();                            

                            } catch (JSONException e) {
                            }
                        }
                    }
                } else {
                    if (productType == IapClient.PriceType.IN_APP_NONCONSUMABLE) {
                        ((HmsInAppPurchaseList) context).loadList();
                        return;
                    }
                }
            }
        }).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
                }
            }
        });
    }

有关更多信息,您可以访问以下链接: 应用内购买文章:

客户端: https ://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201255229704010231&fid=0101187876626530001

服务器端: https ://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201273064244120101&fid=0101187876626530001

应用内购买 Github 链接:

客户端: https ://github.com/DTSE-India-Community/HMS-In-App-Purchase-Kit

服务器端: https ://github.com/DTSE-India-Community/Huawei-In-App-Purchase-And-Push-Kit-Server_Side-Implementation

于 2020-07-27T16:20:39.643 回答
2

60051 表示用户购买产品失败,因为用户已经拥有该产品。@Disavowed 给出了解释和解决方案。 https://developer.huawei.com/consumer/en/doc/development/HMS-References/iap-ExceptionHandlingAndGeneralErrorCodes-v4

这是有关如何使用该产品的代码。

/**
 * Consume the unconsumed purchase with type 0 after successfully delivering the product, then the Huawei payment server will update the order status and the user can purchase the product again.
 * @param inAppPurchaseData JSON string that contains purchase order details.
 */
private void consumeOwnedPurchase(final Context context, String inAppPurchaseData) {
    Log.i(TAG, "call consumeOwnedPurchase");
    IapClient mClient = Iap.getIapClient(context);
    Task<ConsumeOwnedPurchaseResult> task = mClient.consumeOwnedPurchase(createConsumeOwnedPurchaseReq(inAppPurchaseData));
    task.addOnSuccessListener(new OnSuccessListener<ConsumeOwnedPurchaseResult>() {
        @Override
        public void onSuccess(ConsumeOwnedPurchaseResult result) {
            // Consume success
            Log.i(TAG, "consumeOwnedPurchase success");
            Toast.makeText(context, "Pay success, and the product has been delivered", Toast.LENGTH_SHORT).show();
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(Exception e) {
            Log.e(TAG, e.getMessage());
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
            if (e instanceof IapApiException) {
                IapApiException apiException = (IapApiException)e;
                Status status = apiException.getStatus();
                int returnCode = apiException.getStatusCode();
                Log.e(TAG, "consumeOwnedPurchase fail,returnCode: " + returnCode);
            } else {
                // Other external errors
            }

        }
    });
}

/**
 * Create a ConsumeOwnedPurchaseReq instance.
 * @param purchaseData JSON string that contains purchase order details.
 * @return ConsumeOwnedPurchaseReq
 */
private ConsumeOwnedPurchaseReq createConsumeOwnedPurchaseReq(String purchaseData) {

    ConsumeOwnedPurchaseReq req = new ConsumeOwnedPurchaseReq();
    // Parse purchaseToken from InAppPurchaseData in JSON format.
    try {
        InAppPurchaseData inAppPurchaseData = new InAppPurchaseData(purchaseData);
        req.setPurchaseToken(inAppPurchaseData.getPurchaseToken());
    } catch (JSONException e) {
        Log.e(TAG, "createConsumeOwnedPurchaseReq JSONExeption");
    }

    return req;
}
于 2020-07-27T09:38:55.333 回答
1

在沙盒环境中,您可以购买消耗品和非消耗品。购买后,您可以食用它们。之后,您可以再次购买它们以方便测试。

调用消费接口来消费产品。

于 2020-07-23T10:26:42.047 回答