华为HarmonyOS应用内支付服务 -- 1 接入购买

场景介绍

在应用内购买场景中,用户会采用一次性付款的方式购买消耗型商品或非消耗型商品。请结合实际业务场景选择提供的商品类型。

在接入消耗型/非消耗型商品购买能力前,需要提前配置商品信息。用户在应用内购买时,应用拉起IAP Kit的收银台,收银台处会展示商品名称、商品价格等信息,用户根据需求完成商品购买。

业务流程

说明

如下业务流程对于单机应用同样适用。在单机应用中,应用服务器和应用客户端的交互放在应用客户端完成,应用服务器和IAP服务器交互的部分可不处理。

展示商品

  1. 应用客户端向IAP Kit发起queryEnvironmentStatus请求,检查当前用户登录的华为账号所在的服务地是否在IAP Kit支持结算的国家/地区中。

    如请求失败,应用需隐藏相关IAP功能入口。

  2. 应用客户端向IAP Kit发起queryProducts请求来获取在AppGallery Connect上配置的商品信息。
  3. 应用客户端根据返回的商品信息展示可供购买的商品列表,包含商品名称、价格等信息。

购买及结果确认

  1. 用户发起购买后,应用客户端向IAP Kit发起createPurchase购买请求,请求中携带商品ID、商品类型等信息。IAP Kit创建订单并展示收银台。
  2. 购买结果确认。如购买成功,可通过应用客户端或应用服务器接收购买结果,建议通过应用服务器接收购买结果。方式一:通过客户端接收购买结果
    1. 用户购买成功时,IAP Kit返回包含订单信息的PurchaseData数据。
    2. 应用客户端向应用服务器上报PurchaseData数据。
    3. 应用服务器需对PurchaseData.jwsPurchaseOrder进行解码验签,成功后可得到PurchaseOrderPayload的JSON字符串。
    (建议)方式二:通过服务器接收购买结果
    1. 为了提高安全性,开发者可以接入服务端关键事件通知,在用户购买成功时,IAP服务器将发送订单关键事件通知。
    2. 应用服务器可从NotificationPayload.NotificationMetaData中解析出purchaseToken和purchaseOrderId信息,并通过服务端订单状态查询接口向IAP服务器查询最新的订单信息,进一步确认订单的准确性。
    3. IAP服务器返回订单信息jwsPurchaseOrder
    4. 应用服务器需对jwsPurchaseOrder进行解码验签,成功后可得到PurchaseOrderPayload的JSON字符串。

说明

如果购买失败,请参见权益发放处理,及时发放权益。

发放权益

  1. 确认购买成功后,需要处理权益发放。检查当前PurchaseOrderPayload是否已发放权益,未发放则发放相关权益,并记录对应的订单信息(PurchaseOrderPayload),用于后续检查权益发放状态。
  2. 应用客户端向应用服务器查询订单的发货状态。
  3. 应用服务器返回对应的发货状态以及订单信息(PurchaseOrderPayload)。
  4. 发货成功后应用客户端向IAP Kit发送finishPurchase请求,以此通知IAP服务器更新商品的发货状态,完成购买流程。

    应用成功执行此步骤后,IAP服务器会将相应商品标记为已发货状态。对于消耗型商品,IAP服务器会将相应商品重新设置为可购买状态,用户即可再次购买该商品。对于非消耗型商品,用户购买后永久拥有,无法再次购买该商品。

    说明

    此步骤也可放到应用服务器处理。应用服务器可通过请求服务端订单确认发货接口来确认发货,完成购买流程。

    确保在发货成功之后再执行此步骤,否则可能导致IAP服务器已经确认发货但是应用没有发货的问题。

开发步骤

