Search code examples
javaandroidlibgdxbilling

Implementing In-App Billing with libgdx


So this is an issue I´ve dealt with for about 2 months now and I really need some assistance with this one. Im doing an app and I want the user to be able to buy certain stuff.

I´ve followed this guide as far as I´ve been capable: http://developer.android.com/google/play/billing/billing_integrate.html

The thing is, Im using Libgdx which makes it a bit tricky for me. I got it most of the stuff implemented in the AndroidLauncher class which is the main I suspect. Looks like this:

public class AndroidLauncher extends AndroidApplication {

IInAppBillingService mservice;
ServiceConnection connection = new ServiceConnection() {

    public void onServiceConnected(ComponentName name, IBinder service) {
        mservice = IInAppBillingService.Stub.asInterface(service);


    }





    @Override
    public void onServiceDisconnected(ComponentName name) {

        mservice = null;
    }





};


@Override
protected void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
    initialize(new TombStone(null), config);

    Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
    serviceIntent.setPackage("com.android.vending");
    bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);


    // The list the holds all the items available for purchase
    ArrayList<String> skuList = new ArrayList<String> ();
    skuList.add("premiumUpgrade");
    skuList.add("gas");
    Bundle querySkus = new Bundle();
    querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

    try {
        Bundle skuDetails = mservice.getSkuDetails(3, getPackageName(), "inapp", querySkus);
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}


@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    if(mservice != null) {
        unbindService(connection);
    }
}

}

Although that class isn´t the class where the actuall "store" screen is. That is this class:

public class Stones implements Screen {


OrthographicCamera camera;
final TombStone game;


private Stage stage;
private TextureAtlas atlas;
private Skin skin;
private Table table;
private BitmapFont font;
ImageButton btnArrow, btnArrowLeft, imageButton1, imageButton2, imageButton3, imageButton4, imageButton5, imageButton6;


public  Texture background, testImage, arrow, arrowLeft;
public  TextureAtlas buttonAtlas;

public Stones(TombStone gam)    {
    game = gam;

    game.assets.load();
    loadStore();
    camera = new OrthographicCamera();
    camera.setToOrtho(false, 136, 204);



}

public void loadStore()  {
    background = game.assets.storeBackground;
    testImage = game.assets.image;
    arrow = game.assets.arrow;
    arrowLeft = game.assets.arrowLeft;
}

@Override
public void render(float delta) {

    camera.update();
    game.batch.setProjectionMatrix(camera.combined);


    game.batch.begin();

    game.batch.draw(background, 0, 0, 136, 204);
    game.font.setScale(0.5f);
    game.font.draw(game.batch, "This is the current selection of tombstones! Simply click the image of the stone you want to buy it.", 50, 200);

    game.batch.end();

    //Draws the ImageButtons
    stage.act();
    stage.draw();

}

@Override
public void resize(int width, int height) {
    // TODO Auto-generated method stub

}

@Override
public void show() {

    Skin skin = new Skin();



    //ArrowButtons
    Skin skinTwo = new Skin();
    buttonAtlas = new TextureAtlas(Gdx.files.internal("arrow.pack"));
    skinTwo.addRegions(buttonAtlas);
    ImageButtonStyle styleTwo = new ImageButtonStyle();
    TextureRegionDrawable arrowImage = new TextureRegionDrawable(new TextureRegion(new Texture("arrowLeft.png")));
    styleTwo.up = skinTwo.newDrawable(skinTwo.newDrawable(arrowImage));
    styleTwo.down = skinTwo.newDrawable(skinTwo.newDrawable(arrowImage));



    //ImageButtons - Category buttons
    ImageButtonStyle style = new ImageButtonStyle();
    TextureRegionDrawable ibimage = new TextureRegionDrawable(new TextureRegion(new Texture("image.png")));

    style.up = skin.newDrawable(skin.newDrawable(ibimage));
    style.down = skin.newDrawable(skin.newDrawable(ibimage));
    imageButton1 = new ImageButton(style);
    imageButton2 = new ImageButton(style);
    imageButton3 = new ImageButton(style);
    imageButton4 = new ImageButton(style);
    imageButton5 = new ImageButton(style);
    imageButton6 = new ImageButton(style);

    //ArrowButtons implement
    btnArrow = new ImageButton(styleTwo);

    btnArrow.setSize(150, 150);
    btnArrow.setPosition(450, 10);


    /*table = new Table();
    table.setBounds(100, 100, 100, 100);

    skin = new Skin();
    font = new BitmapFont();

    TextureRegion image = new TextureRegion(testImage);
    stage = new Stage();
    Gdx.input.setInputProcessor(stage);

    //ImageButtonStyle style = new ImageButtonStyle(skin.get(ButtonStyle.class));
    //style.imageUp = new TextureRegionDrawable(image);
    //style.imageDown = new TextureRegionDrawable(image);
    ImageButton iconButton = new ImageButton(skin);

    //Button imgButton = new Button(new Image(image), skin);*/



    //Stage for the BuyImages
    stage = new Stage();



    table = new Table();
    table.setBounds(20, 320, 175, 1050);

    table.add(imageButton1).pad(5).size(175, 175).row();
    table.add(imageButton2).pad(5).size(175, 175).row();
    table.add(imageButton3).pad(5).size(175, 175).row();
    table.add(imageButton4).pad(5).size(175, 175).row();
    table.add(imageButton5).pad(5).size(175, 175).row();
    table.add(imageButton6).pad(5).size(175, 175).row();



    stage.addActor(table);
    stage.addActor(btnArrow);

    Gdx.input.setInputProcessor(stage);


    //Backbutton
    btnArrow.addListener(new ChangeListener() {

        @Override
        public void changed(ChangeEvent event, Actor actor) {
            game.setScreen(new StoreScreen(game));

        }


    });

    imageButton1.addListener(new ChangeListener() {

        @Override
        public void changed(ChangeEvent event, Actor actor) {


        }


    });

}

@Override
public void hide() {
    // TODO Auto-generated method stub

}

@Override
public void pause() {
    // TODO Auto-generated method stub

}

@Override
public void resume() {
    // TODO Auto-generated method stub

}

@Override
public void dispose() {
    // TODO Auto-generated method stub

}

}

So I suspect that I´ll need to link the first class to the second somehow to be able to use the stuff I´ve implemented in the first one? But how? And after that Im sort of lost. I´ve looked at a bunch of tutorials but none describes my problem more specificly. Help would be tremendous! Thanks in advance


Solution

  • There is a Libgdx extension library for handling in-app purchases in a cross-platform way: https://github.com/libgdx/gdx-pay. Its not as well tested as the rest of libgdx yet, but its probably a good place to start. Using this will side-step your problem.

    However, getting what you've got working isn't too hard (hopefully) so that is also a viable approach. Basically, you need to get your platform-independent app code to talk to the backend-specific code. Generally, this is done in Libgdx applications by defining an interface that the platform independent code (your "Stones" class) can use, and defining an implementation of that interface in each supported backend. So, in your case you can add that interface to your AndroidLauncher (but its probably better to create a new class that implements it). If you have any other backends (e.g., the desktop one) you'll need to create an implementation that stubs out the API so your code will still run on the desktop (or whichever). Then when each backend starts up, it has to pass its implementation of the interface into the constructor of the platform-independent class. The Libgdx documentation covers this in general here (they use the example of a leaderboard): https://github.com/libgdx/libgdx/wiki/Interfacing-with-platform-specific-code