React-native-iap: purchaseUpdatedListener wird auch nach dem Kauf mehrmals aufgerufen

Erstellt am 26. Okt. 2020  ·  22Kommentare  ·  Quelle: dooboolab/react-native-iap

Version von react-native-iap

5.0.1

Version von React-Native

0,63,3

Plattformen, auf denen Sie den Fehler hatten (IOS oder Android oder beides?)

IOS

Erwartetes Verhalten

purchaseUpdatedListener wird nicht mehrmals aufgerufen

Tatsächliches Verhalten

purchaseUpdatedListener wird beim Start mehrmals aufgerufen, manchmal sogar dazwischen

Getestete Umgebung (Emulator? Reales Gerät?)

Reales Gerät (iOS 14, 13 im Testflug und im AppStore)

Schritte zum Reproduzieren des Verhaltens

(Navigatorkomponente)

const itemSkus = ['01', '02'];

const processNewPurchase = async (purchase) => {
  const { productId, transactionReceipt } = purchase;
  if (transactionReceipt !== undefined && transactionReceipt) {
       //backend call with fetch - validating receipt 
        if (data.ack === 'success') {
          console.log('finished');
          await finishTransaction(purchase);
      } else if (data.ack === 'failure') {
          props.setProcessing(false);
          console.log('error');
      }
    }
};


const getProductsIAP = useCallback(async () => {
  await clearProductsIOS();
  await clearTransactionIOS();

 try {
   const result = await initConnection();
   const products = await getProducts(itemSkus);
   props.setProducts(products);
   console.log('result', result);
 } catch (err) {
   console.warn(err.code, err.message);
 }

  purchaseUpdateSubscription = purchaseUpdatedListener(
    async (purchase) => {
      const receipt = purchase.transactionReceipt;
      console.log('purchaseUpdatedListener');
      if (receipt) {
        try {
          await processNewPurchase(purchase);
        } catch (ackErr) {
           console.log('ackErr', ackErr);
        }
      } else {
        console.log('purchaseUpdatedListener error: receipt');
      }
    },
  );

  purchaseErrorSubscription = purchaseErrorListener(
    (error: PurchaseError) => {
      console.log('purchaseErrorListener', error);
      console.log(JSON.stringify(error));
    },
  );

  setLoading(false);
}, []);


useEffect(() => {
  getProductsIAP();

  return () => {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
  };
}, []);

📱 iOS 🙏 help wanted

Hilfreichster Kommentar

Immer noch das gleiche Problem. Sieht so aus, als wäre der Kauf von UpdatedListener kaputt. Bitte beheben Sie dies so schnell wie möglich. Keine Lösung gefunden.

Alle 22 Kommentare

Löst die Veranstaltung die gleichen Kaufergebnisse aus?

Ja, es wird mit den erfolgreichen Ergebnissen / Quittungen ausgelöst. Wenn kein aktueller Beleg vorhanden ist, wird dieser ebenfalls ausgelöst, schlägt jedoch auf dem Validierungsserver fehl.

Könnten Sie bitte überprüfen, ob Ihre Komponente nicht erneut gerendert wurde? Es gab viele Probleme, als die Komponente neu gerendert wurde und die Listener gelegentlich mehrmals gestartet wurden. Nun, das sollte hart veröffentlicht werden, aber wir müssen Ihren Fall reproduzieren.

Nun, es ist der "NavigatorContainer", der bedeutet, dass ich verschiedene Zustände einstelle, Dinge aktualisiere und so weiter. Aber rendert nur einen und dann "rendern" für die Aktualisierung verschiedener Zustände, Requisiten ...

Aber dafür ist es gedacht - sich von den Hörern abzumelden / dies zu vermeiden.

useEffect(() => {
  getProductsIAP();

  return () => {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
  };
}, []);

Nun, es ist der "NavigatorContainer", der bedeutet, dass ich verschiedene Zustände einstelle, Dinge aktualisiere und so weiter. Aber rendert nur einen und dann "rendern" für die Aktualisierung verschiedener Zustände, Requisiten ...

Aber dafür ist es gedacht - sich von den Hörern abzumelden / dies zu vermeiden.

useEffect(() => {
  getProductsIAP();

  return () => {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
  };
}, []);

Ja, das habe ich auch erwähnt. Ich habe gerade die vorherige Ausgabe geteilt, an die ich mich erinnere. Wir brauchen die Reproduktion.

Es kann auch hilfreich sein, die Transaktion zu löschen oder es mit einem anderen Testflight-Konto zu versuchen.

const getProductsIAP = useCallback(async () => {
  await clearProductsIOS();
  await clearTransactionIOS();

.....

Getestet in TestFlight, Produktion und verschiedenen Geräten.

Anderes Konto?

Ja, das gleiche Ergebnis.

Seltsam. Könnten Sie auch das Code-Snippet in unserem IapExample -Projekt ausprobieren?

Ich habe das folgende Verhalten.

1) Benutzer kauft IAP.
2) purchaseUpdatedListener wird aufgerufen.
3) Der Benutzer deinstalliert die App.
4) Der Benutzer kehrt zur App zurück.
5) purchaseUpdatedListener wird ausgelöst und geht in eine Schleife.

Ich verwende Klassen, sehe aber kein erneutes Rendern.

Ich bin auf "react-native-iap": "4.4.1" und "react-native": "0.63.3".

Ich habe versucht, auf 5.0.0 zu aktualisieren, erhalte jedoch das gleiche Verhalten.

Ich habe das folgende Verhalten.

  1. Der Benutzer kauft IAP.
  2. PurchaseUpdatedListener wird aufgerufen.
  3. Der Benutzer deinstalliert die Anwendung.
  4. Der Benutzer kehrt zur Anwendung zurück.
  5. purchaseUpdatedListener wird ausgelöst und bildet eine Schleife.

Ich benutze Klassen, aber ich sehe keine Wiederholungen.

Ich bin in "react-native-iap": "4.4.1" und "react-native": "0.63.3".

Ich habe versucht, auf 5.0.0 zu aktualisieren, aber ich bekomme das gleiche Verhalten.

Hallo eine Frage. Hast du die Lösung dafür gefunden?

Immer noch das gleiche Problem. Sieht so aus, als wäre der Kauf von UpdatedListener kaputt. Bitte beheben Sie dies so schnell wie möglich. Keine Lösung gefunden.

Ich habe das gleiche Problem damit. Wie ist es möglich, dass es seit Monaten nicht behoben ist? Ist dies kein kritisches Problem oder hat jemand eine Problemumgehung dafür gefunden? Auch wenn es hilft, denke ich, dass ich dieses Problem nur beim Upgrade meines Geräts von iOS 13 auf iOS 14 festgestellt habe. Soweit ich mich erinnern kann, hat es unter iOS 13 einwandfrei funktioniert, aber ich könnte mich irren.

Gleiches Problem hier.
Mir ist aufgefallen, dass dies jedes Mal passiert, wenn ich den Code speichere und die App im laufenden Betrieb neu geladen wird.
In diesem Szenario wird die Stammkomponente nicht bereitgestellt und anschließend erneut bereitgestellt.

Dies ist mein useIap() Haken

