Exploração do esquema e processo de processamento de compras no aplicativo iOS

prefácio

As compras no aplicativo, relacionadas à receita real, geralmente são a principal prioridade de todas as empresas e também a principal prioridade de nossos desenvolvedores. Portanto, hoje discutiremos o conteúdo das compras no aplicativo dos mais importantes. O simples processo de compra no aplicativo é concluído passo a passo através do processamento de cada cena especial. Se você acha que é muito longo, assista a parte final

Compra básica no aplicativo

Logo no início do artigo, simulamos um cenário mais básico de processamento de compras in-app, ou seja, para garantir que o processo normal seja creditado na conta e, em seguida, fizemos otimizações subsequentes de acordo com diferentes cenários.

O processo básico de compra no aplicativo é o seguinte:

Processo do cliente:

graph LR
用户充值 --> 下单传递userId --> 下单成功 --> 充值 --> 苹果返回成功 --> 上报凭证传递userId --> 收到成功回调 --> 关闭交易事务

Processo do lado do servidor:

Para fazer um pedido:

graph LR
接收客户端下单信息 --> 订单信息入库 --> 返回订单号

Documentos de relatório:

graph LR
接收客户端上报凭证 --> 找苹果校验成功 --> 返回客户端成功 --> 客户端关闭交易事务
找苹果校验成功 --> 通过userId查找对应的订单 --> 充值到账并写入凭证的transactionId 

Diagrama de interação bem-sucedida:

Devido ao conteúdo excessivo do diagrama de interação, apenas o processo de interação do processo bem-sucedido é exibido temporariamente.

sequenceDiagram
用户->>客户端: 点击充值
客户端->>服务端: 下单(带userId)
服务端->>服务端: 订单入库
服务端-->>客户端: 下单成功
客户端->>苹果: 调用充值接口
苹果-->>用户: 充值操作
用户->>苹果: 充值完成
苹果-->>客户端: 回调充值成功
客户端->>服务端: 上报凭证(带userId)
服务端->>苹果: 调用凭证验证接口
苹果-->>服务端: 凭证验证合法
服务端-->>客户端: 上报成功
客户端-->>用户: 提示充值成功
服务端->>服务端: 通过userId查询订单信息
服务端->>服务端: 充值到账并写入凭证的transactionId 

problema e analise

No processo de uso de compras básicas no aplicativo, o problema mais comum é o problema anormal causado pela troca de conta.

Cenário 1: alternar contas entre recargas

Ambiente da cena:

Um dispositivo, duas contas de login A e B.

Processo de exceção:

A conta A faz um pedido de recarga e, quando a recarga é concluída e a Apple não retorna, ela muda para a conta B e o certificado passa a ser informado por B.

situação real:

No jogo, os gerentes do sindicato precisam trocar de conta com frequência, ou trocar a conta do trompete para realizar operações diferentes. Após a recarga normal, se o usuário não perceber o status da conta e trocar de conta diretamente, essa situação pode ocorrer .

Desempenho anormal:

  1. Se verificar o registro do pedido neste momento. Ou seja, ele consultará o pedido anterior feito pelo userId antes e descobrirá que o pedido não foi feito antes e não pode ser recebido, resultando em pedido perdido.
  2. Se o registro do pedido não for verificado neste momento e a conta B for verificada diretamente após a verificação direta, haverá uma sequência de pedidos.

solução:

Usando o esquema de bloqueio do ID do dispositivo (IDFV), apenas um pedido pode existir para cada dispositivo e cada ID de mercadoria no processo completo. Ao relatar o voucher, o pedido é recuperado de acordo com o ID do dispositivo e creditado na conta.

Desbloqueie a atualização da cena:

Desbloqueie a cena
Apple retorna sucesso e relata sucesso do certificado
Apple retorna falha de recarga

Atualização do processo:

Processo do cliente:


graph LR
用户充值 --> 下单传递IDFV --> 下单成功 --> 充值 --> 苹果返回成功 --> 上报凭证传递IDFV --> 收到成功回调 --> 关闭交易事务
充值 --> 苹果返回失败 --> 上报失败信息(传递IDFV) --> 收到接收回调 --> 关闭交易事务

Processo do lado do servidor:


Para fazer um pedido:

graph LR
接收客户端下单信息 --> 查找订单列表中对应设备id是否存在加锁的订单
查找订单列表中对应设备id是否存在加锁的订单 --> 存在加锁订单 --> 返回锁单中
查找订单列表中对应设备id是否存在加锁的订单 --> 不存在加锁订单 --> 创建订单并入库 --> 订单置为锁单状态 -->  返回订单号

Documentos de relatório:

