NiPfi
NiPfi

Reputation: 1720

Android In-app billing error: Illegal state for operation (launchPurchaseFlow): IAB helper is not set up

I tried setting up InApp purchases for a donation with the guide provided by Google but when I call the activity (which should return if it was a success or not) but it throws this error:

In-app billing error: Illegal state for operation (launchPurchaseFlow): IAB helper is not set up

The activity is called with this method:

public boolean donation() {
        int success = 0;
        Intent intent = new Intent(Main.this, Donate.class);
        startActivityForResult(intent, success);
        if (success != 0) {
            return true;
        }
        else return false;
    }

And the Donate class (which I tried coding with the guide) looks like this:

import java.math.BigInteger;
import java.security.SecureRandom;
import maturaarbeit.nicola_pfister.marks.R;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.util.Log;

public class Donate extends Activity {

    IabHelper mHelper;

    private static final String TAG = "Donate";
    private String payload;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String base64EncodedPublicKey = getKey();
        mHelper = new IabHelper(this, base64EncodedPublicKey);

        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {

            @Override
            public void onIabSetupFinished(IabResult result) {
                if (!result.isSuccess()) {
                    Log.d(TAG, "Problem setting up In-app Billing: " + result); 
                }
            }
        });

        SharedPreferences prefs = getSharedPreferences(getPackageName() + "_preferences", MODE_PRIVATE);    //Add shared preferences
        payload = prefs.getString("devpayload", null);
        if (payload == null) {
            payload = getPayload();

            Editor editor = prefs.edit();
            editor.putString("devpayload", payload)
            .apply();
        }
        mHelper.launchPurchaseFlow(this, "donation_1chf", 1, mPurchaseFinishedListener, payload);
        finish();
    }

    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {

        @Override
        public void onIabPurchaseFinished(IabResult result, Purchase info) {
            if (result.isFailure()) {
                Log.d(TAG, "Error purchasing: " +result);
                return;
            }
            else if (info.getDeveloperPayload().equals(payload)) {
                return;
            }
        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        } else {
            Log.i(TAG, "onActivityResult handled by IABUtil.");
        }
    }

    private String getKey() {
        //Code for building public key
    }

    private String getPayload() {
      SecureRandom random = new SecureRandom();
      {
        return new BigInteger(130, random).toString(32);
      }
    }

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

}

It is supposed to generate a dev payload which is stored in shared prefs if there isn't already one. If you need any additional information feel free to ask.

Thanks for your help!

Upvotes: 7

Views: 6937

Answers (3)

Alireza Jamali
Alireza Jamali

Reputation: 317

if you have targetSdkVersion 30+ you have to query the market in your AndroidManifest and declare that your app wants to use its services. use this to see if you already have that among the list

for (ApplicationInfo a : getPackageManager().getInstalledApplications(PackageManager.GET_META_DATA)){
    System.out.println(a.name);
}

if not, you have to declare the market's package in your AndroidManifest these two are for bazaar and myket, don't know about playstore, Huwai or Galaxy

<queries>
    <package android:name="com.farsitel.bazaar" />
    <package android:name="ir.mservices.market" />
</queries>

if you don't know their packages, you can add the intent those stores use, that way you also declare that you query every other app that uses that specific intent. which every store have to use.

<queries>
    <intent>
        <action android:name="android.intent.action.MAIN" />
    </intent>
</queries>

when you use this query, you can call the method getInstalledApplications I mentioned earlier and get the new list, find the store's package and just replace your query with the package only

Upvotes: 0

Burak iren
Burak iren

Reputation: 336

You should use real device for app billing because when using emulator some parameters are being null and it causes runtime errors.

Upvotes: 5

ianhanniballake
ianhanniballake

Reputation: 199805

You have to wait for onIabSetupFinishedListener to return before calling launchPurchaseFlow - move those lines into your onIabSetupFinishedListener's onIabSetupFinished method to ensure that the IabHelper's setup is complete:

mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
        @Override
        public void onIabSetupFinished(IabResult result) {
            if (!result.isSuccess()) {
                Log.d(TAG, "Problem setting up In-app Billing: " + result); 
            }
            else { // Only launch the purchase flow if setup succeeded
                mHelper.launchPurchaseFlow(Donate.this, "donation_1chf", 1,
                    mPurchaseFinishedListener, payload);
            }
        }
    });

Upvotes: 5

Related Questions