const useIap=()=>{

const purchaseUpdateSubscription = useRef<EmitterSubscription[]>([]);
    const purchaseErrorSubscription = useRef<EmitterSubscription[]>([]);

const init = useCallback(async () => {
        console.taggedLog(logTag, 'call iap init');

        await RNIap.initConnection();

        await RNIap.flushFailedPurchasesCachedAsPendingAndroid();

        purchaseUpdateSubscription.current.push(RNIap.purchaseUpdatedListener(async purchase => {
            console.taggedLog(logTag, 'purchaseUpdatedListener', purchase);

            try {
                await finalizePurchase(purchase);
            } catch (err) {
                handleFailedPurchase();
            }
        }));

        // use array to be sure to not accidentally overwrite subscriptions and lose access to them.
        // being an array I can always iterate and call `remove` on them
        purchaseErrorSubscription.current.push(RNIap.purchaseErrorListener(error => {
            handleFailedPurchase(error);
        }));

        updateProducts();
        return clear;
    }, []);

  const clear = useCallback(() => {
        console.taggedLog(logTag, 'clearing all');
        clearPurchaseEventListeners();
    }, [clearPurchaseEventListeners]);


 const clearPurchaseEventListeners = useCallback(() => {
        console.taggedLog(logTag, 'clearing purchase event listener', purchaseUpdateSubscription.current.length, purchaseErrorSubscription.current.length);
        purchaseUpdateSubscription.current.forEach(sub => sub.remove());
        purchaseErrorSubscription.current.forEach(sub => sub.remove());
        purchaseUpdateSubscription.current = [];
        purchaseErrorSubscription.current = [];
    }, []);

return {init,clear}
}

Und dann benutze ich diesen Code in der Root-Komponente

const iap=useIap();
 useEffect(() => {
        console.log("root component mounted");
        iap.init();

        return () => {
            console.log("root component unmounted");
            iap.clear();
        };
    }, []);

Es kann vorkommen, dass die Root-Komponente abgemeldet und erneut bereitgestellt wird. Die Methode clear wird jedoch aufgerufen, und ich sehe auch das Protokoll 'Kaufereignis-Listener löschen', 1,1, was bedeutet, dass sie gelöscht werden.

Selbst in dieser Situation wird der Kauf purchaseUpdatedListener immer noch oft aufgerufen, es

irgendeine Lösung?

Habe das gleiche Problem.
Es wurden sogar verschiedene Bildschirme aufgerufen.
Irgendwelche Updates dazu?

Gleiches Problem für mich. Es ruft die vergangenen Belege auf, wenn das iap das nächste Mal initialisiert wird.

Ich hatte das gleiche Problem und stellte fest, dass das Gleiche geschah, weil ich die Komponente nicht richtig zusammen- und auseinanderbaute, wodurch mehrere Listener gleichzeitig geöffnet wurden.

componentWillUnmount() { if (this.purchaseUpdateSubscription) { this.purchaseUpdateSubscription.remove(); this.purchaseUpdateSubscription = null; } }
Jedes Mal, wenn ein Kauf getätigt und die Komponente zerlegt wird, muss der Listener / das Abonnement entfernt und beim Zusammenbau der Komponente ein neues hinzugefügt werden.
Dieser Fehler tritt bei Android nicht auf. Warum? Ich weiß es nicht, aber da es unter Android funktioniert, denken Sie, dass der Fehler in iOS und nicht im Code liegt.

Eine mögliche Problemumgehung beim Testen Ich habe festgestellt, dass manchmal die vergangenen Belege (an den Server gesendet) angezeigt werden. Daher habe ich sofort die Transaktions-ID jeder empfangenen Benachrichtigung gespeichert. Sie überprüfen daher immer zuerst die Datenbank, ob diese Transaktions-ID verarbeitet wurde und ob Also ignorieren (es ist ein Duplikat), wenn nicht, können Sie fortfahren. Wenn die Benachrichtigung zuerst an die App (und nicht an den Server) gesendet wird, können Sie eine Logik festlegen, um dies zu steuern. Sie sollten also nur 1 erhalten, nachdem auf eine bestimmte Schaltfläche geklickt wurde usw.
Nach ausgiebigen Tests hörte es nach einer Weile auf zu duplizieren, da ist etwas los.

Ja, es gibt einige skizzenhafte Problemumgehungen, aber sie sind alle hübsch ...
Bitte beheben Sie einfach dieses Problem. Dies ist definitiv ein kritischer und projektbrechender Fehler seit Oktober 2020 ....

Es gibt nur eine Lösung : Revenuecat;)

irgendeine Lösung?

Revenuecat

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen