HarmonyOS 鸿蒙Next中沙盒状态下如何测试非消耗型内购的恢复

HarmonyOS 鸿蒙Next中沙盒状态下如何测试非消耗型内购的恢复 沙盒测试购买非消耗商品后,完成iap.finishPurchase发货,查询iap.queryPurchases购买的情况时候,没有任何购买记录,我现在有一个问题,我想测试一下用户卸载app,后重新安装,如何恢复之前购买的非消耗型内购呢?正式的环境下,卸载重装能否通过 iap.queryPurchases 查询到购买记录。沙盒状态下我如何测试非消耗性内购的恢复呢?

5 回复

沙盒环境下 finishPurchase后查询无记录是特意设计的便利机制,不影响正式环境的购买恢复。测试恢复流程时,可通过暂不发货来模拟已购状态,并模拟重装行为验证查询结果。

在沙盒环境中模拟“卸载重装后恢复购买”的场景,可参考以下步骤:

  • 暂停调用 finishPurchase:在沙盒测试中购买非消耗型商品后,暂不调用 iap.finishPurchase。这样,订单会保持“已购买未发货”状态,后续通过 iap.queryPurchases仍能查询到该购买记录,从而模拟正式环境中已购商品的可恢复状态。
  • 模拟重装行为:您可以通过清除应用数据或重新安装应用(使用调试签名包)来模拟用户卸载重装的操作。重新启动应用后,调用 iap.queryPurchases检查是否能查询到之前购买的商品记录。
  • 利用沙盒账号管理:请注意,沙盒账号的购买历史记录可通过AppGallery Connect后台“清除购买历史记录”功能完全删除,该操作不可逆。若需长期测试恢复流程,建议避免使用此功能,或专门保留一个测试账号用于恢复场景。

更多关于HarmonyOS 鸿蒙Next中沙盒状态下如何测试非消耗型内购的恢复的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这是沙盒环境和正式环境的行为差异,不代表正式环境无法恢复。非消耗型商品在正式环境中,用户卸载重装或换设备后,应用启动时可以调用 iap.queryPurchases 查询已购非消耗型商品,再按查询结果恢复权益。

沙盒里调用 finishPurchase 后查不到,主要是为了方便开发者重复购买同一个非消耗商品做测试。也就是说,沙盒中“已发货完成”的非消耗订单可能不会继续作为可恢复购买返回。

测试恢复流程可以分两步:

  1. 购买成功后先不要调用 finishPurchase,保持订单处于可查询状态,再重装应用或清数据后调用 queryPurchases 验证恢复逻辑。
  2. 业务代码仍要按正式流程实现:购买成功、服务端验签/发货、记录权益、完成后调用 finishPurchase;应用冷启动时再查本地权益和 queryPurchases 结果做兜底恢复。

【解决方案】

  1. 目前非消耗性商品在沙盒状态下调用finishPurchase接口是便于下次可以重新购买,因为非消耗性商品正常情况下只能购买一次。沙盒提供该机制是为了能够方便开发者不用多次创建商品或者更换系统账号进行再次测试,若需要获取到购买数据,可以在沙盒环境下不调用finishPurchase接口。iap.finishPurchase在已购商品的发货后进行调用来指明此次购买流程结束。而iap.queryPurchases返回已购商品的订单信息,在沙盒场景下已发货状态的非消耗型商品订单信息将不返回。

  2. 正式环境中为了在应用卸载重装、更换设备安装等场景下保障用户权益,需要在应用首次打开时,应用客户端向IAP Kit发起queryPurchases请求,查询用户已购非消耗型商品,完成权益恢复。

在鸿蒙Next沙盒环境下,调用IAP Kit的restorePurchases接口,使用沙盒测试账号登录后即可触发恢复流程。系统将返回该账号所有非消耗型商品的购买记录,核对purchaseToken即可恢复相应权益。

沙盒下无法查到已购非消耗品记录,通常是因为错误地对非消耗型商品调用了 finishPurchase。该方法仅用于消耗型商品,调用后购买记录就会被消耗,导致 queryPurchases 返回空。

正确做法:非消耗型商品购买成功后不要调用 finishPurchase,系统会持久化保存该记录。此时无论卸载重装还是更换设备,只要使用同一华为账号登录沙盒环境,queryPurchases 都能查到该商品,即可实现恢复。正式环境与此逻辑一致。

沙盒测试恢复流程示例(ArkTS):

iap.queryPurchases({ purchaseType: iap.PurchaseType.NONCONSUMABLE })
  .then((data) => {
    if (data.purchaseList.length > 0) {
      // 存在非消耗品记录,进行发货/恢复
      for (let purchase of data.purchaseList) {
        // 验证 purchase.productId 并处理业务恢复逻辑
      }
    }
  });

购买成功后只需记录订单,无需消耗:

iap.purchaseProduct({ productId: 'your_nonconsumable_id', purchaseType: iap.PurchaseType.NONCONSUMABLE })
  .then((result) => {
    // 购买成功,记录订单,切勿调用 finishPurchase
  });

若已在沙盒误调用 finishPurchase,只能换用新沙盒账号重新测试。

回到顶部