React-native-iap: Erro ao atualizar / fazer downgrade de assinatura no Android com modo DEFERRED

Criado em 28 dez. 2019  ·  31Comentários  ·  Fonte: dooboolab/react-native-iap

Versão do react-native-iap

4.3.3

Versão do react-native

0,59,10

Plataformas em que você enfrentou o erro (IOS ou Android ou ambos?)

Android

Comportamento esperado

Ao fazer upgrade / downgrade de uma assinatura com o modo DEFERRED, o listener de atualização de compra deve ser chamado com o novo recibo de transação.

Comportamento real

o listener de erro de compra é chamado com o seguinte erro:

{mensagem: 'as compras são nulas.',
código: 'OK',
debugMessage: '',
responseCode: 0}

Ambiente testado (emulador? Dispositivo real?)

Dispositivo real - sandbox

Passos para reproduzir o comportamento

1. Compre uma assinatura com RNIap.requestSubscription (sku), isso funciona corretamente.

2. Faça upgrade ou downgrade da assinatura com RNIap.requestSubscription (newSku, false, sku, 4). (4 é o modo de rateio DEFERIDO) A caixa de diálogo de cobrança do Google Play mostrará que o plano de assinatura foi alterado com sucesso e você receberá um e-mail de notificação do Google Play sobre isso. No entanto, o listener de erro é chamado com o erro mencionado acima.

3.Se você chamar RNIap.requestSubscription (newSku, false, sku, 4) novamente, a caixa de diálogo de faturamento do Google Play dirá que não pode alterar o plano de assinatura e o listener de erro é chamado com o seguinte erro:

{mensagem: 'O Google está indicando que temos problemas de conexão com o pagamento',
código: 'E_DEVELOPER_ERROR',
debugMessage: '',
responseCode: 5}

Mas às vezes a caixa de diálogo de faturamento do Google Play dirá que seu pedido está em processamento e seu produto deve ser entregue em breve, e o listener de erro é chamado com o seguinte erro:

{mensagem: 'Você já possui este item.',
código: 'E_ALREADY_OWNED',
debugMessage: '',
responseCode: 7}

Acho que isso se deve ao fato de a transação da etapa 2 estar esperando para ser reconhecida. No entanto, como a etapa 2 não retorna um recibo, não podemos acusá-lo.

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

Comentários muito úteis

Algum plano para resolver esse problema?

Todos 31 comentários

Tente ligar para getAvailablePurchases depois de fazer upgrade / downgrade da assinatura.
Consulte o documento The list of Purchase objects in onPurchasesUpdated() does not contain paused subscriptions. .

Não tenho certeza se espero que ajude. Sinta-se à vontade para deixar quaisquer outros testes e discussões.

Tentei getAvailablePurchases () após fazer upgrade / downgrade da assinatura, mas, infelizmente, apenas o recibo da transação da compra original está no array retornado.

RNIap v2.3.19 e v2.5.5 funciona corretamente, buySubscription () irá retornar um novo recibo quando atualizar / reduzir a assinatura. Mas eu gostaria de atualizar para a v3 ou v4, que tem um modelo baseado em eventos melhor, se possível.

Aqui está um documento de referência que explica como funciona o upgrade / downgrade da assinatura do Android e por que precisamos do novo recibo após o upgrade / downgrade.

@ howg0924 Obrigado por confirmar isso. Gostaria de comparar as diferenças com a v2 e nossa versão atual e ver como posso corrigir esse problema.

Pesquisei o código no fim de semana para você no # 893
A nova atualização chegará em 4.4.0 .

Você poderia testar a versão [email protected] ?

@hyochan Acabei de tentar o 4.4.0-rc.1, mas a situação ainda é a mesma.

Depois de chamar RNIap.requestSubscription (oldSku, false, newSku 4) e terminar a atualização / downgrade, o listener de erro é chamado com o seguinte erro:

{mensagem: 'as compras são nulas.',
código: 'OK',
debugMessage: '',
responseCode: 0}

E getAvailablePurchases () contém apenas recibos antigos.

@ howg0924 Se você sabe como depurar android , espero que teste colocando alguns Log.d e veja se passa nas condições de if em buyItemByType . Isso seria possível para você? Eu quero ver como eles estão sendo executados.

@ howg0924 Oh, espere ~! Acho que encontrei o problema, deixe-me entrar em contato em breve!

@ howg0924 Você poderia tentar 4.4.0-rc.2 ? Acho que desta vez funcionará.

@hyochan 4.4.0-rc.2 falhou em:

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

@hyochan Eu monitorei buyItemByType () de 4.4.0-rc.1. Ao fazer upgrade / downgrade, ele executou:

builder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED);

e também executou:

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

Você quer que eu monitore / despeje qualquer fluxo / dados?

(removido devido a algum mal-entendido)

@ howg0924 Desculpe ter cometido um erro porque não tive uma boa depuração env . Eu reverti isso em 4.4.0-rc.3 . Parece que seu código não está executando builder.setOldSku(oldSku) que é o mais importante.

Depois de comparar com 2.5.5, descobri que 2.5.5 não chama

builder.setReplaceSkusProrationMode (BillingFlowParams.ProrationMode.DEFERRED);

ao usar o modo DEFERRED.

Então, tento remover essa linha no 4.4.0-rc.1 e funciona! Mas, eu não sei:

1. qual modo de rateio ele está trabalhando agora.
2.por que não funciona quando definido para o modo DEFERRED por setReplaceSkusProrationMode ()

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

No momento, estamos transmitindo ProrationMode conforme acima. Então, isso significa que você pode auto renew subscription depois de remover DEFERRED ?

Quero dizer, se eu mudar o código para:

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

