React-native-iap: Error al actualizar / degradar la suscripción en Android con el modo DIFERIDO

Creado en 28 dic. 2019  ·  31Comentarios  ·  Fuente: dooboolab/react-native-iap

Versión de react-native-iap

4.3.3

Versión de react-native

0.59.10

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

Androide

Comportamiento esperado

Cuando se actualiza / degrada una suscripción con el modo DEFERRED, se debe llamar al oyente de actualización de compra con un nuevo recibo de transacción.

Comportamiento real

Se llama al oyente de error de compra con el siguiente error:

{mensaje: 'las compras son nulas',
código: 'OK',
debugMessage: '',
responseCode: 0}

Entorno probado (¿Emulador? ¿Dispositivo real?)

Dispositivo real - caja de arena

Pasos para reproducir el comportamiento

1.Compre una suscripción con RNIap.requestSubscription (sku), esto funciona correctamente.

2.Actualice o baje la suscripción con RNIap.requestSubscription (newSku, false, sku, 4). (4 es el modo de prorrateo DIFERIDO) El cuadro de diálogo de facturación de Google Play mostrará que el plan de suscripción se cambió correctamente y recibirá una notificación por correo electrónico de Google Play al respecto. Sin embargo, se llama al detector de errores con el error mencionado anteriormente.

3.Si vuelve a llamar a RNIap.requestSubscription (newSku, false, sku, 4), el cuadro de diálogo de facturación de Google Play indicará que no pueden cambiar el plan de suscripción y se llamará al oyente de errores con el siguiente error:

{mensaje: 'Google indica que tenemos algún problema para conectarnos al pago.',
código: 'E_DEVELOPER_ERROR',
debugMessage: '',
responseCode: 5}

Pero a veces, el cuadro de diálogo de facturación de Google Play indicará que su pedido está en proceso y que su producto debería entregarse pronto, y se llama al oyente de errores con el siguiente error:

{mensaje: 'Ya eres propietario de este artículo',
código: 'E_ALREADY_OWNED',
debugMessage: '',
responseCode: 7}

Supongo que esto se debe a que la transacción del paso 2 está esperando ser reconocida. Sin embargo, dado que el paso 2 no devuelve un recibo, no podemos acusar recibo.

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

Comentario más útil

¿Tiene planes de resolver este problema?

Todos 31 comentarios

Intente llamar al getAvailablePurchases después de actualizar / degradar la suscripción.
Consulte el documento The list of Purchase objects in onPurchasesUpdated() does not contain paused subscriptions. .

No estoy muy seguro, espero que ayude. No dude en dejar cualquier otra prueba y discusión.

Intenté getAvailablePurchases () después de actualizar / degradar la suscripción, pero desafortunadamente, solo el recibo de transacción de la compra original está en la matriz devuelta.

RNIap v2.3.19 y v2.5.5 funciona correctamente, buySubscription () devolverá un nuevo recibo cuando actualice / baje la suscripción. Pero me gustaría actualizar a v3 o v4, que tiene un mejor modelo basado en eventos si es posible.

Aquí hay un documento de referencia que explica cómo funciona la actualización / degradación de la suscripción de Android y por qué necesitamos el nuevo recibo después de la actualización / degradación.

@ howg0924 Gracias por confirmar esto. Me gustaría comparar las diferencias con la v2 y nuestra versión actual y ver cómo puedo solucionar este problema.

Busqué el código el fin de semana en el n. ° 893
La nueva actualización llegará en 4.4.0 .

¿Podría probar la versión [email protected] ?

@hyochan Acabo de probar 4.4.0-rc.1, pero la situación sigue siendo la misma.

Después de llamar a RNIap.requestSubscription (oldSku, false, newSku 4) y finalizar la actualización / degradación, se llama al detector de errores con el siguiente error:

{mensaje: 'las compras son nulas',
código: 'OK',
debugMessage: '',
responseCode: 0}

