React-native-iap: purchaseUpdatedListener wird beim Start der App nur einmal aufgerufen und ruft niemals nach dem Aufruf von requestSubscription auf

Erstellt am 21. Apr. 2020  ·  22Kommentare  ·  Quelle: dooboolab/react-native-iap

Version von react-native-iap

4.4.6

Version von React-Native

0,61,5

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

ios

Erwartetes Verhalten

purchaseUpdatedListener jedes Mal nach einem Anruf von requestSubscription aufgerufen

Tatsächliches Verhalten

purchaseUpdatedListener wird beim Start der App nur einmal aufgerufen und ruft niemals nach dem Aufruf von requestSubscription auf

Getestete Umgebung (Emulator? Reales Gerät?)

Echtes Gerät

Schritte zum Reproduzieren des Verhaltens

Folgen Sie einfach der Readme-Datei und versuchen Sie, ein Abonnement anzufordern

📱 iOS 🕵️‍♂️ need more investigation 🙏 help wanted

Hilfreichster Kommentar

Hatte das gleiche Problem, als ich den Aufruf initConnection() nicht hinzugefügt habe.
Die README-Datei scheint gerade mit dem fett gedruckten Teil hier aktualisiert worden zu sein:

initConnection() Unter iOS wird einfach die canMakePayments-Methode aufgerufen und der Wert zurückgegeben, der erforderlich ist, damit die Listener ordnungsgemäß funktionieren .__

Ich denke, dieser Teil "Unter iOS wird einfach canMakePayments aufgerufen" sollte entfernt werden, außerdem sollte initConnection() Basisbeispiel hinzugefügt werden

Ich war wirklich überzeugt, dass es optional war, weil es nicht im Beispiel war

Das Hinzufügen der initConnection() vor der Registrierung der Kauf-Listener hat dies für mich behoben, sodass dies wahrscheinlich mit # 1002 und # 756 zusammenhängt

Alle 22 Kommentare

Hat jemand anderes das gleiche Problem? @Strate hast du finishTransaction angerufen?

@hyochan ja, aber tatsächlich geschieht dieser Aufruf nach dem Neustart der App

@hyochan Ich habe versucht, ein Expo-in-App-Kaufpaket zu kaufen, und es gibt kein Problem wie dieses - alles scheint in Ordnung zu sein

