React-native-iap: Erreur lors de la mise à niveau / rétrogradation de l'abonnement sur Android avec le mode DEFERRED

Créé le 28 déc. 2019  ·  31Commentaires  ·  Source: dooboolab/react-native-iap

Version de react-native-iap

4.3.3

Version de react-native

0,59,10

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

Android

Comportement attendu

Lors de la mise à niveau / rétrogradation d'un abonnement avec le mode DEFERRED, l'écouteur de mise à jour d'achat doit être appelé avec un nouveau reçu de transaction.

Comportement réel

l'écouteur d'erreur d'achat est appelé avec l'erreur suivante:

{message: 'les achats sont nuls.',
code: 'OK',
debugMessage: '',
responseCode: 0}

Environnement testé (émulateur? Real Device?)

Appareil réel - bac à sable

Étapes pour reproduire le comportement

1. achetez un abonnement avec RNIap.requestSubscription (sku), cela fonctionne correctement.

Mettez à niveau ou rétrogradez l'abonnement avec RNIap.requestSubscription (newSku, false, sku, 4). (4 est le mode de proration DEFERRED) La boîte de dialogue de facturation de Google Play indiquera que le plan d'abonnement a été modifié avec succès et vous recevrez un e-mail de notification de Google Play à ce sujet. Cependant, l'écouteur d'erreur est appelé avec l'erreur mentionnée ci-dessus.

3.Si vous appelez à nouveau RNIap.requestSubscription (newSku, false, sku, 4), la boîte de dialogue de facturation de Google Play indiquera qu'ils ne peuvent pas modifier le plan d'abonnement et l'écouteur d'erreur est appelé avec l'erreur suivante:

{message: "Google indique que nous rencontrons un problème lors de la connexion au paiement.",
code: 'E_DEVELOPER_ERROR',
debugMessage: '',
responseCode: 5}

Mais parfois, la boîte de dialogue de facturation Google Play indiquera que votre commande est en cours de traitement et que votre produit devrait être livré bientôt, et l'auditeur d'erreur est appelé avec l'erreur suivante:

{message: "Vous possédez déjà cet article.",
code: 'E_ALREADY_OWNED',
debugMessage: '',
responseCode: 7}

Je suppose que cela est dû au fait que la transaction de l'étape 2 attend d'être reconnue. Cependant, comme l'étape 2 ne renvoie pas de reçu, nous ne pouvons pas l'accuser.

🕵️‍♂️ need more investigation 🙏 help wanted 🤖 android

Commentaire le plus utile

Des plans pour résoudre ce problème?

Tous les 31 commentaires

Essayez d'appeler getAvailablePurchases après avoir mis à niveau / rétrograder votre abonnement.
Reportez-vous au doc , The list of Purchase objects in onPurchasesUpdated() does not contain paused subscriptions. .

Je ne suis pas sûr que cela aide. N'hésitez pas à quitter tous les autres essais et discussions.

J'ai essayé getAvailablePurchases () après la mise à niveau / rétrogradation de l'abonnement, mais malheureusement, seul le reçu de transaction de l'achat d'origine est dans le tableau retourné.

RNIap v2.3.19 et v2.5.5 fonctionne correctement, buySubscription () renverra un nouveau reçu lors de la mise à niveau / rétrogradation de l'abonnement. Mais j'aimerais passer à la v3 ou à la v4 qui a un meilleur modèle basé sur les événements si possible.

Voici un document de référence qui explique le fonctionnement de la mise à niveau / rétrogradation de l'abonnement Android et pourquoi nous avons besoin du nouveau reçu après la mise à niveau / rétrogradation.

@ howg0924 Merci d'avoir confirmé cela. Je voudrais comparer les différences avec la v2 et notre version actuelle et voir comment je peux résoudre ce problème.

J'ai recherché le code le week-end pour vous dans # 893
La nouvelle mise à jour arrivera dans 4.4.0 .

Pourriez-vous tester la version [email protected] ?

@hyochan Je viens d'essayer 4.4.0-rc.1, mais la situation est toujours la même.

Après avoir appelé RNIap.requestSubscription (oldSku, false, newSku 4) et terminé la mise à niveau / rétrogradation, l'écouteur d'erreur est appelé avec l'erreur suivante:

{message: 'les achats sont nuls.',
code: 'OK',
debugMessage: '',
responseCode: 0}

Et getAvailablePurchases () ne contient que l'ancien reçu.

@ howg0924 Si vous savez comment déboguer android , j'espère que vous allez tester en mettant des Log.d et voir si cela passe les conditions if dans buyItemByType . Serait-ce possible pour vous? Je veux voir comment ils sont exécutés.

@ howg0924 Oh attendez ~! Je pense avoir trouvé le problème, laissez-moi vous répondre bientôt!

