React-native-iap: purchaseUpdatedListener llamó varias veces incluso después de la compra

Creado en 26 oct. 2020  ·  22Comentarios  ·  Fuente: dooboolab/react-native-iap

Versión de react-native-iap

5.0.1

Versión de react-native

0.63.3

Plataformas a las que se enfrentó el error (¿IOS o Android o ambos?)

IOS

Comportamiento esperado

purchaseUpdatedListener no recibe llamadas varias veces

Comportamiento real

purchaseUpdatedListener recibe una llamada en el inicio varias veces, a veces incluso entre

Entorno probado (¿Emulador? ¿Dispositivo real?)

Dispositivo real (iOS 14, 13 en vuelo de prueba y en AppStore)

Pasos para reproducir el comportamiento

(Componente del navegador)

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

Comentario más útil

Sigue siendo el mismo problema. Parece que su purchaseUpdatedListener no funciona. Solucione esto lo antes posible. No se encontró ninguna solución.

Todos 22 comentarios

¿El evento genera los mismos resultados de compra?

Sí, se dispara con los resultados / recibo exitosos. Si no hay un recibo actual, también se dispara, pero falla en el servidor de validación.

¿Podría comprobar si su componente no se ha vuelto a procesar? Hubo muchos problemas cuando el componente se volvió a generar y los oyentes comenzaron varias veces ocasionalmente. Bueno, eso debería publicarse con fuerza, pero necesitamos reproducir su caso.

Bueno, es el "NavigatorContainer", lo que significa que estoy configurando diferentes estados, actualizando cosas, etc. Pero solo renderiza uno y luego "vuelve a renderizar" para la actualización de diferentes estados, accesorios ...

Pero para eso está: darse de baja de los oyentes / para evitar esto.

useEffect(() => {
  getProductsIAP();

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

Bueno, es el "NavigatorContainer", lo que significa que estoy configurando diferentes estados, actualizando cosas, etc. Pero solo renderiza uno y luego "vuelve a renderizar" para la actualización de diferentes estados, accesorios ...

Pero para eso está: darse de baja de los oyentes / para evitar esto.

useEffect(() => {
  getProductsIAP();

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

Sí, también he mencionado esto. Acabo de compartir el número anterior que recuerdo. Necesitamos la reproducción.

Además, puede ser útil borrar la transacción o intentarlo con una cuenta de testflight diferente.

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

.....

Probado en TestFlight, producción y diferentes dispositivos.

¿Cuenta diferente?

Sí, mismo resultado.

Extraño. ¿También podrías probar el fragmento de código en nuestro proyecto IapExample ?

Tengo el siguiente comportamiento.

1) El usuario compra IAP.
2) Se llama a purchaseUpdatedListener.
3) El usuario desinstala la aplicación.
4) El usuario vuelve a la aplicación.
5) purchaseUpdatedListener se activa y forma un bucle.

Estoy usando clases, pero no veo ninguna repetición.

Estoy en "react-native-iap": "4.4.1" y "react-native": "0.63.3".

Intenté actualizar a 5.0.0, pero obtengo el mismo comportamiento.

Tengo el siguiente comportamiento.

  1. El usuario compra IAP.
  2. Se llama a purchaseUpdatedListener.
  3. El usuario desinstala la aplicación.
  4. El usuario vuelve a la aplicación.
  5. purchaseUpdatedListener se activa y forma un bucle.

Estoy usando clases, pero no veo ninguna repetición.

Estoy en "react-native-iap": "4.4.1" y "react-native": "0.63.3".

Intenté actualizar a 5.0.0, pero obtengo el mismo comportamiento.

Hello one question. did you find the solution to this?

Sigue siendo el mismo problema. Parece que su purchaseUpdatedListener no funciona. Solucione esto lo antes posible. No se encontró ninguna solución.

Tener el mismo problema con esto. ¿Cómo es posible que no se arregle durante meses? ¿No es este un problema crítico o alguien ha encontrado una solución para esto? Además, si ayuda, creo que solo encontré este problema cuando actualicé mi dispositivo de iOS 13 a iOS 14. Por lo que recuerdo, estaba funcionando bien en iOS 13, pero podría estar equivocado.

El mismo problema aquí.
Noté que sucede cada vez que guardo el código y la aplicación se recarga en caliente.
En este escenario, el componente raíz se desmonta y luego se vuelve a montar.

Este es mi useIap() gancho

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

Y luego uso este código en el componente raíz

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

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

Es posible que el componente raíz se desmonte y vuelva a montar, sin embargo, se llama al método clear y también veo el registro 'borrando el detector de eventos de compra', 1,1, lo que significa que los borrará.

Incluso en esta situación, la compra purchaseUpdatedListener todavía se llama muchas veces, es

¿alguna solución?

Tiene el mismo problema.
Incluso llamó a diferentes pantallas.
¿Alguna actualización sobre esto?

El mismo problema para mí. Llama a los recibos pasados ​​cuando el iap se inicializa la próxima vez.

Tuve el mismo problema y me di cuenta de que pasaba lo mismo porque no estaba montando y desmontando el componente correctamente, haciendo que varios oyentes se abran al mismo tiempo.

componentWillUnmount() { if (this.purchaseUpdateSubscription) { this.purchaseUpdateSubscription.remove(); this.purchaseUpdateSubscription = null; } }
Cada vez que se realiza una compra y se desmonta el componente, es necesario eliminar el oyente / suscripción y añadir uno nuevo al montar el componente.
Este error no ocurre en Android, ¿por qué? No lo sé, pero como funciona en Android te hace pensar que el error está en iOS y no en el código.

Una posible solución alternativa, probando noté que a veces muestra los recibos anteriores (enviados al servidor), por lo que lo que hice fue almacenar inmediatamente el transactionId de cada notificación recibida, por lo que siempre verifica primero la base de datos para ver si este transactionId ha sido procesado y si entonces ignore (es un duplicado) si no, entonces puede continuar. Si la notificación llega primero a la aplicación (en lugar del servidor), entonces puede poner algo de lógica para controlar esto, es decir, solo debería recibir 1 después de que se haya hecho clic en un botón determinado, etc.
Después de probar exhaustivamente, dejó de duplicarse después de un tiempo, algo está sucediendo allí.

Sí, hay algunas soluciones incompletas, pero todas son bonitas ...
Solucione este problema. Este es definitivamente un error crítico y que rompe el proyecto desde octubre de 2020 ...

Solo hay una solución, es usar : Revenuecat;)

¿alguna solución?

Revenuecat

¿Fue útil esta página
0 / 5 - 0 calificaciones