onSuccess is not getting called after purchase

I finally started using sdkbox. :smile:
I use Auto installer but it was failed to modified Cococs2dxActivity.java apart from copying jar files.
So i modified manually, now almost working fine.

But after purchase onSuccess is not getting called, item has been purchased that i can see through sdkbox debug lines.

Listeners working fine in loading screen when game starts, for IAP::restore()
But listeners not working in main menu where buy button is there.

I am using version 3.8.1 and sdkbox 0.5.7.1
One more thing i have some code for leaderboard/achievements in AppActivity.java

Okay, so i got it working by removing listener from loading screen at start. :flushed:
So that means we can have only one listener through out game for IAP? :disappointed:
then how we can restore status of items at beginning of game? :worried:
or am i missing something? :confused:
Help me out. :expressionless:
And yes i did call IAP::removeListener(); in destructer of my loading screen class.
EDIT:
still onCanceled or onFailure not getting called.

Hi @smitpatel88 I am not sure about the the failures, let us ask @nite to take a look at this.

Having a listener inside a scene is not a good practice, since scenes got created and destroyed.

You should create a global listener so it will always be there and ready to handle all the iap events.

@nite Ohk.
So i should create singleton to handle all IAP things through out game?
Let me try that.
@slackmoehrle thanks for helping.

Yes having a global IAP handler and sending out IAP events and there are logics in each scene response to different purchase events.

Hi @nite
Can you give me hint how to handle callbacks from singleton to current scene?

@smitpatel88

Completely untested:

#ifndef _IAPSINGLETON_H_
#define _IAPSINGLETON_H_

#include "cocos2d.h"
#include "PluginIAP/PluginIAP.h"

class IAPSingleton : public sdkbox::IAPListener
{
    public:
        static IAPSingleton* Instance();

    private:
        IAPSingleton();
        IAPSingleton(const IAPSingleton&);
        IAPSingleton& operator= (const IAPSingleton&);
        static IAPSingleton* pinstance;

        // IAPListener
        virtual void onInitialized(bool ok) override;
        virtual void onSuccess(sdkbox::Product const& p) override;
        virtual void onFailure(sdkbox::Product const& p, const std::string &msg) override;
        virtual void onCanceled(sdkbox::Product const& p) override;  
        virtual void onRestored(sdkbox::Product const& p) override;
        virtual void onProductRequestSuccess(std::vector<sdkbox::Product> const &products) override;
        virtual void onProductRequestFailure(const std::string &msg) override;
        void onRestoreComplete(bool ok, const std::string &msg);
};
#endif // _IAPSINGLETON_H_
#include "IAPSingleton.h"

using namespace cocos2d;
using namespace sdkbox;

extern IAPSingleton* _iapSingleton;

IAPSingleton* IAPSingleton::pinstance = 0;

IAPSingleton* IAPSingleton::Instance()
{
	if (pinstance == 0)
	{
		  pinstance = new IAPSingleton();
      pinstance->initInstance();
    }

	return pinstance;
}

IAPSingleton::IAPSingleton()
{
}

void IAPSingleton::initInstance()
{
    // whatever else you might want to do
}

void IAPSingleton::onInitialized(bool ok)
{
    CCLOG("%s : %d", __func__, ok);
}

void IAPSingleton::onSuccess(const Product &p)
{
    // do something here

    CCLOG("Purchase Success: %s", p.id.c_str());
}

void IAPSingleton::onFailure(const Product &p, const std::string &msg)
{
    CCLOG("Purchase Failed: %s", msg.c_str());
}

void IAPSingleton::onCanceled(const Product &p)
{
    CCLOG("Purchase Canceled: %s", p.id.c_str());
}

void IAPSingleton::onRestored(const Product& p)
{
    CCLOG("Purchase Restored: %s", p.name.c_str());
}

void IAPSingleton::onProductRequestSuccess(const std::vector<Product> &products)
{
    // do something here
}

void IAPSingleton::onProductRequestFailure(const std::string &msg)
{
    CCLOG("Fail to load products");
}

void IAPSingleton::onRestoreComplete(bool ok, const std::string &msg)
{
    CCLOG("%s:%d:%s", __func__, ok, msg.data());
}

Then to use it where ever:

#include "IAPSingleton.h"
extern IAPSingleton* _iapSingleton;

_iapSingleton->Instance()......

@slackmoehrle Thanks for writing code but i know how to write singleton.
My question was how to handle singleton to current scene.
Suppose take below example,

void IAPSingleton::onSuccess(const Product &p)
{
// if its called from main_menu
MainMenu::getInstance()->onSuccess(p);

// if its called from ingame purchase screen
GamePlay::getInstance()->onSuccess(p);

// etc...

CCLOG("Purchase Success: %s", p.id.c_str());
}

void IAPSingleton::onFailure(const Product &p, const std::string &msg)
{
// if its called from main_menu
MainMenu::getInstance()->onFailure(p, msg);

// if its called from ingame purchase screen
GamePlay::getInstance()->onFailure(p, msg);

// etc...

CCLOG("Purchase Failed: %s", msg.c_str());
}

Because its very important to show appropriate msg popup and animation depend on response.
I hope you got the point.
Just take Touch listener for an example, we can have in all scene, why not same way for IAP listeners?
Its very difficult to use this way.
@nite is it same for all sdkbox plugins??

1 Like

I faced this issue as well. Hope for a better solution to come by, but in the meantime, I think we are stuck with this. :expressionless:

@smitpatel88, I see what you mean now. Sorry, I misunderstood. Let us ask @nite to clarify for us.

You could add/remove listeners
But you have to make sure all the listener you set are valid (not destroyed when the callback happens.)