Android In-App Billing V3: "impossible d'effectuer l'opération: queryInventory"

J'ai configuré la facturation intégrée à L'application pour la première fois en utilisant la nouvelle API v3. Il fonctionne correctement sur mes appareils, mais j'ai reçu beaucoup de rapports d'erreurs d'autres utilisateurs.

L'Un d'eux est:

java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: queryInventory
    at my.package.util.iab.IabHelper.checkSetupDone(IabHelper.java:673)
    at my.package.util.iab.IabHelper.queryInventory(IabHelper.java:462)
    at my.package.util.iab.IabHelper$2.run(IabHelper.java:521)
    at java.lang.Thread.run(Thread.java:1019)

Et un autre est:

java.lang.NullPointerException
    at my.package.activities.MainActivity$4.onIabSetupFinished(MainActivity.java:159)
    at my.package.util.iab.IabHelper$1.onServiceConnected(IabHelper.java:242)

Mon implémentation d'activité suit le code d'exemple de Google (toutes les classes référencées ne sont pas touchées par l'exemple):

IabHelper mHelper;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //...

    mHelper = new IabHelper(this, IAB_PUBLIC_KEY);
    mHelper.enableDebugLogging(true);

    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
        public void onIabSetupFinished(IabResult result) {
            if (!result.isSuccess()) {
                // Oh noes, there was a problem.
                return;
            }

            // Hooray, IAB is fully set up. Now, let's get an inventory of
            // stuff we own.
            mHelper.queryInventoryAsync(mGotInventoryListener); //***(1)***
        }
    });
}

// Listener that's called when we finish querying the items we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result,
            Inventory inventory) {
        if (!result.isFailure()) {
            if (inventory.hasPurchase(SoundsGlobals.IAB_SKU_PREMIUM)){
                //we are premium, do things
            }
        }
        else{
            //oops
        }
    }
};

@Override
protected void onDestroy() {
    if (mHelper != null) {
        mHelper.dispose();
        mHelper = null;
    }
    super.onDestroy();
}

Je suppose que les erreurs proviennent de la ligne marquée comme ***(1)***

Quelle est la cause de ces les erreurs? Si j'appelle {[4] } uniquement dans onIabSetupFinished, Comment est-il possible que mHelper soit null ou que mHelper ne soit pas configuré?

Est-ce que quelqu'un connaît une solution à cela?

29
demandé sur Ereza 2012-12-25 04:12:58

11 réponses

Comme @Martin l'a expliqué, il y avait un bug dans L'exemple de facturation Google In-App qui a causé cela.

Cependant, après l'avoir réparé, je recevais toujours des erreurs dans les appels internes (queryInventory à l'intérieur du thread créé dans queryInventoryAsync dans de rares cas, signale que l'Assistant n'est pas configuré). J'ai résolu cela en ajoutant une prise supplémentaire dans ce cas:

try {
    inv = queryInventory(querySkuDetails, moreSkus);
}
catch (IabException ex) {
    result = ex.getResult();
}
catch(IllegalStateException ex){ //ADDED THIS CATCH
    result = new IabResult(BILLING_RESPONSE_RESULT_ERROR, "Helper is not setup.");
}

J'ai aussi eu un crash sur mHelper.dispose() que j'ai fixé de manière similaire:

try{
    if (mContext != null) mContext.unbindService(mServiceConn);
}
catch(IllegalArgumentException ex){ //ADDED THIS CATCH
    //IGNORE IT - somehow, the service was already unregistered
}

Bien sûr, au lieu d'ignorer ces erreurs, vous peut les connecter silencieusement à ACRA, par exemple:)

Merci pour tous vos commentaires.

19
répondu Ereza 2013-03-09 13:29:07

Il y a un bug dans IABHelper. La ligne de retour dans le gestionnaire d'exception est manquante, ce qui signifie qu'elle passe et appelle le hanlder de succès-cependant, mSetupDone n'a pas été défini, donc d'autres appels à L'API échouent. Ajoutez l'instruction return comme ci - dessous-cela échouera toujours, mais l'échec sera correctement signalé à votre application afin que vous puissiez prendre les mesures appropriées.

                catch (RemoteException e) {
                if (listener != null) {
                    listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION,
                                                "RemoteException while setting up in-app billing."));
                }
                e.printStackTrace();
                return;  // This return line is missing
            }

            if (listener != null) {
                listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful."));
            }
