---
title: "安卓应用内购买，第4部分：Billing Library Error Codes以及如何避免搞砸测试"
description: "在本教程中，我们将仔细研究Google Play Billing Library中与应用内购买相关的错误，并看看是什么原因导致了这些错误"
url: "https://adapty.io/zh/blog/android-in-app-purchases-part-4-billing-library-error-codes-and-how-not-to-fail-testing/"
language: "zh"
slug: "android-in-app-purchases-part-4-billing-library-error-codes-and-how-not-to-fail-testing"
category: "adapty-updates"
date: "2021-09-29T00:00:00.000Z"
date_modified: "2021-09-29T00:00:00.000Z"
author: "Vlad Guriev"
---

# 安卓应用内购买，第4部分：Billing Library Error Codes以及如何避免搞砸测试

今天我们将讨论我们可以从[getResponseCode()](https://developer.android.com/reference/com/android/billingclient/api/BillingResult#getResponseCode%28))法的Billing Library中获得的[错误代码](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode)。

您可以在[本文](https://adapty.io/blog/android-in-app-purchases-google-play-billing-library-part-2/)中找到我们如何将错误传递给回调函数的示例。我们已经在之前的文章中讨论过一个错误——当用户没有进行任何购买就关闭购买对话框时，就是[**USER_CANCELED**](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#USER_CANCELED)。我们来了解一下其他的吧。

## ERROR和DEVELOPER_ERROR

让我们从名为[**ERROR**](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ERROR)（responseCode 6）和[**DEVELOPER_ERROR**](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#DEVELOPER_ERROR)（ responseCode 5）的错误开始吧。对于第一种情况，Google在文档中写了“API操作过程中的致命错误”，对于第二种情况——“提供给API的无效参数”。例如，当我为[querySkuDetailsAsync()](https://developer.android.com/reference/com/android/billingclient/api/SkuDetailsParams.Builder#setType%28java.lang.String))请求传递一个空字符串给[setType()](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querySkuDetailsAsync%28com.android.billingclient.api.SkuDetailsParams,%20com.android.billingclient.api.SkuDetailsResponseListener))中的构建器时，我能够得到一个DEVELOPER_ERROR。

但事情没那么简单。我更近了一步，在[launchBillingFlow()](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#launchBillingFlow%28android.app.Activity,%20com.android.billingclient.api.BillingFlowParams))法中，我使用了修改后的[SkuDetails](https://developer.android.com/reference/com/android/billingclient/api/SkuDetails)（从实际产品的SkuDetails中提取json，更改其中的productID并将其传递给新的SkuDetails构造器）。事实上，这是一个无效参数，我希望得到一个**DEVELOPER_ERROR**，但是……我得到了一个 **ERROR**。

当然，这是一个人工例子。Google拒绝支付的情况更接近现实。如果您从一个测试卡测试购买时，在购买对话框选择“测试卡，总是拒绝”，我们将在文章的最后告诉您，**ERROR** 也将返回，但具有正确的文本。

在[第三篇](https://adapty.io/blog/android-in-app-purchases-part-3-retrieving-active-purchases-and-subscription-change/)文章中，我们描述了订阅（subscription）变化，我们将其中一种比例模式的年订阅价格提高了近3倍，但没有说明如果我们没有这么做会出现什么错误。我们正在进行修改。

因为这里指定了错误的比例模式，所以在逻辑上我们应该得到相同的**DEVELOPER_ERROR**。相反，我们得到了[**SERVICE_UNAVAILABLE**](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#SERVICE_UNAVAILABLE)（responseCode 2）。如果我们输入任何不适当的数字作为比例模式（这是int，不是enum，没人会阻止我们），或者如果我们明确指出错误的purchaseToken，我们也会得到这个。我们看了 **SERVICE_UNAVAILABLE** 的文档，然后……等等，什么？！我们看到了“网络连接中断。”

与此同时，我们也看到了一个奇怪的对话框：

![](https://adapty.io/wp-content/uploads/2023/03/615371cbae3a194fdd67617c_5n7uqaw9bx5dejwxgqh9sluv3r38yqwegbzbnzj5db9bullr12o2uraffoyko2jn4pjwhsy04xwdwrwxt37pkvgt3q1zgtblivzbagg-91v1ogagpaptqj-av1kdmoqhe96kwy4x3ds0-5.jpg)

在**ERROR** 的情况下，另一个有趣的现象是，当**不** 通过“OK”键关闭对话框（即，通过被解释为“导航返回”的方法）时，**ERROR** 来到[onPurchasesUpdated()](https://developer.android.com/reference/com/android/billingclient/api/PurchasesUpdatedListener#onPurchasesUpdated%28com.android.billingclient.api.BillingResult,%20java.util.List%3Ccom.android.billingclient.api.Purchase%3E))，而在**SERVICE_UNAVAILABLE** 的情况下，类似的情况出现的是**USER_CANCELED**（但如果您在对话框中点“OK”，我们将收到 **SERVICE_UNAVAILABLE**，正如预期的那样）。

在失去互联网连接的情况下，确实会出现**SERVICE_UNAVAILABLE**。

## 错误代码

这里还有一些带有小注释的错误代码，可以说是比较罕见的错误。

- [BILLING_UNAVAILABLE](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#BILLING_UNAVAILABLE)（responseCode 3）。Google解释说“Billing API版本不支持请求的类型”。当我退出Google账户，以及使用没有Google Play Services的华为设备时，我能够重现这个错误。它也可能在Google Play没有更新的旧手机上进行复制。
- [SERVICE_DISCONNECTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#SERVICE_DISCONNECTED)（responseCode -1）。应用程序有时会与Google Play服务断开连接。如果安卓市场意外更新，这种情况就会发生。因此，我建议您谨慎行事，在每次调用Billing Library方法之前进行连接，就像前几篇文章中介绍的那样。此外，如果响应中仍然出现此错误，[Google](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#SERVICE_DISCONNECTED)和我们都建议您添加一些重试策略。
- [SERVICE_TIMEOUT](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#SERVICE_TIMEOUT)（responseCode -3）。这个名字不言而喻——我们已经等待Google Play的响应太久了。
- [FEATURE NOT SUPPORTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#FEATURE_NOT_SUPPORTED)。BillingClient类中有5个[FeatureType](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.FeatureType)常量。它们在这个设备上的可用性可以使用[BillingClient.isFeatureSupported(BillingClient.FeatureType.A_NECESSARY_FEATURE)](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#isFeatureSupported%28java.lang.String))方法来检查。在我的手机（小米Mi A2 Lite）上，**FEATURE_NOT_SUPPORTED** 只返回了**SUBSCRIPTIONS_ON_VR**。同时，对于 **IN_APP_ITEMS_ON_VR** 以及所有其他特性，OK已返回。
- [ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_NOT_OWNED)（responseCode 8）。它会在我们试图消费一件我们没有的东西时发生。可能会，甚至多次成功消费后也会。
- [ITEM_ALREADY_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_ALREADY_OWNED)（responseCode 7）。而这里，恰恰相反，错误发生在试图购买我们已经拥有的产品时。在这种情况下，您只需要更新用户界面并让购买按钮不可点击即可。

## ITEM_UNAVAILABLE

在应用内购买实现路径开始的最后一个可能也是最常见的错误就是[**ITEM_UNAVAILABLE**](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_UNAVAILABLE)（responseCode 4）。它说该产品无法购买，但没有解释原因。原因可能非常不同：从在错误的账户或设备上测试到购买不活跃的产品。

以下是您在测试时需要做的避免这种错误的清单：

1. 将一个带有Billing Library的应用程序发送到您的测试轨道。这是一个强制性条件；同时，您也可以使用相同的applicationId在调试构建上进行测试，但有一点很重要，至少把Billing Library的应用程序上传到Play Console一次。
2. 将测试人员的Google账号添加到测试轨道中，这对于内部测试或封闭的阿尔法/贝塔测试尤为重要。在*测试人员如何加入您的测试* 部分也会有一个链接，测试人员应该在那里接受邀请。
3. 您只能购买已激活的产品。创建一个产品后，在Play Console有一个***“激活”***按钮。我们在[第一篇文章](https://adapty.io/blog/android-in-app-subscriptions/)中更详细地描述了创建产品的过程。
4. 请确保设备上的测试是从测试人员的Google账户进行的（这意味着它必须注册为测试轨道的测试人员，必须拥有所有必要的技术访问权限）。这一点似乎很明显，但世事难料，如果收到这样的错误，您也需要检查这一点。
5. 用于购买测试构建的applicationId必须完全匹配来自Play Console的applicationId。对于那些在调试版本中已经添加后缀的来说，这一点尤其重要。
6. 将测试人员的电子邮件地址添加到账户左侧菜单的*Setup → License Testing* 部分（而不是应用程序），这样他们就可以从测试卡上免费购买产品，而不是从真实的卡上购买产品。在这种情况下，订阅的另一个优点是有一个[测试持续时间](https://developer.android.com/google/play/billing/test#renewals)。它与这个错误无关，但也是有用的知识。

## 结论

错误会使工作变得非常复杂，所以了解它们是如何发生的一直很重要。考虑到需要经过多少步骤才能访问产品，最简单的方法就是捕获ITEM_UNAVAILABLE。因此，我希望我的清单可以帮到您。

[Adapty软件开发工具包（SDK）](https://adapty.io/sdk/android/)将促进错误处理，并提供许多其他优势：基本订阅分析、群组分析（cohort analysis）、付费墙（paywall）的简单测试、与分析服务的整合、服务器错误验证。现在就试试吧！