@Strate Ich möchte Ihren Code sehen. Ich kann selbst keinen Fehler finden :(

Dieses Problem ist absolut ärgerlich. Gibt es eine frühere Version, in der dies nicht der Fall ist?

Hat jemand anderes das gleiche Problem? @Strate hast du finishTransaction angerufen?

Wie wäre dies möglich, da der Kauf ein Argument in finishTransaction ist? Daher benötigen Sie den Ereignis-Listener, um das Argument an finishTransaction zu übergeben.

@Sophrinix finishTransaction wird voraussichtlich innerhalb von purchaseUpdatedListener aufgerufen

@hyochan Entschuldigung, aber es sieht so aus, als hätte ich expo-in-app-purchase gewechselt. @Sophrinix scheint dasselbe Problem zu haben.

Übrigens, mein Code enthielt nichts Besonderes: Registrieren Sie den Listener, sobald die App gestartet wurde, und folgen Sie einfach der Readme-Datei.

Es stellt sich heraus, dass dies eine Regression ist.

Wenn Sie die folgenden Versionen verwenden, funktioniert alles:

"react": "16.8.1",
"react-native": "^0.59.10",
"react-native-iap": "4.3.0",

Das Problem tritt auf, wenn Sie versuchen, react-native-iap 4.4.4 und eine Version von react-native vor 0.60

@Sophrinix Ich habe gerade requestPurchase in meiner Seite ausprobiert und alles scheint zu funktionieren. Könnten Sie bitte einen Teil Ihres Codes teilen?

Überprüfen Sie außerdem erneut, ob Sie initConnection angerufen haben. Dies ist eine wichtige Änderung in einem kürzlich durchgeführten Update, die jetzt in iOS wie in android aufgerufen werden muss.

Ich bestätige, dass das Zurücksetzen auf 4.3.0 funktioniert. Ich war verrückt nach der neuesten Version und habe über 1 Stunde lang debuggt, um das Problem zu finden.

Wenn ich hinzufügen darf, dass 4.3.4 bis 4.4.3 funktionieren, beginnt das Problem mit 4.4.4

Wenn ich hinzufügen darf, dass 4.3.4 bis 4.4.3 funktionieren, beginnt das Problem mit 4.4.4

Gleich hier, von 4.4.8 auf 4.4.3 herabgestuft und es funktioniert jetzt!

Hat jemand anderes das gleiche Problem? @Strate hast du finishTransaction angerufen?

Ich habe das gleiche Problem mit 4.4.0 - keiner der Ereignis-Listener wird angerufen, einschließlich purchaseErrorSubscription .

Lesen Sie einfach über das Downgrade, ich werde es gleich versuchen ...

Bearbeiten: Dies ist ein ernstes Problem, weil:

  • Es verhindert, dass Käufe zur Serververarbeitung gesendet werden
  • Es verhindert ein Rollback des Status, wenn jemand den Kauf storniert.

Ich kann auch bestätigen, dass 4.3.0 funktioniert.

Ich hatte das gleiche Problem für ein paar Tage mit RN 0.62.2 und reag-native-iap 4.4.8
Ich habe das initConnection() irgendwie verpasst, wahrscheinlich weil es im Beispiel in der README fehlt

Hatte das gleiche Problem unter iOS beim Upgrade auf 4.4.8, wodurch einige Abonnements nicht vollständig wurden. Ein Downgrade auf 4.4.3 hat das Problem vorerst behoben. Ist initConnection () obligatorisch? Der Doc macht es so, als ob es nicht so wäre

Hatte das gleiche Problem, als ich den Aufruf initConnection() nicht hinzugefügt habe.
Die README-Datei scheint gerade mit dem fett gedruckten Teil hier aktualisiert worden zu sein:

initConnection() Unter iOS wird einfach die canMakePayments-Methode aufgerufen und der Wert zurückgegeben, der erforderlich ist, damit die Listener ordnungsgemäß funktionieren .__

Ich denke, dieser Teil "Unter iOS wird einfach canMakePayments aufgerufen" sollte entfernt werden, außerdem sollte initConnection() Basisbeispiel hinzugefügt werden

Ich war wirklich überzeugt, dass es optional war, weil es nicht im Beispiel war

Das Hinzufügen der initConnection() vor der Registrierung der Kauf-Listener hat dies für mich behoben, sodass dies wahrscheinlich mit # 1002 und # 756 zusammenhängt

Ich bin am 4.4.9 und das in diesem Ticket beschriebene Problem tritt auch bei mir auf.
Der Listener wird nur beim Start aufgerufen, aber wenn ich ihn einstelle und dann den Kauf durchführe, wird er nicht aufgerufen.
Ich habe es gelöst, indem ich das native Ereignis direkt abonniert habe, nachdem ich mir react-native-iap/index.ts und herausgefunden habe, dass dies intern geschieht.
Dies kann jederzeit erfolgen und bleibt bestehen. (Stellen Sie einfach sicher, dass es nur einmal gemacht wird)

import { NativeModules, NativeEventEmitter } from 'react-native';
import { Observable } from 'rxjs/Observable';

const purchaseEvent = Observable.fromEvent(
  new NativeEventEmitter(NativeModules.RNIapIos),
  'purchase-updated'
);
const purchaseSubscription = purchaseEvent.subscribe((transactionData) => {
  // Trigger server receipt validation here...
});
const errorEvent = Observable.fromEvent(
  new NativeEventEmitter(NativeModules.RNIapIos),
  'purchase-error'
);
const errorSubscription = errorEvent.subscribe((errorData) => {
  // Handle errors here...
});

Viele Leute stoßen auf Fehler, weil initConnection() nicht im Beispielcode der README enthalten ist. Ich habe es hier hinzugefügt: # 1088, aber wenn jemand meinen Code überprüfen könnte, wäre er dankbar. (Ich habe meinen Code immer noch nicht voll funktionsfähig, daher bin ich mir nicht sicher ...)

Ich bin auch auf dieses Problem in Version 5.1.1 gestoßen. initConnection hat es nicht gelöst. Die Listener-Rückrufe werden beim Kauf von Update nie ausgelöst. Funktioniert gut auf Android. Meine Problemumgehung bestand darin, Observables wie @mrozanski zu verwenden.

import React, { useContext, useEffect, useState } from 'react';
import { Alert, EmitterSubscription, Platform, NativeEventEmitter,
    NativeModules } from 'react-native';
import { connect } from 'react-redux';
import RNIap, {
    InAppPurchase,
    PurchaseError,
    SubscriptionPurchase,
    purchaseErrorListener,
    purchaseUpdatedListener,
} from 'react-native-iap';
import { Observable, Subscription } from 'rxjs';

const RNIAPEvent = new NativeEventEmitter(NativeModules.RNIapIos);
const purchaseObservable = new Observable((subscriber) => {
    RNIAPEvent.addListener('purchase-updated', (event) => {
        subscriber.next(event);
    })
})

const RNIAPErrorEvent = new NativeEventEmitter(NativeModules.RNIapIos);
const purchaseErrorObservable = new Observable((subscriber) => {
    RNIAPErrorEvent.addListener('purchase-error', (event) => {
        subscriber.next(event);
    })
})


const Wrapper = ({ ...props }) => {

    let purchaseUpdateSubscription: EmitterSubscription | Subscription | null = null;
    let purchaseErrorSubscription: EmitterSubscription | Subscription | null = null;

    const validateTransaction = async (purchase: SubscriptionPurchase) => {    
        return new Promise(async (resolve) => {
              //resolve(validationResponseFromYourBackend)
        }
    }

    const handleSubEvent = async (purchase: InAppPurchase | SubscriptionPurchase) => {
        const receipt = purchase.transactionReceipt;
        const purchaseToken = purchase.purchaseToken
        if (receipt) {
            try {
                const result = await validateTransaction(purchase);
                if (result.status === 200) {
                    RNIap.acknowledgePurchaseAndroid(purchaseToken).then(() => {
                        RNIap.finishTransaction(purchase, false)
                        .then(() => giveYourUserValue())
                        .catch((e) => {
                            //
                        })
                    })
                }
            } catch (err) {
                //
            }
        }
    }


    useEffect(() => {
        RNIap.initConnection()
            .then(() => {
                RNIap.flushFailedPurchasesCachedAsPendingAndroid().catch(() => {
                    // exception
                    })
                .then(() => {
                    if (Platform.OS === 'ios') {
                        //Documented implementation has issues purchaseUpdatedListener callback
                        purchaseUpdateSubscription = purchaseObservable.subscribe((purchase) => {
                            console.log('purchase observable', purchase)
                            handleSubEvent(purchase);
                        });

                        purchaseErrorSubscription = purchaseErrorObservable.subscribe((error) => {
                            console.log('purchaseErrorListener', error);
                        })

                    } else {
                        //for android use the documented method. Callbacks work.
                        purchaseUpdateSubscription = purchaseUpdatedListener(
                            (purchase: InAppPurchase | SubscriptionPurchase) => {
                                handleSubEvent(purchase);
                            }

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

                })
            })
        return () => {
              // clear your listeners
             //eg if Subscription purchaseErrorSubscription.unsubscribe() 
            //eg if EmitterSubscription purchaseErrorSubscription.remove() 
        }
    }, []);

    return (
        <InAppSubContext.Provider
            value={{
                someValueYouWantPassedDown: 'theValue'
            }}
        >
            {props.children}
        </InAppSubContext.Provider>
    )
}

const mapState = (state) => ({ someProps: 'yeah' });

const InAppSubscriptionManager = connect(mapState)(Wrapper);

export default InAppSubscriptionManager;

Sie können dies jetzt verwenden, um Ihre App in Ihr App.tsx zu verpacken:


import InAppSubscriptionManager from './path/to/inAppSubscriptionManager';
const App = () => {

    return (
        <Provider store={store}>
                <InAppSubscriptionManager>

                    <AppNavigator />

                </InAppSubscriptionManager>
        </Provider>
    );
}

export default App;

Ich bin froh, dass es geholfen hat. Wir haben dies seit Juni in Produktion.
Es hat sich irgendwann von Observable zu diesem geändert (wir verwenden kein Typoskript).

      const purchaseEvent = new NativeEventEmitter(NativeModules.RNIapIos);
      const subscription = purchaseEvent.addListener(
        'purchase-updated',
        transactionData => {
          console.log('IAP-LOG purchase-updated');
          dispatch(validateRecepit(transactionData));
        }
      );
      const errorSubscription = purchaseEvent.addListener(
        'purchase-error',
        data => {
          crashlytics().log(`Purchase error ${JSON.stringify(data)}`);
          console.log('IAP-LOG purchase-error', data);
        }
      );
    };
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen