React-native-iap: getAvailablePurchases renvoie un tableau différent à chaque fois

Créé le 9 août 2019  ·  13Commentaires  ·  Source: dooboolab/react-native-iap

Version de react-native-iap

3.3.9 (mais expérimente également cela dans 3.0.0 et avant)

Version de react-native

0,59,9

Plateformes sur lesquelles vous avez rencontré l'erreur (IOS ou Android ou les deux?)

iOS (non testé sur Android)

Comportement attendu

Même tableau à chaque fois que j'appelle getAvailablePurchases
Même longueur de tableau à chaque fois

Comportement réel

Tableau différent à chaque fois que j'appelle getAvailablePurchases
Différentes longueurs de tableau à chaque fois que j'appelle getAvailablePurchases

Environnement testé (émulateur? Real Device?)

Appareil réel

Étapes pour reproduire le comportement

Je pense que cela n'est visible qu'avec beaucoup de transactions, mais je ne peux pas le confirmer. Mon compte Sandbox a plus de 50 transactions.

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;
}

Avec le code ci-dessus, lorsque j'appuie sur "Restaurer l'achat", j'obtiens des journaux différents à chaque fois:

En appuyant sur «Restaurer l'achat» 6 fois, avec une attente entre les deux pour laisser entrer les résultats:

// 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

Je m'attendrais à ce que le tableau soit toujours le même, non? Qu'est-ce qu'il se passe ici?

Le résultat de getAvailablePurchases() est différent à chaque fois que je l'exécute

📱 iOS 🙏 help wanted 🚶🏻 stale

Commentaire le plus utile

J'ai également exécuté une boucle sur toutes les transactions et je n'ai pas pu les supprimer avec finishTransactionIOS. Mes transactions sont des abonnements à renouvellement automatique.

Tous les 13 commentaires

Je vois aussi cela. Ce qui est vraiment dangereux, c'est qu'il est possible que le reçu valide le plus récent ne figure pas dans les résultats.

En regardant ce code de modules, cela ressemble honnêtement à un problème du côté d'Apple, car ce module ne fait que passer par tout ce que restoreCompletedTransactions() rend

Je me demande si getPurchaseHistory() est une bonne alternative à utiliser pour les abonnements. J'utilise actuellement cela comme alternative, car cela me donne des résultats fiables. Je n'ai pas d'autres achats dans mon application, uniquement des abonnements.

Comme indiqué dans la documentation iap sur ce package, getAvailablePurchases() parle de consommables. Un abonnement n'est pas un produit «consommable» ou «non consommable». C'est un "abonnement auto-renouvelable" Donc getPurchaseHistory() devrait faire?

Screenshot 2019-08-16 at 18 11 13

J'ai trouvé que getPurchaseHistory () donnait également des longueurs de tableau variables. On dirait que la fréquence des demandes l'a effectué. En fin de compte, il s'est avéré que cela n'avait pas vraiment d'importance pour nous, une fois que l'un des reçus de transaction avait été envoyé pour validation, tous les reçus étaient retournés par Apple dans le tableau latest_receipt_info toute façon, ce qui était tout ce qui comptait pour nous.

J'ai le même problème (je ne sais pas s'il s'agit d'une erreur de mode sandbox). De plus, lorsque je change d'identifiant Apple dans un appareil réel, l'achat effectué avec un autre compte est retourné.

Ex:
1 - J'ai effectué un achat avec le compte [email protected]
2 - Identifiant Apple remplacé par
3 - getAvailablePurchases renvoie le transactionId de l'achat effectué avec le compte [email protected]

Un autre problème que j'ai trouvé est que si je restaure l'appareil (réinitialisation d'usine), les deux méthodes getPurchaseHistory() et getAvailablePurchases donnent des résultats aléatoires

La réponse d'Apple pour restaurer un achat est:

"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."

Nous avons trouvé un sujet sur les forums de développeurs Apple sur les différents résultats de restoreCompletedTransactions comme indiqué par @ ssg-luke plus tôt.

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

Peut-être que c'est lié:

Il semble que vous faites référence à un utilisateur ayant de nombreuses transactions pour lesquelles l'application n'a pas encore appelé finishTransaction.
https://forums.developer.apple.com/thread/115242#thread -post-355444

J'ai eu d'autres comptes sandbox sur le même appareil. Alors, pourrait-il être que les transactions de différents comptes, sur le même appareil, sont tout simplement gâchées et ne sont pas du tout «terminées»?

Cependant, j'ai exécuté une boucle sur toutes les transactions et j'ai appelé finishTransactionIOS sur chacune d'elles. Mais cela ne les a pas fait disparaître ni ne s'est traduit par une sortie fiable de getAvailablePurchases() ... Peut-être parce que je suis déjà sur un nouveau compte sandbox et que les transactions proviennent d'un ancien compte sandbox?

Pourrait également expliquer ce que @fcandiani vit.

J'ai trouvé que getPurchaseHistory () donnait également des longueurs de tableau variables. On dirait que la fréquence des demandes l'a effectué. En fin de compte, il s'est avéré que cela n'avait pas vraiment d'importance pour nous, une fois que l'un des reçus de transaction avait été envoyé pour validation, tous les reçus étaient retournés par Apple dans le tableau latest_receipt_info de toute façon, ce qui était tout ce qui comptait pour nous.

Merci pour l'info @ ssg-luke, je vais faire de même.

J'ai également exécuté une boucle sur toutes les transactions et je n'ai pas pu les supprimer avec finishTransactionIOS. Mes transactions sont des abonnements à renouvellement automatique.

Face à presque la même chose. J'étais en train de créer un problème, mais j'ai décidé de mettre ici toutes les informations pour aider les autres à trouver le problème et la solution.

Version de react-native-iap

3.5.9

Version de react-native

0,60,5

Plateformes sur lesquelles vous avez rencontré l'erreur (IOS ou Android ou les deux?)

iOS

  • Le même code fonctionne parfaitement sur Android, déjà en production

Comportement attendu

L'utilisateur s'est abonné une fois , getAvailablePurchases ne devrait retourner qu'un seul achat

Comportement réel

getAvailablePurchases retourne plus d'un achat,

Environnement testé (émulateur? Real Device?)

Véritable appareil avec un nouveau compte sandbox.

Étapes pour reproduire le comportement

  • Créez un utilisateur de test sandbox sur https://appstoreconnect.apple.com/access/testers
  • Construire et exécuter un projet sur xcode
  • Appelez getAvailablePurchases , ne retourne aucun achat (comme prévu)
  • Abonnez-vous à un produit
  • mon purchaseUpdatedListener est appelé, et j'appelle RNIap.finishTransactionIOS(subscription.transactionId); qui ne retourne que undefined (comme prévu je suppose)
  • Appelez getAvailablePurchases , retourne un achat (comme prévu)
  • Recharger l'application
  • Appelez getAvailablePurchases , retourne deux achats , chacun avec un 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...."
}
  • Recharger l'application
  • Appelez getAvailablePurchases , retourne trois achats , chacun avec un transactionId (différent du résultat précédent):
{
   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..."
}
  • Recharger l'application
  • Appelez getAvailablePurchases , retourne quatre achats , chacun avec un transactionId (différent du résultat précédent) ...