então posso usar RNIap.requestSubscription (newSku, false, sku, 4 / * modo DEFERRED * /) para fazer upgrade / downgrade de uma assinatura. Embora eu não tenha certeza de qual modo de rateio ele realmente funciona, já que builder.setReplaceSkusProrationMode () não é executado, como a v2.5.5.

O código a seguir é da 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 Bem, isso é muito estranho, já que nem mesmo definimos DEFFERED em nosso branch master atual, que é 4.3.4 . Eu adicionei este código em 4.4.0+ .

Acho que o motivo pode ser algo diferente. Espero que você possa voltar se houver alguma outra notícia.

Relacionado # 391 # 555

OK, vou tentar mais e apresentar um relatório.

Relacionado # 707

@hyochan Após mais testes em 4.4.0-rc.1:

IMMEDIATE_WITH_TIME_PRORATION => obras
IMMEDIATE_AND_CHARGE_PRORATED_PRICE => obras
IMMEDIATE_WITHOUT_PRORATION => trabalhos
DEFERIDO => NÃO TRABALHA (não sei por quê)

Bem, isso é muito estranho, já que nem mesmo definimos DEFFERED em nosso branch master atual, que é 4.3.4. Eu adicionei este código no 4.4.0+.

Acredito que isso seja devido ao seguinte código em 4.3.0 ainda configurá-lo para o modo DEFERRED:

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

No entanto, o código acima não existe em 2.3.19 e 2.5.5. Portanto, quando chamei RNIap.requestSubscription (newSku, false, sku, 4 / * DEFERRED * /) em 2.3.19 e 2.5.5, pensei que funcionava antes, mas agora percebi que realmente funcionava no modo IMMEDIATE_WITH_TIME_PRORATION padrão .

Ok, então devemos saber porque o Deffered não funciona. Não consegui encontrar o motivo agora.

Eu tenho o mesmo problema, mas o comportamento é diferente.

Quando eu chamo requestSubscription(newSku, false, oldSku, 4) , ele lança um erro com o código de erro OK e uma mensagem de erro vazia. O pagamento no lado do Google Play é o esperado (é adiado). Quando a próxima cobrança de assinatura acontecer, recebo purchaseUpdatedListener evento ao iniciar o aplicativo, mas não consigo reconhecer a compra (chamando finishTransaction() ). finishTransaction() dá um erro DEVELOPER_ERROR .

Acontece nas versões 4.4.0 e 4.3.4 .

Olá @hyochan , vi que em https://github.com/dooboolab/react-native-iap/pull/893 você marcou isso como resolvido, mas atualizei react-native-iap para a versão mais recente, mas esta ainda não é fixo. Ainda tenho erro no listener error {"code": "OK", "debugMessage": "", "message": "purchases are null.", "responseCode": 0} e recebi o e-mail You updated your subscription purchase normalmente. Portanto, minha pergunta é qual é a solução correta para o modo DEFERRED?

Da última vez, também encontrei esse problema. Estranhamente, não funciona apenas no modo deferred . Precisamos investigar isso.

Olá @ howg0924 , você já encontrou uma solução para esse problema?

@ nenjamin2405 Não, ainda estou usando o modo IMMEDIATE_WITH_TIME_PRORATION padrão e realmente espero que isso possa ser corrigido.

Olá @hyochan , alguma atualização sobre isso? O novo recurso do meu aplicativo está bloqueado por esse problema. Agradeço muito seu esforço em investigar isso, obrigado

Ainda não. Não tive tempo de examinar esse assunto.
Espero que alguém também traga informações úteis para lidar com esse problema.
Pedir Google ou StackOverflow e compartilhar isso neste tópico pode ser muito útil.

Olá, parece que não houve nenhuma atividade sobre este problema recentemente. O problema foi corrigido ou ainda requer a atenção da comunidade? Este problema pode ser resolvido se nenhuma outra atividade ocorrer. Você também pode rotular esse problema como "Para discussão" ou "Bom primeiro problema" e eu o deixarei em aberto. Obrigado por suas contribuições.

Estamos analisando esse problema e queríamos compartilhar com a comunidade. Isso pode ajudar algumas pessoas lá fora.

O problema é devido ao listener de compra atualizado sendo chamado com uma lista vazia de compras em uma substituição de assinatura adiada, que é como o Android funciona (veja aqui "Para o modo de substituição adiada ...")

Adicionamos o suporte de substituição de assinatura adiada android no react-native-iaphub , fazendo uma correção, observando quando o listener de erro é chamado com o erro purchases are null em uma substituição de assinatura. ( Veja commit )

É claro que você terá que fazer algumas modificações no servidor para validar seus recibos também, atualizar o recibo não é suficiente ao lidar com assinaturas adiadas.
Você terá que implementar as notificações em tempo real do Android para detectar quando a substituição da assinatura está ocorrendo e processar um novo token.

Ou você pode apenas usar o IAPHUB, que está fazendo tudo isso por você 🙂

Algum plano para resolver esse problema?

Como @iaphub menciona, o problema é que onPurchasesUpdated é chamado com o argumento purchases como null quando o modo DEFERRED é usado.

Do google docs :

Para o modo de substituição adiada, seu aplicativo recebe uma chamada para seu PurchasesUpdatedListener com uma lista vazia de compras e um status se o upgrade ou downgrade foi bem-sucedido.

Portanto, é apenas uma questão de lidar com esse caso dentro do ouvinte.

Mas não tenho certeza sobre qual deve ser a maneira adequada de lidar com essa situação:

  • Resolvendo a promessa com as informações da assinatura anterior
  • Resolvendo a promessa com undefined
  • Rejeitando a promessa com um código PURCHASE_DEFERRED

O que você acha?

Esta página foi útil?
0 / 5 - 0 avaliações