展示商品

  1. 检查应用引入IAP Kit的可用性。

    在使用应用内支付之前,应用客户端需要向IAP Kit发送queryEnvironmentStatus请求,以此判断用户当前登录的华为账号所在的服务地是否在IAP Kit支持结算的国家/地区中。如请求失败,则隐藏相关IAP功能入口。

    说明

    当前IAP Kit支持结算的国家/地区仅有中国大陆。

     
      
    1. import { iap } from '@kit.IAPKit';
    2. import { common } from '@kit.AbilityKit';
    3. import { BusinessError } from '@kit.BasicServicesKit';
    4. queryEnvironmentStatus() {
    5. const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    6. iap.queryEnvironmentStatus(context).then(() => {
    7. // 请求成功
    8. console.info('Succeeded in querying environment status.');
    9. }).catch((err: BusinessError) => {
    10. // 请求失败
    11. console.error(`Failed to query environment status. Code is ${err.code}, message is ${err.message}`);
    12. });
    13. }
  1. 展示商品列表。

    应用客户端通过queryProducts来获取在AppGallery Connect上配置的商品信息。发起请求时,需在请求参数QueryProductsParameter中携带相关的商品ID,并根据实际配置指定其商品类型productType。

    当接口请求成功时,IAP Kit将返回商品信息Product的列表。 应用可以使用Product包含的商品价格、名称和描述等信息,向用户展示可供购买的商品列表。

    说明

    queryProducts每次只能查询一种商品类型的商品,每次最多查询200个商品,否则请求将报错。

     
      
    1. import { iap } from '@kit.IAPKit';
    2. import { common } from '@kit.AbilityKit';
    3. import { BusinessError } from '@kit.BasicServicesKit';
    4. queryProducts() {
    5. const queryProductParam: iap.QueryProductsParameter = {
    6. // iap.ProductType.CONSUMABLE:消耗型商品
    7. // iap.ProductType.NONCONSUMABLE:非消耗型商品
    8. productType: iap.ProductType.CONSUMABLE,
    9. // productIds中的商品需要替换成开发者在AppGallery Connect网站配置的商品
    10. productIds: ['ohos_consume_001']
    11. };
    12. const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    13. iap.queryProducts(context, queryProductParam).then((result) => {
    14. // 请求成功
    15. console.info('Succeeded in querying products.');
    16. // 展示商品信息
    17. // ...
    18. }).catch((err: BusinessError) => {
    19. // 请求失败
    20. console.error(`Failed to query products. Code is ${err.code}, message is ${err.message}`);
    21. });
    22. }

发起购买

用户发起购买时,应用客户端向IAP Kit发送createPurchase请求来拉起IAP Kit收银台。发起请求时,需在请求参数PurchaseParameter中携带此前已在华为AppGallery Connect网站上配置并生效的商品ID,并根据实际配置指定其productType。

说明

开发过程中易出现频繁调用接口的现象,建议控制接口调用频度,具体可参见1001860004 接口访问过频

 
  1. import { iap } from '@kit.IAPKit';
  2. import { common } from '@kit.AbilityKit';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. createPurchase() {
  5. const createPurchaseParam: iap.PurchaseParameter = {
  6. // iap.ProductType.CONSUMABLE:消耗型商品
  7. // iap.ProductType.NONCONSUMABLE:非消耗型商品
  8. productType: iap.ProductType.CONSUMABLE,
  9. // productId需要替换成开发者在AppGallery Connect网站配置商品信息时设置的“商品ID”
  10. productId: 'ohos_consume_001'
  11. };
  12. const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  13. iap.createPurchase(context, createPurchaseParam).then(async (result) => {
  14. console.info('Succeeded in creating purchase.');
  15. // 购买成功,处理购买结果
  16. // dealPurchaseResult实现请参见下一步
  17. this.dealPurchaseResult(result);
  18. }).catch((err: BusinessError) => {
  19. // 购买失败
  20. console.error(`Failed to create purchase. Code is ${err.code}, message is ${err.message}`);
  21. // dealPurchaseError实现请参见下一步
  22. this.dealPurchaseError(err);
  23. })
  24. }

购买结果处理

