React-native-iap: Error de compra en la aplicación de iOS cuando el método de pago se agregó en vivo cuando no hay un método de pago ya presente

Creado en 31 oct. 2018  ·  27Comentarios  ·  Fuente: dooboolab/react-native-iap

Versión de react-native-iap

react-native-iap": "^2.3.17

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

iOS

Comportamiento esperado

El pago debe realizarse solo cuando se llame a finishTransaction

Comportamiento real

El monto se detecta después de agregar un método de pago como tarjeta de crédito.
Pero se alcanzó el método RNIap.buyProductWithoutFinishTransaction(sku) .

Entorno probado (¿Emulador? ¿Dispositivo real?)

Dispositivo real - iPhone 6s

Pasos para reproducir el comportamiento

  • Verifique para asegurarse de que la cuenta de Apple en el dispositivo, el método de pago esté configurado en ninguno o algunos detalles de pago no válidos
  • Realice la compra en la aplicación a través de la aplicación
  • Se lleva al usuario a la página de configuración de la cuenta para agregar un método de pago válido
  • Se cobra el método de pago pero el recibo de la transacción no se recibe en el código mencionado a continuación
ComponentDidMount(){
     await RNIap.initConnection();
     await RNIap.consumeAllItems();
     const prod = await RNIap.getProducts(product);

} 

  async componentWillUnmount() {
       RNIap.endConnection()
}

