web-dev-qa-db-fra.com

Android In App Billing: Impossible de lancer launchPurchaseFlow car launchPurchaseFlow est en cours.

J'implémente In App Billing pour la première fois et je teste mes premiers achats à l'aide des identifiants de SKU statiques. 

Cela a très bien fonctionné la première fois. J'ai appelé mHelper.launchPurchaseFlow(...) et terminé l'achat du test. Mon activité a reçu le rappel onActivityResult et je me suis assuré de le traiter avec mHelper.handleActivityResult(...). Tout était super. 

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Pass on the activity result to the helper for handling
    log("onActivityResult");
    if (!this.mHelper.handleActivityResult(requestCode, resultCode, data)) {
        log("cleared the launch flow");
        // 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);
    }
}

Cependant, je voulais tester la partie suivante, j'ai donc relancé l'application et essayé d'acheter le même SKU (le statique purchased SKU). 

mHelper.launchPurchaseFlow(rootActivity, "Android.test.purchased", 10002,   
       new IabHelper.OnIabPurchaseFinishedListener() {

        @Override
        public void onIabPurchaseFinished(IabResult result, Purchase purchaseInfo) {
            if (result.isFailure()) {
                log("purchased failed");
            } else {
                log("purchase succeeded");
            }
        }
    }, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

La deuxième fois que j'essaie d'acheter l'article, ma OnIabPurchaseFinishedListener est appelée et je vois purchase failed dans mon journal: "Erreur de facturation intégrée à l'application: impossible d'acheter un article, réponse d'erreur: 7: article déjà en possession"

Cela a du sens, mais si j'essaie d'acheter un autre article, mon application se bloque avec l'erreur suivante:

Java.lang.IllegalStateException: impossible de démarrer l'opération asynchrone (launchPurchaseFlow) car un autre asynchrone opération (launchPurchaseFlow) est en cours.

Le rappel onActivityResult ne se produit pas lorsque j'essaie de faire un achat qui échoue. Le flux de lancement qui a échoué n'est ni traité ni nettoyé. Ainsi, lorsque j'essaye un autre achat, c'est la raison pour laquelle il se bloque car il est censé être encore au milieu de la dernière transaction ayant échoué.

Qu'est-ce que je fais mal? Comment puis-je m'assurer que la commande launchPurchaseFlow () est nettoyée après une défaillance?

36
Kenny Wyland

Je sais que c'est un peu une contribution tardive à la question, mais je faisais face au même problème aujourd'hui et j'appelais la facturation intégrée à l'application dans un fragment. J'ai donc cherché dans "labHelper.Java" et j'ai trouvé une solution directe qui, je le crois le problème qui est ... J'ai modifié la méthode "void flagStartAsync (String operation)" dans labHelper.Java pour ressembler à ceci

void flagStartAsync(String operation) {
    if (mAsyncInProgress) {
        flagEndAsync();
    }
    if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" +
            operation + ") because another async operation(" + mAsyncOperation + ") is in progress.");
    mAsyncOperation = operation;
    mAsyncInProgress = true;
    logDebug("Starting async operation: " + operation);
}

J'espère que cela aiderait quelqu'un là-bas ...

29
alazmi95

Pour moi, la meilleure solution consistait à mettre à jour le code à la version récente ( here ) et à faire ce que this post

1) rendre la méthode flagEndAsync publique. C'est là, mais pas visible.

2) demandez à chaque auditeur d’appeler iabHelper.flagEndAsync pour s’assurer que la procédure est correctement marquée; il semble être nécessaire chez tous les auditeurs.

3) entourez les appels avec un try/catch pour intercepter la IllegalStateException qui peut survenir, et gérez-le de cette façon.

La raison pour laquelle la mise à jour du code n'était pas suffisante, c'est que j'ai trouvé des cas particuliers où ce bogue se produit toujours (ou au moins un):

  • déconnecter de l'Internet;
  • entrez votre application;
  • laissez-le initialiser la IabHelper;
  • connecter à Internet;
  • une fois que l'appareil est connecté, essayez de faire un achat.
10
android developer

J'ai le même problème. 

Première tentative: solution de contournement

J'ai téléchargé la version actuelle de IabHelper.Java , conformément à la solution de jmrmb80 , mais cela n'a pas fonctionné. (Il semble que le dépôt soit maintenant deprecated et que nous devrions nous fier à la version fournie par le gestionnaire de SDK Android.) J'ai donc suivi le conseil de Khan :

  • définir IabHelper.flagEndAsync () comme public, et
  • ajouter iabHelper.flagEndAsync() avant iabHelper.launchPurchaseFlow(...)

Cela ressemble à un bidouillage flagrant! Et cela peut avoir des effets secondaires indésirables. Mais, il fonctionne"...

Cela semble être un bogue connu: # 134 et # 189 .

Deuxième tentative: réparer

Après une enquête plus approfondie, je ne pense pas que la solution ci-dessus résout mon problème. Je pense que la solution real consiste à remplacer onActivityResult dans le fil de l'interface utilisateur.

8
user2768

Pas besoin de solutions de hackers ... L'activité ou le fragment qui demande le flux d'achat doit avoir ceci:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
    if (billingHelper == null) return;

    // Pass on the activity result to the helper for handling
    if (!billingHelper.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.d(TAG, "onActivityResult handled by IABUtil.");
    }
}

Cela provient de l'exemple de projet de Google, essayé sur mon projet et cela fonctionne.

2
RominaV

Error response: 7:Item Already Owned signifie que vous avez acheté un article mais que vous ne l'avez pas encore consommé et que vous essayez de l'acheter à nouveau. 

Cela m'est arrivé lorsque j'ai activé AndroidManifest launchMode dans mon activité in-app à singleInstance. App toujours fini avec l'erreur que vous avez décrite.

Pour éviter ce problème, modifiez votre launchMode sur toute autre valeur adaptée à vos besoins Android:launchMode="singleInstance" -> Android:launchMode="singleTask"

Je n'ai pas essayé de comprendre profondément pourquoi singleInstance ne fonctionne pas. Si quelqu'un sait s'il vous plaît fournir plus d'informations.

Ma solution consistait donc à changer launchMode et à utiliser les éléments déjà possédés. Depuis ce temps, le PAI fonctionne bien pour moi.

0
Honza Musil