graph LR
接收客户端上报凭证 --> 找苹果校验成功 --> 返回客户端成功 --> 客户端关闭交易事务
找苹果校验成功 --> 通过设备id查找对应的订单 --> 充值到账
通过设备id查找对应的订单 --> 订单解锁并写入凭证的transactionId 

Falha ao relatar:

graph LR
接收客户端上报失败信息 --> 通过设备id查找对应的订单 --> 订单解锁 --> 返回接受成功
接收客户端上报失败信息 --> 失败信息写入日志

Diagrama interativo de recarga bem-sucedida:


sequenceDiagram
用户->>客户端: 点击充值
客户端->>服务端: 下单(带IDFV)
服务端->>服务端: 订单入库并加锁
服务端-->>客户端: 下单成功
客户端->>苹果: 调用充值接口
苹果-->>用户: 充值操作
用户->>苹果: 充值完成
苹果-->>客户端: 回调充值成功
客户端->>服务端: 上报凭证(带IDFV)
服务端->>苹果: 调用凭证验证接口
苹果-->>服务端: 凭证验证合法
服务端-->>客户端: 上报成功
客户端-->>用户: 提示充值成功
服务端->>服务端: 通过IDFV查询订单信息
服务端->>服务端: 订单解锁并写入凭证的transactionId 
服务端->>服务端: 充值到账

Cenário 2: desbloqueie a exceção

Ambiente da cena:

Durante o processo de recarga, feche o aplicativo e cancele o pagamento

Processo de exceção:

Depois que o usuário fizer o pedido e o processo de recarga, feche o aplicativo e cancele o pagamento. Neste ponto, a Apple não retorna mais nenhuma informação de pagamento.

Desempenho anormal:

Como a Apple não retornou nenhuma informação, o servidor não desbloqueou o pedido, portanto, não pode ser recarregado antes de desinstalar e reinstalar.

situação real:

O usuário pode simplesmente clicar para recarregar por engano. Para evitar a recarga bem sucedida, o aplicativo pode ser fechado diretamente e a recarga será cancelada. Esta situação ocorrerá neste momento.

solução:

在唤起充值之后,如果未返回过充值成功,则在下次服务端返回充值失败时,可以假定用户充值失败,则直接进行解锁操作。

解锁场景更新:

解锁场景
苹果返回成功并上报凭证成功
苹果返回充值失败
重启应用后的首次下单返回锁定,且苹果未返回充值信息

流程更新:

客户端流程:


graph LR
用户充值 --> 下单传递IDFV --> 下单成功 --> 充值 --> 苹果返回成功 --> 上报凭证传递IDFV --> 收到成功回调 --> 关闭交易事务
充值 --> 苹果返回失败 --> 上报失败信息(传递IDFV) --> 收到接收回调 --> 关闭交易事务
下单传递IDFV --> 返回锁单中 --> 判断为打开应用后首次下单 --> 上报苹果未返回  --> 收到上报回调 --> 下单传递IDFV

其余流程无需更新

场景三:卸载重装无法到账

场景环境:

一台设备,充值过程中卸载重装应用

异常流程:

账号下单充值,充值完成且在苹果未返回的情况下,卸载重装应用,此时凭证上报时候的设备id发生了变化,导致无法找到设备ID对应的订单。(如果使用保存在 keychain 中的 idfv,则恢复出厂设置时也将无法获取到之前保存的 idfv)

现实场景:

用户在充值之后,可能由于网络问题,暂时无法到账,瞬间弃坑删除应用,再过一段时间的冷静期后,又重新继续下载应用,此时就会出现该情况

解决方案:

上报凭证时候有两种地方获取,一个是旧的直接通过 transactionData 获取, 一种是官方推荐的 NSBundle 中获取。我们需要优化的点在于两处内容同时上报,解析 transactionData 时,可以获取到 UniqueVendorIdentifier ,这个与发起充值时候的 IDFV 的值是相同的,我们就可以针对这点来做订单的关联,并使用bundle中的凭证信息做安全相关的检验。(实际上,直接使用 transactionData 中的数据也是可以的,目前通过苹果验证后的暂未发现异常情况)

流程更新:

服务端流程:


上报凭证:

graph LR
接收客户端上报凭证 --> 找苹果校验成功 --> 返回客户端成功 --> 客户端关闭交易事务
找苹果校验成功 --> 提取凭证中的UniqueVendorIdentifier --> 查找对应的订单 --> 充值到账并写入凭证的transactionId 
查找对应的订单 --> 订单解锁

其余流程无需更新

场景四:充值成功但是到账慢

情况有多种,但是表现类似,就放一起讨论 环境场景:

  1. 设备本身网络较慢
  2. 服务器与苹果链接慢
  3. 服务端异常导致入库失败

异常流程:

  1. 玩家本身网络慢,导致苹果返回充值成功之后,上报凭证服务端超时,按照正常流程则需要苹果再次下发充值成功才会再次上报,间隔时间长。
  2. 服务器找苹果校验凭证信息,接口调用时间过长导致超时,返回客户端失败,从而等待下次上报
  3. 服务器本身出现异常(内存满了、发布中等)导致入库异常,返回客户端失败等待重新上报

现实情况:

电梯中或者高铁上玩手机进行充值,时常会有信号不好的时候,此时即为该情况

解决方案:

  1. 客户端收到苹果下发的充值成功信息后,保存凭证到内存中再进行上报凭证到服务端的操作,上报成功后移除对应凭证信息,上报失败则进行延迟重试处理
  2. 服务端收到上报的凭证时,入库成功后则直接返回成功给客户端,然后再调用苹果接口校验凭证是否合法,如果发生超时情况,则延后进行重试。

更新的流程放在结尾处

结尾

以上为旧版 storekit 所使用的方案,在目前已知情况下除了苹果自身多次扣款,其余情况都能保证充值的正常到账。新版的 storeKit 可以直接使用 appAccountToken 进行关联。如果有其他情况,欢迎一起讨论

完整解锁场景

解锁场景
苹果返回成功并上报凭证成功
苹果返回充值失败
重启应用后的首次下单返回锁定,且苹果未返回充值信息

完整流程

客户端流程:


graph LR
用户充值 --> 下单传递IDFV --> 下单成功 --> 充值 --> 苹果返回成功 --> 保存凭证信息 --> 上报凭证 --> 收到成功回调 --> 关闭交易事务 --> 移除保存的凭证
上报凭证 --> 收到异常回调 --> 延时30s --> 上报凭证
充值 --> 苹果返回失败 --> 上报失败信息(传递IDFV) --> 收到接收回调 --> 关闭交易事务
下单传递IDFV --> 返回锁单中 --> 判断为打开应用后首次下单 --> 上报苹果未返回  --> 收到上报回调 --> 下单传递IDFV

服务端流程:


下单:

graph LR
接收客户端下单信息 --> 查找订单列表中对应设备id是否存在加锁的订单
查找订单列表中对应设备id是否存在加锁的订单 --> 存在加锁订单 --> 返回锁单中
查找订单列表中对应设备id是否存在加锁的订单 --> 不存在加锁订单 --> 创建订单并入库 --> 订单置为锁单状态 -->  返回订单号

上报凭证:

graph LR
接收客户端上报凭证 --> 请求苹果凭证校验接口 --> 苹果校验返回成功 --> 返回客户端成功 --> 客户端关闭交易事务
苹果校验返回成功 --> 提取凭证中的UniqueVendorIdentifier --> 查找对应的订单 --> 充值到账并写入凭证的transactionId 
查找对应的订单 --> 订单解锁
请求苹果凭证校验接口 --> 找苹果校验超时 --> 延时30s --> 请求苹果凭证校验接口

上报失败:

graph LR
接收客户端上报失败信息 --> 通过设备id查找对应的订单 --> 订单解锁 --> 返回接受成功
接收客户端上报失败信息 --> 失败信息写入日志

充值成功交互图:


sequenceDiagram
用户->>客户端: 点击充值
客户端->>服务端: 下单(带 IDFV)
服务端->>服务端: 订单入库并加锁
服务端-->>客户端: 下单成功
客户端->>苹果: 调用充值接口
苹果-->>用户: 充值操作
用户->>苹果: 充值完成
苹果-->>客户端: 回调充值成功
客户端->>服务端: 上报凭证
服务端->>苹果: 调用凭证验证接口
苹果-->>服务端: 凭证验证合法
服务端-->>客户端: 上报成功
客户端-->>用户: 提示充值成功
服务端->>服务端: 通过凭证获取的UniqueVendorIdentifier查询订单信息
服务端->>服务端: 订单解锁并写入凭证的transactionId 
服务端->>服务端: 充值到账

FAQ

  1. 多次扣款时如何补发给用户?

这种情况由于是极少数情况,只能定位到多次扣款的那个订单信息,并定位确认最近的订单,并跟用户确认后手动补发

  1. 如何验证重复上报凭证

上报凭证时候,先判断凭证的 transactionId 是否已存在,如果已存在则说明已上报过,直接返回成功即可

  1. 是否要做其他的限制

凭证验证成功后,查询订单时,查询凭证充值时间前的订单即可,并确认解析后的包名是否正确,如果需要的话,可以考虑查询到过早的订单时,不进行到账处理并预警该订单


Acho que você gosta

Origin juejin.im/post/7118770506702012453
Recomendado
Clasificación