@ howg0924 Pourriez-vous essayer 4.4.0-rc.2 ? Je pense que cela fonctionnera cette fois.

La compilation de @hyochan 4.4.0-rc.2 a échoué sur:

RNIapModule.java:436: error: incompatible types: SkuDetails cannot be converted to String:
   builder.setOldSku(selectedOldSku);
                     ^

@hyochan J'ai surveillé buyItemByType () de 4.4.0-rc.1. Lors de la mise à niveau / rétrogradation, il a exécuté:

builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED);

et également exécuté:

BillingResult billingResult = billingClient.launchBillingFlow(activity, flowParams);

Voulez-vous que je surveille / vider tout flux / données?

(supprimé en raison d'un malentendu)

@ howg0924 Désolé d'avoir commis une erreur car je n'avais pas un bon débogage env . J'ai annulé cela dans 4.4.0-rc.3 . Il semble que votre code n'exécute pas builder.setOldSku(oldSku) ce qui est le plus important.

Après comparaison avec 2.5.5, j'ai trouvé que 2.5.5 n'appelle pas

builder.setReplaceSkusProrationMode (BillingFlowParams.ProrationMode.DEFERRED);

lors de l'utilisation du mode DEFERRED.

J'essaye donc de supprimer cette ligne sur 4.4.0-rc.1, et ça marche! Mais je ne sais pas:

1. sur quel mode de proration il travaille actuellement.
2. pourquoi cela ne fonctionne pas lorsqu'il est réglé sur le mode DEFERRED par setReplaceSkusProrationMode ()

        if (prorationMode != null && prorationMode != -1) {
          if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE);
            if (type.equals(BillingClient.SkuType.SUBS) == false) {
              String debugMessage = "IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in subscription purchase.";
              WritableMap error = Arguments.createMap();
              error.putString("debugMessage", debugMessage);
              error.putString("code", PROMISE_BUY_ITEM);
              error.putString("message", debugMessage);
              sendEvent(reactContext, "purchase-error", error);
              promise.reject(PROMISE_BUY_ITEM, debugMessage);
              return;
            }
          } else if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION);
          } else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED);
          } else if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION);
          } else {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY);
          }
        }

Nous transmettons actuellement le ProrationMode comme ci-dessus. Cela signifie-t-il que vous pouvez auto renew subscription lorsque vous avez supprimé DEFERRED ?

Je veux dire si je change le code en:

        if (prorationMode != null && prorationMode != -1) {
          if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE);
            if (type.equals(BillingClient.SkuType.SUBS) == false) {
              String debugMessage = "IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in subscription purchase.";
              WritableMap error = Arguments.createMap();
              error.putString("debugMessage", debugMessage);
              error.putString("code", PROMISE_BUY_ITEM);
              error.putString("message", debugMessage);
              sendEvent(reactContext, "purchase-error", error);
              promise.reject(PROMISE_BUY_ITEM, debugMessage);
              return;
            }
          } else if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION);
          } else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
            // comment following line
            // builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED);
          } else if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION) {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION);
          } else {
            builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY);
          }
        }

alors je peux utiliser RNIap.requestSubscription (newSku, false, sku, 4 / * mode DEFERRED * /) pour mettre à niveau / rétrograder un abonnement. Bien que je ne sois pas sûr du mode de prorata sur lequel il fonctionne, car builder.setReplaceSkusProrationMode () n'est pas exécuté, comme l'a fait la version 2.5.5.

Le code suivant est de la v2.5.5:

        if (type.equals(BillingClient.SkuType.SUBS) && oldSku != null && !oldSku.isEmpty()) {
          // Subscription upgrade/downgrade
          if (prorationMode != null && prorationMode != 0) {
            builder.setOldSku(oldSku);
            if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE) {
              builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE);
            } else if (prorationMode == BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION) {
              builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION);
            } else {
              builder.addOldSku(oldSku);
            }
          } else {
            builder.addOldSku(oldSku);
          }
        }

@ howg0924 Eh bien, c'est très étrange car nous n'avons même pas défini DEFFERED dans notre branche maître actuelle qui est 4.3.4 . J'ai ajouté ce code dans 4.4.0+ .

Je pense que la raison pourrait être quelque chose de différent. J'espère que vous pourrez revenir s'il y a d'autres nouvelles.

Associé # 391 # 555

OK, j'essaierai plus et ferai rapport.

Related # 707

@hyochan Après un test supplémentaire sur 4.4.0-rc.1:

IMMEDIATE_WITH_TIME_PRORATION => fonctionne
IMMEDIATE_AND_CHARGE_PRORATED_PRICE => fonctionne
IMMEDIATE_WITHOUT_PRORATION => fonctionne
DEFERRED => NE FONCTIONNE PAS (je ne sais pas pourquoi)