Y getAvailablePurchases () solo contiene un recibo antiguo.

@ howg0924 Si sabes cómo depurar android , espero que pruebes poniendo algunas Log.d y veas si pasa las condiciones if en buyItemByType . ¿Sería eso posible para ti? Quiero ver cómo se están ejecutando.

@ howg0924 ¡Oh, espera ~! Creo que encontré el problema, déjame contactarte pronto.

@ howg0924 ¿Podrías probar 4.4.0-rc.2 ? Creo que funcionará esta vez.

La compilación de @hyochan 4.4.0-rc.2 falló en:

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

@hyochan Supervisé buyItemByType () de 4.4.0-rc.1. Al actualizar / degradar, se ejecutó:

builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED);

y también ejecutado:

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

¿Quieres que supervise / vuelque algún flujo / datos?

(eliminado debido a un malentendido)

@ howg0924 Lamento haber cometido un error porque no tuve una buena depuración env . He revertido esto en 4.4.0-rc.3 . Parece que su código no se está ejecutando builder.setOldSku(oldSku) que es lo más importante.

Después de comparar con 2.5.5, encontré que 2.5.5 no llama

builder.setReplaceSkusProrationMode (BillingFlowParams.ProrationMode.DEFERRED);

cuando se utiliza el modo DIFERIDO.

Así que trato de eliminar esta línea en 4.4.0-rc.1, ¡y funciona! Pero no lo sé:

1.En qué modo de prorrateo está trabajando ahora.
2.por qué no funciona cuando setReplaceSkusProrationMode () lo establece en modo DIFERIDO

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

Actualmente estamos pasando el ProrationMode como arriba. Entonces, ¿eso significa que puede auto renew subscription cuando haya eliminado DEFERRED ?

Quiero decir, si cambio el código a:

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

entonces puedo usar RNIap.requestSubscription (newSku, false, sku, 4 / * modo DEFERRED * /) para actualizar / degradar una suscripción. Aunque no estoy seguro de en qué modo de prorrateo funciona realmente, ya que builder.setReplaceSkusProrationMode () no se ejecuta, como lo hizo v2.5.5.

El siguiente código es de 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 Bueno, esto es muy extraño ya que ni siquiera configuramos DEFFERED en nuestra rama maestra actual, que es 4.3.4 . Agregué este código en 4.4.0+ .

Creo que la razón puede ser diferente. Espero que pueda volver si hay alguna otra noticia.

Relacionado # 391 # 555

Bien, intentaré más e informaré.

Relacionado # 707

@hyochan Después de más pruebas en 4.4.0-rc.1:

IMMEDIATE_WITH_TIME_PRORATION => funciona
IMMEDIATE_AND_CHARGE_PRORATED_PRICE => funciona
IMMEDIATE_WITHOUT_PRORATION => funciona
DIFERIDO => NO FUNCIONA (no sé por qué)

Bueno, esto es muy extraño ya que ni siquiera configuramos DEFFERED en nuestra rama maestra actual, que es 4.3.4. Agregué este código en 4.4.0+.

Creo que esto se debe a que el siguiente código en 4.3.0 aún lo establece en modo DIFERIDO:

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

Sin embargo, el código anterior no existe en 2.3.19 y 2.5.5. Por lo tanto, cuando llamé a RNIap.requestSubscription (newSku, false, sku, 4 / * DEFERRED * /) en 2.3.19 y 2.5.5, pensé que funcionaba antes, pero ahora me di cuenta de que en realidad funcionaba en el modo predeterminado IMMEDIATE_WITH_TIME_PRORATION.

Bien, entonces deberíamos saber por qué el diferido no funcionará. No pude encontrar la razón por ahora.

Tengo el mismo problema pero el comportamiento es diferente.