14
répondu Martin 2013-02-06 20:01:07

Je crois qu'il y a encore deux bugs dans le code Android, ce qui explique pourquoi vous voyez toujours l'erreur. Notez que la pile d'appels est sur un thread autonome. Mais le code qui définit mSetupDone (IabHelper) à true s'exécute sur le thread principal de l'interface utilisateur. Java ne garantit pas que les données modifiées par un thread seront visibles pour l'autre thread en raison de la mise en cache du processeur, sauf si vous déclarez la variable avec le mot-clé volatile. Ainsi, il est possible qu'il ait été configuré (mSetupDone == true), mais que le la nouvelle valeur de mSetupDone est mise en cache sur le thread de L'interface utilisateur, pas encore visible pour ce thread dans votre pile d'appels. Donc, ce thread voit toujours mSetupDone = = false.

J'ai essayé de résoudre ce problème en déclarant mSetupDone avec volatile, et aussi tous les autres champs non finaux de IabHelper juste pour être sûr.

Maintenant l'autre problème est la .disposer () fonction. Cela n'arrête pas les threads en cours. Cela signifie qu'il peut définir mSetupDone sur false pendant que l'un des threads de travail est en cours d'exécution. Si vous regardez queryInventoryAsync (), vous verrez qu'il vérifie que mSetupDone est vrai. Et en fonction de votre pile d'appels, il a dépassé cela. Puis il s'est écrasé plus tard avec mSetupDone = = false. La seule façon qui pourrait arriver est si dispose () ont été appelés pendant que votre thread était en vol. Le correctif est que dispose () doit signaler aux threads de simplement renflouer silencieusement au lieu de continuer et de lancer des erreurs quand il voit mSetupDone == false. Cela empêche également un autre problème avec IabHelper où les instances éliminées appellent appels d'écoute même après avoir été éliminés! C'est un peu compliqué d'expliquer ligne par ligne ici, mais j'espère que vous serez ainsi pointé dans la bonne direction.

10
répondu David M 2013-05-25 19:41:17

Je l'ai découvert! Il s'agit de la version de L'application Google Play Store de l'utilisateur. La facturation intégrée à l'application v3 nécessite 3.9.16 ou supérieur ( http://developer.android.com/google/play/billing/versions.html ). J'ai utilisé une version plus ancienne et j'ai reçu cette erreur, maintenant sur 4.4.21 c'est ok!

6
répondu edwell 2013-11-06 17:11:04

Assurez-vous que vous implémentez la méthode IabHelper.han.handleActivityResult(requestCode, resultCode, data) dans votre méthode activities onActivityResult.

   @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

// Pass on the activity result to the helper for handling
  if (!mIabHelper.handleActivityResult(requestCode, resultCode, data)) {
      // not handled, so handle it ourselves (here's where you'd
      // perform any handling of activity results not related to in-app
      // billing...
      super.onActivityResult(requestCode, resultCode, data);
  } else {
      Log.i(TAG, "onActivityResult handled by IABUtil.");
  }
}
2
répondu KevinM 2013-01-02 07:36:22

Je reçois exactement la même erreur avec à peu près le même code exact.