Eh bien, c'est très étrange car nous n'avons même pas défini DEFFERED dans notre branche master actuelle qui est 4.3.4. J'ai ajouté ce code dans 4.4.0+.

Je pense que c'est à cause du code suivant dans 4.3.0 toujours le mettre en mode DEFERRED:

  if (prorationMode != 0 && prorationMode != -1) {
    builder.setReplaceSkusProrationMode(prorationMode);
  }

Cependant, le code ci-dessus n'existe pas sur 2.3.19 et 2.5.5. Par conséquent, quand j'ai appelé RNIap.requestSubscription (newSku, false, sku, 4 / * DEFERRED * /) sur 2.3.19 et 2.5.5, je pensais que cela fonctionnait auparavant, mais maintenant je me suis rendu compte que cela fonctionnait en fait sur le mode IMMEDIATE_WITH_TIME_PRORATION par défaut .

Ok donc nous devrions savoir pourquoi le Deffered ne fonctionnera pas. Je n'ai pas trouvé la raison pour le moment.

J'ai le même problème mais le comportement est différent.

Lorsque j'appelle requestSubscription(newSku, false, oldSku, 4) , cela génère une erreur avec le code d'erreur OK et un message d'erreur vide. Le paiement côté Google Play est comme prévu (il est différé). Lorsque les frais d'abonnement suivants surviennent, j'obtiens l'événement purchaseUpdatedListener au démarrage de l'application mais je ne parviens pas à confirmer l'achat (en appelant finishTransaction() ). finishTransaction() donne une erreur DEVELOPER_ERROR .

Se produit sur les deux versions 4.4.0 et 4.3.4 .

Salut @hyochan , j'ai vu que dans https://github.com/dooboolab/react-native-iap/pull/893 vous avez marqué cela comme résolu mais j'ai mis à jour react-native-iap vers la dernière version mais celle-ci n'est toujours pas fixé. J'ai toujours une erreur dans l'auditeur error {"code": "OK", "debugMessage": "", "message": "purchases are null.", "responseCode": 0} et j'ai reçu le courriel You updated your subscription purchase normalement. Ma question est donc quelle est la bonne solution pour le mode DEFERRED?

La dernière fois que j'ai trouvé ce problème non plus. Cela ne fonctionne étrangement qu'en mode deferred . Nous devons enquêter là-dessus.

Salut @ howg0924 , avez-vous déjà

@ nenjamin2405 Non, j'utilise toujours le mode IMMEDIATE_WITH_TIME_PRORATION par défaut, et j'espère vraiment que cela pourra être corrigé.

Salut @hyochan , une mise à jour à ce sujet? La nouvelle fonctionnalité de mon application est bloquée par ce problème. J'apprécie vraiment vos efforts pour enquêter sur cela, merci

Pas encore. Je n'ai pas eu le temps de revenir sur cette question.
J'espère que quelqu'un apportera également des informations utiles pour gérer ce problème.
Demander Google ou StackOverflow et partager cela dans ce fil peut être vraiment utile.

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.

Nous avons examiné ce problème et avons voulu partager avec la communauté, cela peut aider certaines personnes.

Le problème est dû au fait que l'auditeur d'achat mis à jour est appelé avec une liste vide d'achats sur un remplacement d'abonnement différé, qui est le fonctionnement d'Android (voir ici "Pour le mode de remplacement différé ...")

Nous avons ajouté la prise en charge du remplacement d'abonnement différé android sur react-native-iaphub en effectuant un correctif en regardant lorsque l'écouteur d'erreur est appelé avec l'erreur purchases are null sur un remplacement d'abonnement. ( Voir commit )

Bien sûr, vous devrez faire quelques modifications côté serveur pour valider vos reçus également, l'actualisation du reçu ne suffit pas lorsqu'il s'agit d'abonnements différés.
Vous devrez implémenter les notifications en temps réel Android afin de détecter le moment où le remplacement de l'abonnement a lieu et de traiter un nouveau jeton.

Ou vous pouvez simplement utiliser IAPHUB qui fait tout cela pour vous 🙂

Des plans pour résoudre ce problème?

Comme le mentionne @iaphub , le problème est que onPurchasesUpdated est appelé avec l'argument purchases comme null lorsque le mode DEFERRED est utilisé.

À partir de Google Docs :

Pour le mode de remplacement différé, votre application reçoit un appel à votre PurchasesUpdatedListener avec une liste d'achats vide et un état indiquant si la mise à niveau ou la rétrogradation a réussi.

Il s'agit donc simplement de gérer ce cas à l'intérieur de cet auditeur.

Mais je ne sais pas quelle devrait être la bonne façon de gérer cette situation:

  • Résoudre la promesse avec les informations d'abonnement précédentes
  • Résoudre la promesse avec undefined
  • Rejeter la promesse avec un code PURCHASE_DEFERRED

Qu'est-ce que tu penses?

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