Cela ne semble pas être le bon comportement, d'après ce que j'ai lu sur les documents et ce qui se passe sur Android.

J'apprécie toute aide.

getAvaialblePurchases () renvoie plus de 150 résultats sur mon compte de test sandbox. J'ai décidé de ne pas utiliser du tout getAvailablePurchases () et de simplement stocker le dernier achat sur l'appareil et également sur le serveur. Si l'application est supprimée ou l'utilisateur déplacé vers un nouveau téléphone, nous aurons toujours le dernier achat sur notre serveur lié à l'ID utilisateur et à la plate-forme de notre entreprise (iOS ou Android). L'appel de getAvailablePurchases () prend près d'une minute et appelle parfois cet auditeur mis à jour d'achat déclencheur essayant de restaurer plusieurs achats. Nous avons modifié notre flux comme ceci:
1) Lorsque l'utilisateur se connecte à l'appareil:
a) voir s'il existe un dernier achat valide sur notre serveur pour l'utilisateur et la plateforme.
b) S'il n'y a pas d'enregistrement sur le serveur, vérifiez s'il existe un achat local enregistré dans DB
c) S'il n'y en a pas ou s'il y en a un expiré, affichez la vue des abonnements.
Au départ, nous appelions getAvailablePurchases () et essayions de voir si le dernier achat était toujours valide. Je ne sais pas si cela aide les autres, mais nous ne rencontrons plus de problèmes avec cela. Nous sommes en train de réagir 59 et c'est une autre douleur à laquelle nous devons faire face.

@ramakula et que faire si l'utilisateur annule son abonnement?

Comme vous l'avez dit, vous conserverez l'abonnement dans votre base de données jusqu'à la date de fin, et vous «verrez» que l'achat n'est plus disponible.

Salut, il semble qu'il n'y ait eu aucune activité sur ce problème récemment. Le problème a-t-il été résolu ou nécessite-t-il toujours l'attention de la communauté? Ce problème peut être résolu si aucune autre activité ne se produit. Vous pouvez également étiqueter ce problème comme "Pour discussion" ou "Bon premier numéro" et je le laisserai ouvert. Merci pour vos contributions.

Clôture de ce numéro après une période d'inactivité prolongée. Si ce problème est toujours présent dans la dernière version, n'hésitez pas à créer un nouveau problème avec des informations à jour.

getAvaialblePurchases () renvoie plus de 150 résultats sur mon compte de test sandbox. J'ai décidé de ne pas utiliser du tout getAvailablePurchases () et de simplement stocker le dernier achat sur l'appareil et également sur le serveur. Si l'application est supprimée ou l'utilisateur déplacé vers un nouveau téléphone, nous aurons toujours le dernier achat sur notre serveur lié à l'ID utilisateur et à la plate-forme de notre entreprise (iOS ou Android). L'appel de getAvailablePurchases () prend près d'une minute et appelle parfois cet auditeur mis à jour d'achat déclencheur essayant de restaurer plusieurs achats. Nous avons modifié notre flux comme ceci:

  1. Lorsque l'utilisateur se connecte à l'appareil:
    a) voir s'il existe un dernier achat valide sur notre serveur pour l'utilisateur et la plateforme.
    b) S'il n'y a pas d'enregistrement sur le serveur, vérifiez s'il existe un achat local enregistré dans DB
    c) S'il n'y en a pas ou s'il y en a un expiré, affichez la vue des abonnements.
    Au départ, nous appelions getAvailablePurchases () et essayions de voir si le dernier achat était toujours valide. Je ne sais pas si cela aide les autres, mais nous ne rencontrons plus de problèmes avec cela. Nous sommes en train de réagir 59 et c'est une autre douleur à laquelle nous devons faire face.

Je pense que nous pouvons obtenir les derniers achats à partir du reçu. En vérifiant la réception d'un utilisateur, avec exclude-old-transactions: true, nous pouvons obtenir les dernières informations d'abonnement (uniquement pour le type renouvelable automatiquement). Je pense que nous pouvons utiliser cette méthode pour restaurer les achats d'abonnements auto-renouvelables. Je ne suis pas sûr que ce soit une méthode idéale.

Cette page vous a été utile?
0 / 5 - 0 notes