Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Posts: 13
Registered: ‎04-11-2012
My Device: Blackberry Playbook, Blackberry 10 Dev Alpha
My Carrier: None

A Post Mortem: Supporting In-App Purchases With Cocos2d-x

[ Edited ]


Edit: In this post I talk about a hack to get the window group. The cocos2d-x site was down yesterday while I was at work. You can avoid that ugly hack by using CCEGLView::sharedOpenGLView().getWindowGroupId()


I've been adding support for in-app purchases to a game I'm working on since yesterday afternoon and it's been a bit of a hassle. So I've decided to do this post-mortem describing what I had to go through to get things working. Some things I got stuck on you guys might have answers to so please feel free to point things out. This will hopefully act as a good debugging guide for people having issues with in-app purchases.


So you want to have transactions in your native game or application and you're not quite sure where to start? You might have stumbled upon the Selling Digital Goods page already as I did but you'll quickly notice three things. 


1) The syntax error in the code provided (tisk tisk) Missing a curly brace on an else statement.

2) A call to the function get_window_group_id() that doesn't exist anywhere.

3) The sample code hangs indefinitely.


Maybe you're lucky (or smart) and didn't have #3 happen to you. What wasn't obvious to me was that you need a window group in order to support in app purchases. 


Although getting a window group wasn't hard in the NDK samples, it was not easy to do with Cocos2d-x. In order to create a window group you need the screen_window_t structure you used to create your window. Cocos2d-x has that hidden as a private member of CCEGLView.


Modifying Cocos2d-x wasn't an option for me. I work on a team with several others, and Cocos2d-x is not a part of the repository, we all have a local version of it that we reference from the project. So modifying Cocos2d-x would require me passing around modified source which would be a nightmare. So instead I devised a hack to get this working.


Please note at this point that what I'm about to say is a dirty hack. I'm not recommending this, I'm just saying how I did it.


I made a local copy of the CCEGLView_qnx.h and simply made m_screenWindow public. If we include my local header before the cocos headers the include guards in my version get hit before the actual cocos version. Preventing the cocos version from ever being hit and creating conflicts. This was I can check in my local copy to the repository and people who check out the source can still build it without any issues.


Now that I have a window context I can make my call to screen_create_window_group.


Now of course you're a wise developer and decided to muli-thread your solution. You learned your lesson after blocking indefinitely by simply not having a window group. But you may run into a couple issues still.


It's pretty well documented that you need to call bps_initialize and bps_shutdown from your worker thread, but maybe you forgot. Simple enough - just make those calls from your thread. However what you may not have realized is that paymentservice_set_connection_mode is local to your thread. Funny enough that's not documented anywhere at all. For me that looked like setting the parameter to true and false doesn't do anything and that local mode was broken some how.


Now that you've figured that out you'll probably be interested in writing verbose error handling, making your code really easy to debug. Brilliantly we're given two functions paymentservice_event_get_error_id and paymentservice_event_get_error_text. You can use these after you get a FAILURE_RESPONSE from an event. So now you're logging the error number and text and you want to have something else happen depending on what the error code is.


So.... do we just switch on the error number? Sounds reasonable. So what do those error codes mean?  In the documentation that has proved to be ever so helpful thus far we can note the comments for paymentservice_event_get_error_id saying simply "@return The error ID.". Okay so that wasn't helpful - maybe the online documentation is better. The online documentation says the same thing.


Well, that's not a problem. We're smart developers and we value debuggable code over the sweat of our brow. I'm willing to reproduce the error scenarios and pull the error codes from the console and enumerate the possibilities myself. Luckily the local mode lets us simply choose a state we want to reproduce and simply do that.


So you boot up the device, and you have logging code around the error ID to see what it gives you for each one. Pen and paper ready you're calling each of the six  configurations only to soon realize Local mode always returns 0 for the error codes. Bah!!! That's annoying! I refuse to do string comparisons on the return from paymentservice_event_get_error_text so what am I left to do? Not a lot really. I guess I could put the product online in sandbox mode and try to actually reproduce the scenarios but I simply don't have the time.


Even without that, I successfully have a beautiful interface to create merchandise in my game with easy to use handlers in a multi-threaded approach. 


How about you guys? Any similar things happen to you when trying to get support for in-app purchases? Did I simply miss documentation somewhere about one of these things? Let me know, I'd be interested to get feedback on my first post-mortem.

Posts: 2,559
Registered: ‎10-16-2009
My Device: BlackBerry Z10
My Carrier: Bell

Re: A Post Mortem: Supporting In-App Purchases With Cocos2d-x

Nice write-up! I'll be sure to forward your comments and found issues along. 


For the Error IDs you can use the documentation from the AIR development site for now, they are the same as what should be expected for Native:



I will be sure to get the native site updated shortly to include this info as well.



Goodbye everybody!
New Contributor
Posts: 3
Registered: ‎01-12-2013
My Device: Dev Alpha B
My Carrier: None

Re: A Post Mortem: Supporting In-App Purchases With Cocos2d-x

[ Edited ]



Thank you for the post, will definitely find it useful. Currently I'm hanged upon the 


if (event) {
    if (bps_event_get_domain(event) == paymentservice_get_domain())

 part of the in app sample - I just can't get the event from the proper domain...


But that's not what I wanted to write. Regarding that window group thing. What I did is:


#define private public
#include "platform/blackberry/CCEGLView.h"
#undef private

and later on simply:


screen_create_window_group(CCEGLView::sharedOpenGLView()->m_screenWindow, CCEGLView::sharedOpenGLView()->m_windowGroupID);



paymentservice_purchase_arguments_set_group_id(args, CCEGLView::sharedOpenGLView()->m_windowGroupID);


Still - not a very proper sounding solution, but has one advantage over yours - it's using the actual cocos header file, so you don't have to check if the file changes with subsequent cocos releases. I'm quite curious what people have to tell on this way of doing it Smiley Happy


Edit: I still cannot find CCEGLView::getWindowGroupId method in my cocos2dx release....


Edit2: Oh, I see - I have to set the window group first, because cocos doesn't do it. Not very intuitive imho (can't the payment system just set it, since it's always required?), but it's working. Big thanks for your post, I wouldn't get it that fast otherwise.

Posts: 13
Registered: ‎04-11-2012
My Device: Blackberry Playbook, Blackberry 10 Dev Alpha
My Carrier: None

Re: A Post Mortem: Supporting In-App Purchases With Cocos2d-x

I would never suggest defining private as public. Even from a lazy standpoint to speed things up. If one of your files includes that header, or includes a header that includes that header and gets compiled first: the define will break because the IFDEF guards will already be defined. If I'm not mistaken qcc will compile your objects alphabetically and by depth first so if I create a file called "aReallyCoolFile.cpp" that includes cocos2d.h your solution fails.

Needless to say its poor practice anyways.

I work at a company that tightly controls what we commit to open source so I cant offer the change. If its not in the latest build please write a getter (maybe even a setter that makes the right calls) and submit a pull request to the cocos2dx fork.

As for the domain issue. Ive had that recently as well since the NDK updated. Technically its not a great solution because you could receive a number of events before you request one and you'll be handling them instead. For non cocos applications a better solution is something like the following (I'll talk about cocos solutions after)

Create a base class that has a pure virtual method to handle qnx events. Anything that needs to handle those events will override that base class and implement the method. Have your application contain an array (std::vector or some other container is fine) of the base class pointer (eg: std::vector<QNXEventDelegate*>) and methods to subscribe as an event listener and unsubscribe. Make those methods add or remove from that list.

Next find a way to make the application have an update function. Im typing from my phone so it's inconvenient for me to check from here if thats built into CCApplication. In that function have some logic similar to:

while(true) {
// create an event pointer
// use qnx call to get an event. Make this call non blocking.
if(event) {
// loop through your list of delegates and give them the opportunity to handle this event.
} else {

Now inside of your classes that inherit the delegate you can check the event domain and if its what you want you can start to handle it. There are tons of ways to make this more optimized. In fact I think cocos already has similar logic, so you might want to tack onto that and handle payment events if their logic doesn't already.