Ne semble se produire sur certains combinés (en fait, il semble presque exclusivement la Tablette Acer Iconia dans les rapports d'erreur récents!!) - et je gère onActivityResult...

Il y a un certain nombre d'erreurs dans L'échantillon de facturation Google V3 qui peuvent causer ANRs/FCs - je soupçonne que c'est juste un autre (code de mauvaise qualité et docs de mauvaise qualité deviennent une marque Google - malheureusement).

Ma conjecture est - pour l'instant - que nous devons permettre soit mHelper ou mGotInventoryListener étant null et juste désactiver la facturation dans L'application dans ce cas (comme si le résultat.isSuccess() était faux, fondamentalement)

P. S. editted pour ajouter-il se pourrait juste que l'utilisateur ait une version obsolète du Play Store-que seules les mises à jour automatiques s'ils lui permettent de s'exécuter!?

2
répondu 2013-01-04 12:25:02

Vous pouvez vous tenir à jour avec le développement de L'API inapp v3 à https://code.google.com/p/marketbilling/

Le code est plus récent que celui qui est disponible via le gestionnaire de SDK Android.

1
répondu Catalin Morosan 2013-04-23 07:58:50

En plus de @ DavidM et @Ereza.

Un autre problème majeur avec la classe IabHelpr est le mauvais choix de lancer RuntimeExcptions (IllegalStateException) dans plusieurs méthodes. Lancer RuntimeExeptions à partir de votre propre code dans la plupart des cas n'est pas souhaitable en raison du fait qu'ils sont exceptions non cochées. C'est comme saboter votre propre application-si ce n'est pas pris, ces exceptions vont exploser et planter votre application.

La solution consiste à implémenter la vôtre exception vérifiée {[6] } et changez la classe IabHelper pour la lancer, au lieu de L'Exception IllegalStateException. Cela vous forcera à gérer cette exception partout où elle pourrait être lancée dans votre code au moment de la compilation.

Voici mon exception personnalisée:

public class MyIllegalStateException extends Exception {

    private static final long serialVersionUID = 1L;

    //Parameterless Constructor
    public MyIllegalStateException() {}

    //Constructor that accepts a message
    public MyIllegalStateException(String message)
    {
       super(message);
    }
}

Une fois que nous avons fait les changements dans la classe IabHelper, nous pouvons gérer notre exception vérifiée dans notre code où nous appelons les méthodes de classe. Par exemple:

try {
   setUpBilling(targetActivityInstance.allData.getAll());
} catch (MyIllegalStateException ex) {
    ex.printStackTrace();
}
1
répondu Dimitar Darazhanski 2014-11-02 17:16:46

Si tout ce qui précède ne vous aide pas, essayez d'analyser un peu votre code - Votre IabHelper est-il vraiment configuré au moment où vous l'appelez?

Je me suis retrouvé à le faire un peu mal sans m'en rendre compte. Un exemple simple d'utilisation il tort dans Activity.onCreate()

m_iabHelper = new IabHelper(this, base64EncodedPublicKey); // Declare

m_iabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { // Setup
    public void onIabSetupFinished(IabResult result) {
        // Setup code
    }
}

// Don't do this, will produce an error
List additionalSkuList = new ArrayList(); 
additionalSkuList.add(SKU_MYSKU);
m_iabHelper.queryInventoryAsync(true, additionalSkuList, m_queryFinishedListener);
// Don't do this, will produce an error

.

Ci-dessus vous honorera avec l'erreur "IAB helper n'est pas configuré" car pendant que votre application essaie d'exécuter le m_iabHelper.queryInventoryAsync(), L'IabHelper n'est pas encore configuré. Envisager l'utilisation de ces fonctions dans onIabSetupFinished() ou quelque part après que cette fonction est appelée (par exemple. en dehors du onCreate())

1
répondu Voy 2014-11-11 22:45:37

Je reçois les mêmes erreurs. J'ai également fait d'autres questions...

Avoir plus d'un compte google sur un appareil désactivé facturation intégrée à l'application sur mon Galaxy Tab 7. Supprimer un compte réactivé.

J'ai vu des problèmes avec l'exemple de code de facturation intégré à L'application sur un GT-P5110, LGL75C et GT-S5839i, entre autres.

(j'utilise le code dans une application avec ACRA installé... donc, chaque fois qu'il se bloque, je reçois des informations)

Les appareils Android version Varie de 2.3.3 à 4.0.4.

C'est très ennuyeux.

0
répondu orb360 2013-01-11 00:44:01

Il y avait beaucoup de problèmes avec IABHelper.Java.

Tout d'abord - la version téléchargée par le Gestionnaire de SDK n'est pas mise à jour. Utilisez la version trouvée ici: https://code.google.com/p/marketbilling/source/detail?r=15946261ec9ae5f7c664d720f392f7787e3ee6c7 c'est la version la plus à jour au moment de publier cette réponse. De nombreux problèmes semblent avoir été corrigés avec cette version par rapport à la version initiale qui provient du Gestionnaire de SDK.

La seule chose que j'ai eu à faire le changement dans cette version ajoute flagEndAsync(); après la ligne 404 qui corrige une exception IllegalStateException lorsque 2 flux D'achat IAB sont lancés en succession rapide.

Avec cette version, vous n'avez pas besoin de gérer en utilisant flagEndAsync(); dans vos fichiers et pouvez laisser la méthode pour ne pas être publique.

0
répondu Uwais A 2015-04-20 15:46:31