buyProduct(sku){
await RNIap.clearTransaction();

RNIap.buyProductWithoutFinishTransaction(sku)
.then(purchase => {
  // not reached
 if(calltoserverisSuccess){
    RNIap.finishTransaction();
 }
})
.catch(error => {
 // code enters catch case if ever
}}
📱 iOS 🙏 help wanted

Comentario más útil

Creo que debemos ponernos en contacto con apple para esto y parece realmente terrible que haya un caso de prueba diferente que no es reproducible en el entorno sandbox . Para aquellos que quieran entender el problema, he grabado la pantalla y pueden ver el clip aquí . @anandwahed ¿Podrías también ponerte en contacto con Apple para esto? Porque sé que no son tan solidarios, así que es mejor que más personas tengan contacto con ellos. Reunámonos para resolver este problema.

Todos 27 comentarios

Lamento decir esto, pero su código parece tener muchos errores de sintaxis. Consulte nuestro proyecto de ejemplo en nuestro repositorio y compare primero con su código.

@dooboolab
Gracias por la respuesta, el código que se publica aquí es solo un ejemplo, este no es el exacto que se está utilizando en la aplicación real.
Intentaré explicar cuál es el problema.

  1. componenteDidMount

    • conexión iniciada llamando RNIap.initConnection();

    • luego los productos se obtienen y se almacenan en el estado llamando al RNIap.getProducts(product)

  1. cuando el usuario hace clic en el botón de compra

    • RNIap.clearTransaction(); se llama solo para asegurarse de que no queden transacciones pendientes.
    • RNIap.buyProductWithoutFinishTransaction(sku) se llama en caso de éxito se activa una llamada al servidor de aplicaciones si el servidor da el caso de éxito verdadero, entonces se llama a RNIap.finishTransaction(); para completar el pago.
  2. componenteWillUnmount ()

    • RNIap.endConnection() para finalizar la conexión.

Este proceso funciona bien si el usuario ya ha agregado un método de pago. Cuando el usuario no tiene un método de pago agregado, debe agregar la página del método de pago y el monto se carga antes de llegar a RNIap.finishTransaction();

Gracias por el detalle. Tu problema parece claro ahora. cc @JJMoon

@JJMoon

@ zohaibahmed-22 ¿Es este caso de prueba de caja de arena?

@JJMoon No, es un caso de entorno real.

Entiendo que este error ocurre cuando el usuario está desconectado o no tiene información de tarjeta de crédito.
Si los métodos funcionan bien, la causa de este error se encuentra en otra parte.
Necesitamos preparar esta acción, que deja la aplicación, viewDidDisappear, etc.
En el modo sandbox, este síntoma ocurre de una manera algo diferente.
Cuando hago una nueva cuenta de sandbox y la primera compra no funciona.
En la segunda vez, el dispositivo se registra en el estado y funciona bien.
No tengo ni idea de este error.

@dooboolab y @JJMoon también creo que encontré el problema al updatedTransactions , cuando recibimos un mensaje de error en SKPaymentTransactionStateDeferred o SKPaymentTransactionStateFailed , no se supone que finishTransaction .

Dado que en muchos casos el resultado SKPaymentTransactionStateFailed es seguido por un SKPaymentTransactionStatePurchased como se menciona en el hilo anterior 6431 . No estoy seguro sobre el código Objective-C, así que verifique y confirme si borramos la transacción en caso de falla.

@anandwahed Estoy de acuerdo contigo. Que es mi culpa. Lo siento por eso.
Revisaré el hilo de Apple y me ocuparé del problema.

@anandwahed Supongo que es la forma correcta de finish transaction cuando falla. Busque este hilo. https://stackoverflow.com/questions/11008636/inapp-purchase-skpaymentqueue-finish-transaction-doesnt-work
Cuando falla, no habrá recibo, por lo que no aplica el producto de compra. Y la transacción final no siempre significa "compra".
Mientras tanto, investigaré el hilo 6431.

Acabo de leer el hilo 6431 (https://forums.developer.apple.com/thread/6431#14562)
La línea de fondo. Problema no resuelto desde 2015. Vaya ...
Hay dos formas diferentes de manejar este efecto de "flujo del kit de almacenamiento".

  1. No muestre ninguna alerta de usuario.
  2. Muestra el resultado.

Y aprendí dos cosas.
A. Tenemos que finishTransaction cuando falló. (Supongo con o sin opción, siempre)
B. El flujo de Storekit hace que la recepción sea exitosa y fallida. (es malo)

Les sugiero a todos que lean este hilo y vuelvan a este tema.

Supongo que la forma que elijas (1 o 2) es por tu cuenta.
Es posible que necesitemos una llamada de regreso para una respuesta de falla.

@JJMoon ¿significa que no deberíamos usar buyProductWithoutFinishTransaction?

@ maxs15 No
El flujo de StoreKit puede ocurrir en cualquier compra. Es un problema de iOS, no este módulo.
Por ahora, tampoco tengo ni idea. Esto sucede en cualquier aplicación nativa de iOS. ¿Correcto?
Cavaremos más en nuestro tiempo libre.

Hoy he intentado depurar este problema porque he generado este problema. El pago finishTransanction y se completa pero no recibe el callback cuando payMethod ha cambiado. Intenté depurar escribiendo algo de console.log pero no pude probar la facturación real en el entorno dev . ¿Alguien podría sugerirme cómo depurar este proceso para que pueda debug esto por real purchase ? ¿Debería tener que usar esto en el modo sandbox ? Funciona perfectamente en sandbox, así que no tengo idea de cómo depurarlo. Esto es muy reacio.

Recopilemos algunas ideas porque creo que es muy importante arreglarlo.

Siempre recibo este error cuando intento realizar la compra con un usuario que no es sandbox.

@hyochan Si conecta el servidor real (el suyo), no importa si está en modo de depuración o en modo de liberación. Supongo que tienes 2 opciones.

  1. Se ejecuta en el dispositivo real en modo de depuración en Xcode. Utilice el registro de la consola JS.
  2. Se ejecuta en el dispositivo real en modo de lanzamiento en Xcode. Utilice NSLog en el código objetivo-c.
    Ambos métodos deberían funcionar.

@JJMoon Sí, ya me di cuenta de eso, pero aún así no pude hacer pruebas de compra en vivo en iOS. ¿Es cierto este desbordamiento de pila ? Entonces, ¿cómo puedo solucionar este problema? Tenemos que probar la compra en vivo.

Cualquiera que esté enfrentando este problema, estoy seguro de que todos lo hacen, por favor dénos una idea de cómo encontrar este problema. in-app purchase fail when payment method added live como se describe en el título del problema. ¿Cómo podría depurar esto? @anandwahed ¿Alguna vez se

@hyochan No, no nos contactamos con el soporte de Apple.

Creo que debemos ponernos en contacto con apple para esto y parece realmente terrible que haya un caso de prueba diferente que no es reproducible en el entorno sandbox . Para aquellos que quieran entender el problema, he grabado la pantalla y pueden ver el clip aquí . @anandwahed ¿Podrías también ponerte en contacto con Apple para esto? Porque sé que no son tan solidarios, así que es mejor que más personas tengan contacto con ellos. Reunámonos para resolver este problema.

Hoy recibimos respuesta de Apple. Es posible que se devuelva la devolución de llamada después de failure . Estamos trabajando en una solución alternativa en el n. ° 348, pero me temo que esto podría ser muy desagradable.

Lancé a 2.4.0-beta1 , tratando de encontrar una solución para este problema. El PR # 348 se ha agregado a esta versión y también puede ver el archivo Léame de esta función . Tenga en cuenta que esto está bajo prueba.

Probé esto en una compra en vivo y parece estar funcionando. Sin embargo, tenga en cuenta que solo debe agregar un oyente cuando haya una falla o puede duplicarse con un resultado exitoso.

¡Muchachos, gracias por invertir tiempo en este problema! 🙏

Creo que la documentación actual debe ser más clara sobre el uso de addAdditionalSuccessPurchaseListenerIOS . Eso es algo que traté de abordar en el # 414.

Pero también creo que esto deja margen para la mejora de la API. ¿Estarían abiertos a discutir un cambio en la API que pueda adaptarse mejor al llamado 'flujo de kit de tienda'? Algo tal vez usando RxJS, por ejemplo:

const observable = RNIap.buyProduct('com.example.coins100')
                        .subscribe(
                            purchase => console.log(purchase), // successful payment
                            err => console.log(err) // err.code and err.message are available
                        )

¿O algo diferente que esconda mejor la suscripción adicional para iOS?

@Edgpaez Eso es genial, pero eso cambiará el comportamiento de la compra que se realiza en android . Espero poder investigar version 3 de este módulo en 2019 .

hola @hyochan , AFAICT, no necesitamos cambiar el comportamiento interno del paquete, solo la interfaz pública. Podemos mantener el método buyItemByType resolviendo las promesas y simplemente agregar un poco de Rx además de eso en index.js .

por ejemplo, tendríamos esto en index.js:

export const buyProduct = (sku) => Platform.select({
  android: () => Observable.of(RNIapModule.buyItemByType(ANDROID_ITEM_TYPE_IAP, sku, null, 0)), // returns an observable that emits when the RNIapModule.buyItemByType promise resolves
  ios: ... // ios would do the same but taking into account the usage of addAdditionalSuccessPurchaseListenerIOS
})();

Mi objetivo no es esta implementación específica, sino ocultar detalles específicos del 'flujo del kit de tienda'.
¿Crees que es buena idea?
¿Estaría interesado en un PR?

@Edgpaez Ok. Ahora entiendo el detalle. Sin embargo, creo que agregar RxJS es demasiado para implementar feature ya que creo que esto se puede cubrir sin él.

Además, creo que lo siguiente sería algo diferente.

RNIap.buyProduct('com.example.coins100')
                        .subscribe(
                            purchase => console.log(purchase), // successful payment
                            err => console.log(err) // err.code and err.message are available
                        )

Si llama a buyProduct por dos elementos como los siguientes,

RNIap.buyProduct('com.example.coins100');
RNIap.buyProduct('com.example.coins200');

No podemos garantizar cuál terminaría primero, así que creo que deberíamos manejar esto de forma nativa a sendEvent hasta JS .

Siento que la implementación debería verse así

RNIap.buyProduct('com.example.coins100');
RNIap.buyProduct('com.example.coins200');

// receiving events
const subs =  RNIap.purchaseUpdateListener(purchase => {
  ...
});

Dime si hay algo que me haya perdido.

Manejemos más disccustin en # 423

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