Cuando llamo a requestSubscription(newSku, false, oldSku, 4) , arroja un error con el código de error OK y un mensaje de error vacío. El pago en el lado de Google Play es el esperado (está diferido). Cuando ocurre el próximo cargo de suscripción, obtengo purchaseUpdatedListener evento al iniciar la aplicación, pero no puedo reconocer la compra (llamando a finishTransaction() ). finishTransaction() da un error DEVELOPER_ERROR .

Ocurre en ambas versiones 4.4.0 y 4.3.4 .

Hola @hyochan , vi que en https://github.com/dooboolab/react-native-iap/pull/893 marcaste esto como resuelto pero actualicé react-native-iap a la última versión, pero esta todavía no se reparado. Sigo recibiendo un error en el oyente error {"code": "OK", "debugMessage": "", "message": "purchases are null.", "responseCode": 0} y recibí el correo electrónico You updated your subscription purchase normalmente. Entonces, mi pregunta es ¿cuál es la solución correcta para el modo DIFERIDO?

La última vez que encontré este problema tampoco. Curiosamente, no funciona solo en el modo deferred . Necesitamos investigar esto.

Hola @ howg0924 , ¿ya

@ nenjamin2405 No, todavía estoy usando el modo IMMEDIATE_WITH_TIME_PRORATION predeterminado, y realmente espero que esto pueda solucionarse.

Hola @hyochan , ¿alguna actualización sobre esto? La nueva función de mi aplicación está bloqueada por este problema. Realmente aprecio su esfuerzo en investigar esto, gracias

Aún no. No he tenido tiempo de repasar este tema.
Espero que alguien también traiga información útil para manejar este problema.
Preguntar Google o StackOverflow y compartirlo en este hilo podría ser realmente útil.

Hola, parece que no ha habido actividad sobre este tema recientemente. ¿Se ha solucionado el problema o aún requiere la atención de la comunidad? Este problema puede cerrarse si no se produce más actividad. También puede etiquetar este problema como "Para discusión" o "Buen primer número" y lo dejaré abierto. Gracias por sus aportaciones.

Hemos estado analizando este problema y queríamos compartirlo con la comunidad, puede ayudar a algunas personas.

El problema se debe a que se llama al oyente actualizado de compra con una lista vacía de compras en un reemplazo de suscripción diferida, que es cómo funciona Android (consulte aquí "Para el modo de reemplazo diferido ...")

Agregamos la compatibilidad con el reemplazo de suscripción diferida de Android en purchases are null en un reemplazo de suscripción. ( Ver compromiso )

Por supuesto, también tendrá que hacer algunas modificaciones en el lado del servidor para validar sus recibos, actualizar el recibo no es suficiente cuando se trata de suscripciones diferidas.
Tendrá que implementar las notificaciones de Android en tiempo real para detectar cuándo se está produciendo el reemplazo de la suscripción y procesar un nuevo token.

O simplemente puede usar IAPHUB, que está haciendo todo eso por usted 🙂

¿Tiene planes de resolver este problema?

Como menciona @iaphub , el problema es que onPurchasesUpdated se llama con el argumento purchases como null cuando se usa el modo DEFERRED.

De los documentos de Google :

Para el modo de reemplazo diferido, su aplicación recibe una llamada a su comprador actualizado con una lista vacía de compras y un estado de si la actualización o la degradación fue exitosa.

Así que es solo una cuestión de manejar ese caso dentro de ese oyente.

Pero no estoy seguro de cuál debería ser la forma adecuada de manejar esa situación:

  • Resolviendo la promesa con la información de suscripción anterior
  • Resolviendo la promesa con undefined
  • Rechazar la promesa con un código PURCHASE_DEFERRED

¿Qué piensas?

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

Temas relacionados

Gribadze picture Gribadze  ·  4Comentarios

ramondelmondo picture ramondelmondo  ·  4Comentarios

bakedbean picture bakedbean  ·  5Comentarios

schumannd picture schumannd  ·  3Comentarios

iutin picture iutin  ·  4Comentarios