React-native-iap: getAvailablePurchases retorna uma matriz diferente a cada vez

Criado em 9 ago. 2019  ·  13Comentários  ·  Fonte: dooboolab/react-native-iap

Versão do react-native-iap

3.3.9 (mas também experimenta isso no 3.0.0 e antes)

Versão do react-native

0,59,9

Plataformas em que você enfrentou o erro (IOS ou Android ou ambos?)

iOS (não testado no Android)

Comportamento esperado

Mesma matriz sempre que chamo getAvailablePurchases
Mesmo comprimento de array sempre

Comportamento real

Array diferente sempre que chamo getAvailablePurchases
Comprimento diferente da matriz sempre que chamo getAvailablePurchases

Ambiente testado (emulador? Dispositivo real?)

Dispositivo real

Passos para reproduzir o comportamento

Acho que isso só é visível com muitas transações, mas não posso confirmar isso. Minha conta Sandbox tem mais de 50 transações.

handleOnPressRestore = async () => {
  return this.setState({ isLoadingRestorePurchases: true }, async () => {
    try {

      // Get the previous purchases of the current user
      const purchases = await RNIap.getAvailablePurchases();

      // Get the latest receipt from the purchases to validate
      const { transactionReceipt, productId, transactionDate } = this.getLatestPurchase(purchases);

      console.log(purchases.length, productId, transactionDate);

      // Validate the receipt on our server
      await this.props.validateSubscriptionReceipt(productId, transactionReceipt);

      // The validation result is handled in componentDidUpdate
    } catch (err) {
      throw err;
    } finally {
      this.setState({ isLoadingRestorePurchases: false });
    }
  });
}

getLatestPurchase = (purchases: RNIap.ProductPurchase[]): RNIap.ProductPurchase => {
  // First, sort the array, so the latest purchase is on top
  // https://github.com/dooboolab/react-native-iap/issues/532#issuecomment-503174711
  const sortedPurchases = purchases.sort((a, b) => b.transactionDate - a.transactionDate);

  const purchase = sortedPurchases[0];

  return purchase;
}

Com o código acima, quando pressiono "Restaurar compra", obtenho registros diferentes a cada vez:

Pressionando "Restaurar compra" 6 vezes, com uma espera entre para deixar os resultados chegarem:

// purchases.length, productId, transactionDate
9 "com.app.sub" 1565182529000
21 "com.app.sub" 1565181329000
22 "com.app.sub" 1565183001000
42 "com.app.sub" 1565183001000
53 "com.app.sub" 1565182529000
55 "com.app.sub" 1565183001000
15 "com.app.sub" 1565182529000

Eu esperaria que a matriz fosse sempre a mesma, certo? O que está acontecendo aqui?

O resultado de getAvailablePurchases() é diferente a cada vez que eu o executo

📱 iOS 🙏 help wanted 🚶🏻 stale

Comentários muito úteis

Também executei um loop em todas as transações e não fui capaz de removê-las com o finishTransactionIOS. Minhas transações são assinaturas de renovação automática.

Todos 13 comentários

Eu também estou vendo isso. O que é realmente perigoso é que existe a possibilidade de o recibo válido mais recente não constar dos resultados.

Olhando para o código deste módulo, honestamente parece um problema do lado da Apple, já que este módulo está efetivamente apenas passando por qualquer coisa que restoreCompletedTransactions() devolve

Eu me pergunto se getPurchaseHistory() é uma boa alternativa para ser usado para assinaturas. Atualmente estou usando isso como alternativa, pois me dá resultados confiáveis. Não tenho nenhuma outra compra em meu aplicativo, apenas assinaturas.

Conforme declarado nos documentos iap deste pacote, getAvailablePurchases() está falando sobre consumíveis. Uma assinatura não é um produto "consumível" ou "não consumível". É uma "assinatura auto-renovável" Então getPurchaseHistory() deve servir?

Screenshot 2019-08-16 at 18 11 13

Descobri que getPurchaseHistory () forneceu vários comprimentos de array também. Parecia que a frequência de pedidos efetuava isso. No final, descobrimos que isso não importava muito para nós, uma vez que qualquer um dos recibos da transação foi enviado para validação, todos os recibos foram devolvidos pela Apple no array latest_receipt_info qualquer maneira, o que é tudo o que importa para nós.

Estou tendo o mesmo problema (não sei se é um erro do modo sandbox). Além disso, quando eu mudo o ID da apple em um dispositivo real, a compra feita com outra conta é devolvida.