【结果1:购买成功】

  1. 当用户购买成功时,应用客户端将接收到一个CreatePurchaseResult对象,其purchaseData字段包括了此次购买的结果信息。

    说明

    为了提高安全性,建议应用服务器接入服务端关键事件通知以接收购买成功结果。

  2. purchaseData.jwsPurchaseOrder进行解码验签,验证成功可得到PurchaseOrderPayload的JSON字符串。建议应用客户端将purchaseData发送至应用服务器,在应用服务器执行此操作。
  3. 验签成功后,如果PurchaseOrderPayload.purchaseOrderRevocationReasonCode为空,则代表购买成功,即可发放相关权益。

    建议先检查此笔订单权益的发放状态,未发放则发放权益,成功后记录PurchaseOrderPayload等信息,用于后续检查权益发放状态。

  4. 完成购买。

    说明

    请务必确保发货成功后再执行本步骤。本步骤也可放到应用服务器处理。应用服务器可通过请求服务端订单确认发货接口来确认发货,完成购买流程。

    发放权益后,应用客户端需要发送finishPurchase请求确认发货,以此通知IAP服务器更新商品的发货状态,完成购买流程。发送finishPurchase请求时,需在请求参数FinishPurchaseParameter中携带PurchaseOrderPayload中的productType、purchaseToken、purchaseOrderId。

    应用成功执行此步骤后,IAP服务器会将相应商品标记为已发货状态。对于消耗型商品,IAP服务器会将相应商品重新设置为可购买状态,用户即可再次购买该商品。对于非消耗型商品,用户购买后永久拥有,无法再次购买该商品。

     
      
    1. import { iap } from '@kit.IAPKit';
    2. import { common } from '@kit.AbilityKit';
    3. import { BusinessError } from '@kit.BasicServicesKit';
    4. // JWTUtil为自定义类,可参见示例代码
    5. import { JWTUtil } from '../common/JWTUtil';
    6. dealPurchaseResult(result: iap.CreatePurchaseResult) {
    7. const jwsPurchaseOrder: string = JSON.parse(result.purchaseData).jwsPurchaseOrder;
    8. if (!jwsPurchaseOrder) {
    9. return;
    10. }
    11. // 对jwsPurchaseOrder进行解码验签
    12. const purchaseStr = JWTUtil.decodeJwtObj(jwsPurchaseOrder);
    13. // 需自定义PurchaseOrderPayload类,包含的信息请参见PurchaseOrderPayload
    14. const purchaseOrderPayload = JSON.parse(purchaseStr) as PurchaseOrderPayload;
    15. // 处理发货
    16. // ...
    17. // 发货成功后向IAP Kit发送finishPurchase请求,确认发货,完成购买
    18. // finishPurchase请求的参数来源于purchaseOrderPayload
    19. this.finishPurchase(purchaseOrderPayload);
    20. }
    21. /**
    22. * 确认发货,完成购买
    23. *
    24. * @param purchaseOrder 订单信息,来源于购买请求
    25. */
    26. finishPurchase(purchaseOrder: PurchaseOrderPayload) {
    27. const finishPurchaseParam: iap.FinishPurchaseParameter = {
    28. productType: purchaseOrder.productType,
    29. purchaseToken: purchaseOrder.purchaseToken,
    30. purchaseOrderId: purchaseOrder.purchaseOrderId
    31. };
    32. const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    33. iap.finishPurchase(context, finishPurchaseParam).then(() => {
    34. // 请求成功
    35. console.info('Succeeded in finishing purchase.');
    36. }).catch((err: BusinessError) => {
    37. // 请求失败
    38. console.error(`Failed to finish purchase. Code is ${err.code}, message is ${err.message}`);
    39. });
    40. }

【结果2:购买失败】

当用户购买失败时,需要针对code为iap.IAPErrorCode.PRODUCT_OWNEDiap.IAPErrorCode.SYSTEM_ERROR的场景,检查是否需要补发货,确保权益发放,具体请参见权益发放

 
  1. import { iap } from '@kit.IAPKit';
  2. import { BusinessError } from '@kit.BasicServicesKit';
  3. dealPurchaseError(err: BusinessError) {
  4. if (err.code === iap.IAPErrorCode.PRODUCT_OWNED || err.code === iap.IAPErrorCode.SYSTEM_ERROR) {
  5. // 参见权益发放检查是否需要补发货,确保权益发放
  6. // ...
  7. }
  8. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青瓷代码世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值