I have install sdkbox and iap plugins, but I dont know how I integrate to my project. I have try like no ads example in video but when I add sdkbox::IAPListener my CREATE_FUNC gives error (Allocating an object of abstract class type ‘GameScene’)
you need or override the functions sdkbox::IAPListener
needs.
There is extra stuff here, but:
class HelloWorld : public cocos2d::Layer, public sdkbox::IAPListener
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
void onShowAds(cocos2d::Ref* sender);
void onRequestIAP(cocos2d::Ref* sender);
void onRestoreIAP(cocos2d::Ref* sender);
void onIAP(cocos2d::Ref* sender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
private:
void updateIAP(const std::vector<sdkbox::Product>& products);
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;
cocos2d::CCMenu* _iapMenu;
std::vector<sdkbox::Product> _products;
cocos2d::Label* _txtCoin;
int _coinCount;
};
#endif // __HELLOWORLD_SCENE_H__
Can I find simple no_ads example project in github?
sorry, no_ads example
?
You mean, how to remove ads by making an IAP?
Maybe there are enough pieces here to help:
#include "HelloWorldScene.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
template <typename T> std::string tostr(const T& t) { std::ostringstream os; os<<t; return os.str(); }
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto dirs = Director::getInstance();
Size visibleSize = dirs->getVisibleSize();
Vec2 origin = dirs->getVisibleOrigin();
_coinCount = 0;
_txtCoin = Label::create("0", "Marker Felt.ttf", 32);
_txtCoin->setAnchorPoint(cocos2d::Point(0, 0));
_txtCoin->setPosition(cocos2d::Point(800, 500));
addChild(_txtCoin);
auto menuNode = Node::create();
menuNode->setName("menuNode");
int index = 2;
auto thisSceneLabel = Label::createWithTTF("In-App Purchase Demo", "Marker Felt.ttf", 32);
thisSceneLabel->setPosition(Vec2(origin.x+visibleSize.width/2, origin.y +visibleSize.height/2).x, (Vec2(origin.x+visibleSize.width/2, origin.y+visibleSize.height).y - (index) * 40));
this->addChild(thisSceneLabel, 1);
sdkbox::IAP::init();
sdkbox::IAP::setDebug(true);
sdkbox::IAP::setListener(this);
auto menuItem1 = MenuItemFont::create("Remove Ads");
menuItem1->setFontNameObj("Marker Felt.ttf");
menuItem1->setFontSizeObj(32);
menuItem1->setName("menuItem1");
menuItem1->setPosition(Vec2(visibleSize.width/2, visibleSize.height/2));
menuItem1->setCallback([&](cocos2d::Ref *sender)
{
onRequestIAP(sender);
});
auto menu = Menu::create(menuItem1, NULL);
menu->setName("menu");
menuNode->addChild(menu, 1);
menu->setPosition(Vec2::ZERO);
auto closeItem = MenuItemFont::create("CloseNormal.png",
[&](Ref* sender){
// your code here
});
this->addChild(menuNode, 2);
return true;
}
void HelloWorld::onRequestIAP(cocos2d::Ref* sender)
{
sdkbox::IAP::purchase("remove_ads");
}
void HelloWorld::onShowAds(cocos2d::Ref *sender)
{
CCLOG("Show Ads");
}
void HelloWorld::onRestoreIAP(cocos2d::Ref* sender)
{
sdkbox::IAP::restore();
}
void HelloWorld::onIAP(cocos2d::Ref *sender)
{
auto btn = static_cast<Node*>(sender);
sdkbox::Product* p = (sdkbox::Product*)btn->getUserData();
CCLOG("Start IAP %s", p->name.c_str());
sdkbox::IAP::purchase(p->name);
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
void HelloWorld::onSuccess(const sdkbox::Product &p)
{
if (p.name == "coin_package") {
_coinCount += 1000;
_txtCoin->setString(tostr(_coinCount));
}
else if (p.name == "coin_package2") {
_coinCount += 5000;
_txtCoin->setString(tostr(_coinCount));
}
else if (p.name == "remove_ads") {
CCLOG("Remove Ads");
}
CCLOG("Purchase Success: %s", p.id.c_str());
}
void HelloWorld::onFailure(const sdkbox::Product &p, const std::string &msg)
{
CCLOG("Purchase Failed: %s", msg.c_str());
}
void HelloWorld::onCanceled(const sdkbox::Product &p)
{
CCLOG("Purchase Canceled: %s", p.id.c_str());
}
void HelloWorld::onRestored(const sdkbox::Product& p)
{
CCLOG("Purchase Restored: %s", p.name.c_str());
}
void HelloWorld::updateIAP(const std::vector<sdkbox::Product>& products)
{
//
// _iapMenu->removeAllChildren();
// _products = products;
//
// int posX = 0;
// int posY = 0;
//
// for (int i=0; i < _products.size(); i++)
// {
// CCLOG("iap: %s", _products[i].name.c_str());
//
// auto btn = Label::create();
// btn->setString(_products[i].name.c_str());
//// auto btn = CCMenuItemFont::create(_products[i].name.c_str(), CC_CALLBACK_1(HelloWorld::onIAP, this) );
// btn->setColor(Color3B::WHITE);
// btn->setUserData(&_products[i]);
// btn->setPosition(CCPoint(posX, posY));
// _iapMenu->addChild(btn);
// posY += 50;
// }
}
void HelloWorld::onProductRequestSuccess(const std::vector<sdkbox::Product> &products)
{
updateIAP(products);
}
void HelloWorld::onProductRequestFailure(const std::string &msg)
{
CCLOG("Fail to load products");
}
Thank you so much
sure, if you need anything else, please let me know.
I have two button, I dont understand how it works onIAP
? I didnt write ‘onIAP’ func. I set other things and now when I click to my remove ads button console says this Purchase Failed: Invalid product please double check the product id on itunes connect
, It is normal or? I am sorry this is my first IAP experience.
void NoAds( cocos2d::Ref *sender )
{
sdkbox::IAP::purchase("remove_ads");
}
void RestorePurchases( cocos2d::Ref *sender )
{
sdkbox::IAP::restore();
}
have you defined your items in the iTunes Connect interface?
Have I publish first version of game for in app items submit? ITunesconnect says: Your first In-App Purchase must be submitted with a new app version. Select it from the app’s In-App Purchases section and click Submit
. By the way, Can you explain to me how it works onIAP function
in your codes. I didnt use onIAP
, do I need to use it?
You don’t have to submit your IAP, you can still test it. All you need is create a tester user in your iTunesConnect account.
How do I check remove_ads purchased?
void GameScene::ShowAds()
{
if(adsremoved)//Here how can i check?
{
CCLOG("Dont show ads");
}
else
{
CCLOG("Show Ads");
}
}
and can you explain how works this function, I dont write this func in my project, I have to?
void HelloWorld::onIAP(cocos2d::Ref *sender)
{
auto btn = static_cast<Node*>(sender);
sdkbox::Product* p = (sdkbox::Product*)btn->getUserData();
CCLOG("Start IAP %s", p->name.c_str());
sdkbox::IAP::purchase(p->name);
}
Hi,
Review this: http://sdkbox-doc.github.io/en/plugins/iap/v3-cpp/
onIAP()
is not part of the listener. it is just what is run when you press the button in the example. So maybe you have a Buy button and you run this when it is pressed.
As far as how to check for removing ads, I think that there are a lot of ways you can accomplish this. Perhaps UserDefaults
, perhaps SQLite, perhaps even checking restored purchases.
I still have the same problem (Invalid product). How much time did you have to wait for Itunes Connect recognize your Product ID?
Hi I am also running into the error with the “Allocating an object of abstract class type ‘HelloWorld’”.
I actually copied and pasted the code that you said would have all the overridden functions that are needed, but for some reason I still get the error.
Can you show me so I can see what is happening exactly? Maybe a screenshot at least?
Can you confirm what cocos2d-x version, iOS or android, iOS or android version, sdkbox version, please.
I’m using cocos2d-x 3.7.1 on iOS. SDKBOX v0.5.6.20 and sdkbox-iap_v1.2.3.3.
Is it possible that I messed up the installation? I used the automatic sdkbox installer. And then afterwards I used the cocos command to create a project. And then I went into the project directory and typed “sdkbox import iap” into the terminal. The terminal said the installation was successful. Is there anything else that I may have missed?
I bet that if you look you are missing a function in your private
section of your header or also, you don’t have all of these functions defined in your .cpp. Double check.
Add this new function please
https://github.com/darkdukey/sdkbox-iap-sample/blob/master/cpp/Classes/HelloWorldScene.h#L43
I was missing
virtual void onInitialized(bool ok);
and
virtual void onRestoreComplete(bool ok, const std::string &msg);
Thanks everyone
DJEclipse: Yes, I was missing that too. Why? Well, I guess we both read carefully the docs: http://sdkbox-doc.github.io/en/plugins/iap/v3-cpp/#usage
And, those docs make no reference at all to those 2 functions (onInitialized & onRestoreComplete). Without those functions, the build in Xcode fails. Adding those? It works.
So, hey COCOS SDKBOX folks: Please update the docs to include all functions needed for a clean build! Thanks so much for your continued great support!