Ex:
1 - Fiz uma compra com a conta [email protected]
2 - ID da apple alterado para
3 - getAvailablePurchases retorna o transactionId da compra feita com a conta [email protected]

Outro problema que descobri é que se eu restaurar o dispositivo (redefinição de fábrica), os dois métodos getPurchaseHistory() e getAvailablePurchases fornecem resultados aleatórios

A resposta da Apple para restaurar uma compra é:

"Users restore transactions to maintain access to content they've already purchased. For example, when they upgrade to a new phone, they don't lose all of the items they purchased on the old phone. Include some mechanism in your app to let the user restore their purchases, such as a Restore Purchases button."

Encontrado um tópico dos Fóruns de Desenvolvedores da Apple sobre os resultados variáveis ​​de restoreCompletedTransactions conforme dito por @ ssg-luke anteriormente.

https://forums.developer.apple.com/thread/115242

Talvez, isso esteja relacionado:

Parece que você está se referindo a um usuário com muitas transações para as quais o aplicativo ainda não chamou o finishTransaction.
https://forums.developer.apple.com/thread/115242#thread -post-355444

Tive outras contas de sandbox no mesmo dispositivo. Então, poderiam ser as transações de contas diferentes, no mesmo dispositivo, apenas bagunçadas e não "finalizadas"?

No entanto, executei um loop em todas as transações e chamei finishTransactionIOS em todas elas. Mas isso não os fez desaparecer ou resultou em uma saída confiável de getAvailablePurchases() ... Talvez porque eu já esteja em uma conta de sandbox mais recente e as transações sejam de uma conta de sandbox mais antiga?

Também poderia explicar o que o @fcandiani experimenta.

Descobri que getPurchaseHistory () forneceu vários comprimentos de array também. Parecia que a frequência de pedidos efetuava isso. No final, descobrimos que isso realmente não importava para nós, uma vez que qualquer um dos recibos da transação foi enviado para validação, todos os recibos foram devolvidos pela Apple no array latest_receipt_info de qualquer maneira que é tudo o que importou para nós.

Obrigado pela informação @ ssg-luke, vou fazer o mesmo.

Também executei um loop em todas as transações e não fui capaz de removê-las com o finishTransactionIOS. Minhas transações são assinaturas de renovação automática.

Enfrentando quase o mesmo. Estava criando um problema, mas resolvi colocar aqui todas as informações para ajudar outras pessoas a encontrar o problema e a solução.

Versão do react-native-iap

3.5.9

Versão do react-native

0,60,5

Plataformas em que você enfrentou o erro (IOS ou Android ou ambos?)

iOS

  • O mesmo código está funcionando perfeitamente no Android, já em produção

Comportamento esperado

Usuário inscrito uma vez , getAvailablePurchases deve devolver apenas uma compra

Comportamento real

getAvailablePurchases está devolvendo mais de uma compra,

Ambiente testado (emulador? Dispositivo real?)

Dispositivo real com nova conta sandbox.

Passos para reproduzir o comportamento

  • Crie um usuário de teste sandbox em https://appstoreconnect.apple.com/access/testers
  • Construir e executar projeto no xcode
  • Chame getAvailablePurchases , não retorna nenhuma compra (como esperado)
  • Inscreva-se em algum produto
  • meu purchaseUpdatedListener é chamado, e eu chamo RNIap.finishTransactionIOS(subscription.transactionId); que retorna apenas undefined (como esperado, eu acho)
  • Ligue para getAvailablePurchases , retorna uma compra (como esperado)
  • Recarregar o aplicativo
  • Chame getAvailablePurchases , retorna duas compras , cada uma com transactionId :
{
   originalTransactionDateIOS: 1571144840000
   originalTransactionIdentifierIOS: "1000000579413333"
   productId: "io.appmasters.lowcarb.development"
   transactionDate: 1571145019000
   transactionId: "1000000579415509"
   transactionReceipt: "MIIVnQYJKoZIhvcN..."
},
{
   originalTransactionDateIOS: 1571144840000
   originalTransactionIdentifierIOS: "1000000579413333"
   productId: "io.appmasters.lowcarb.development"
   transactionDate: 1571144839000
   transactionId: "1000000579416705"
   transactionReceipt: "MIIVnQYJKoZIhvcN...."
}
  • Recarregue o aplicativo novamente
  • Chame getAvailablePurchases , retorna três compras , cada uma com transactionId (diferente do resultado anterior):
{
   originalTransactionDateIOS: 1571144840000
   originalTransactionIdentifierIOS: "1000000579413333"
   productId: "io.appmasters.lowcarb.development"
   transactionDate: 1571145739000
   transactionId: "1000000579423546"
   transactionReceipt: "MIIb1AYJKoZIhvcN..."
},{
   originalTransactionDateIOS: 1571144840000
   originalTransactionIdentifierIOS: "1000000579413333"
   productId: "io.appmasters.lowcarb.development"
   transactionDate: 1571145019000
   transactionId: "1000000579426352"
   transactionReceipt: "MIIb1AYJKoZI..."
},{
   originalTransactionDateIOS: 1571144840000
   originalTransactionIdentifierIOS: "1000000579413333"
   productId: "io.appmasters.lowcarb.development"
   transactionDate: 1571144839000
   transactionId: "1000000579426353"
   transactionReceipt: "MIIb1AYJKoZIhvcN..."
}
  • Recarregue o aplicativo novamente
  • Chame getAvailablePurchases , retorna quatro compras , cada uma com transactionId (diferente do resultado anterior) ...

Este não parece ser o comportamento correto, pelo que li na documentação e pelo que acontece no Android.

Agradeço qualquer ajuda.

getAvaialblePurchases () está retornando mais de 150 resultados em minha conta de teste do sandbox. Decidi não usar getAvailablePurchases () e apenas armazenar a última compra no dispositivo e também no servidor. Se o aplicativo for excluído ou o usuário for movido para um novo telefone, ainda teremos a última compra em nosso servidor vinculada ao ID de usuário e plataforma de nossa empresa (iOS ou Android). Chamar getAvailablePurchases () leva quase um minuto e, às vezes, chamando esse listener atualizado de compra acionadora tentando restaurar várias compras. Modificamos nosso fluxo assim:
1) Quando o usuário faz login no dispositivo:
a) veja se existe uma última compra válida em nosso servidor para o usuário e plataforma.
b) Caso não haja registro no servidor, verifique se existe alguma compra local salva no DB
c) Se não houver nenhuma ou se houver uma expirada, mostre a exibição de assinaturas.
Inicialmente, estávamos chamando getAvailablePurchases () e tentando ver se a última compra ainda era válida. Não tenho certeza se isso ajuda outras pessoas, mas não estamos mais tendo problemas com isso. Estamos reagindo 59 e essa é outra dor com a qual temos que lidar.

@ramakula e se o usuário cancelar sua assinatura?

Da forma como você disse, você manterá a assinatura em seu banco de dados até a data de término, e "verá" que não está mais disponível para compra.

Olá, parece que não houve nenhuma atividade sobre este problema recentemente. O problema foi corrigido ou ainda requer a atenção da comunidade? Este problema pode ser resolvido se nenhuma outra atividade ocorrer. Você também pode rotular esse problema como "Para discussão" ou "Bom primeiro problema" e eu o deixarei em aberto. Obrigado por suas contribuições.

Encerrando este problema após um período prolongado de inatividade. Se esse problema ainda estiver presente na versão mais recente, sinta-se à vontade para criar um novo problema com informações atualizadas.

getAvaialblePurchases () está retornando mais de 150 resultados em minha conta de teste do sandbox. Decidi não usar getAvailablePurchases () e apenas armazenar a última compra no dispositivo e também no servidor. Se o aplicativo for excluído ou o usuário for movido para um novo telefone, ainda teremos a última compra em nosso servidor vinculada ao ID de usuário e plataforma de nossa empresa (iOS ou Android). Chamar getAvailablePurchases () leva quase um minuto e, às vezes, chamando esse listener atualizado de compra acionadora tentando restaurar várias compras. Modificamos nosso fluxo assim:

  1. Quando o usuário faz login no dispositivo:
    a) veja se existe uma última compra válida em nosso servidor para o usuário e plataforma.
    b) Caso não haja registro no servidor, verifique se existe alguma compra local salva no DB
    c) Se não houver nenhuma ou se houver uma expirada, mostre a exibição de assinaturas.
    Inicialmente, estávamos chamando getAvailablePurchases () e tentando ver se a última compra ainda era válida. Não tenho certeza se isso ajuda outras pessoas, mas não estamos mais tendo problemas com isso. Estamos reagindo 59 e essa é outra dor com a qual temos que lidar.

Acredito que podemos obter as compras mais recentes no recibo. Ao verificar o recebimento de um usuário, com exclude-old-transactions: true, podemos obter as informações de assinatura mais recentes (apenas para tipo auto-renovável). Acredito que podemos usar esse método para restaurar as compras de assinaturas auto-renováveis. Não tenho certeza se este é um método ideal.

Esta página foi útil?
0 / 5 - 0 avaliações