Friday 5 September 2014

Native call backs and Monetization of Cocos 2d-x Games for windows phone 8 platform (Ads and IAP integration)

 Hi Folks!  In the Previous posts I mentioned the basic setup for windows phone 8 Cocos 2d-x game and issues along with solutions.Now lets see how to write call back functions in a cocos 2d-x games to communicate with the c# code (generated code) and vice versa.
1) Basic Call Backs Handling:
Any c++ run time component can communicate with your native code. In this sample I am following the standard ref class and event handlers to handle the communication process.
a) First we will need to add these following classes into your project, in visual studio under (If your project name is some thing like HelloCpp) HelloCppComponent section.
- First Right click on the HelloCppComponent
- Goto Add and select Class
- Select Visual studio C++ class
- Name it as ICallBackHandler
- You will now see an .h and a .cpp file created
- Fill these files with the following content
(ICallBackHandler.h,ICallBackHandler.cpp)
I) ICallBackHandler.h
namespace PhoneDirect3DXamlAppComponent //thi
{
using namespace Platform;
namespace WFM = Windows::Foundation::Metadata;
public enum class eEXTERNAL_REQ_TYPE
{
Initialize = 0, // initializing internet check and other things
InAppConsumable,       //1
InAppNonConsumable,    //2
Show_Banner_Top_Ads,   //3
Show_Banner_Bottom_Ads,   //4
Show_FullScreen_Ads,   //5
Hide_Banner_Ads,    //6
Hide_FullScreen_Ads   //7
} ;

[WFM::WebHostHiddenAttribute]
public interface class ICallBackHandler //Interface class
{
public:
virtual void  OnSendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE eReqType, Platform::String ^strData); };
public delegate void CallBackHandler(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE RequestType, Platform::String^ strData, Platform::String^ strResult);
public ref class ExternalInterfaceHandler sealed //EventArgs
{
public:
event CallBackHandler^ OnCallBack;
public:
property Platform::String^ mPrevRequestedData;
property PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE mPrevRequestType;
//Cx event Handling
public:
event CallBackHandler^ mInternalOnCallBack;
event CallBackHandler^ mEventRegistrationTokenHandler
{
Windows::Foundation::EventRegistrationToken add(CallBackHandler^ handler)
{
return mInternalOnCallBack += handler;
}
void remove(Windows::Foundation::EventRegistrationToken token)
{
mInternalOnCallBack -= token;
}

void raise(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE RequestType,     Platform::String^ strData, Platform::String^ strResult)
{
mInternalOnCallBack(RequestType, strData, strResult);
}
}

//Singleton Instance
public:
static property ExternalInterfaceHandler^ Instance
{
ExternalInterfaceHandler^ get()
{
   static ExternalInterfaceHandler^ instance;
   if (instance == nullptr)
       instance = ref new ExternalInterfaceHandler();
 return instance;
 }

}
public:
virtual ~ExternalInterfaceHandler() { }
private:
ExternalInterfaceHandler() { }
public:
static void SetCallback(ICallBackHandler ^Callback);

void Reciever(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE eRequestType, Platform::String ^mRequestedData, Platform::String^ mRequestedResult);

void SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE eRequestType, Platform::String ^mRequestedData, CallBackHandler^ OnRecieverCallBack);

};

}

Lets add the definitions for the class
  1.  II) ICallBackHandler.cpp
#include<ICallBackHandler.h>

#include <stdlib.h>

#include <assert.h>

#include <time.h>

using namespace PhoneDirect3DXamlAppComponent;

namespace PhoneDirect3DXamlAppComponent

{

Windows::Foundation::EventRegistrationToken mEventRegtokenCookie;

static int _mfPrevTimeOfAdsDisplay = 0;

ICallBackHandler ^CSCallback = nullptr;

void ExternalInterfaceHandler::SetCallback(ICallBackHandler ^Callback)

{

CSCallback = Callback;

}

void ExternalInterfaceHandler::Reciever(

PhoneDirect3DXamlAppComponent:: eEXTERNAL_REQ_TYPE eRequestType, Platform::String ^mRequestedData,

Platform::String^ msResult)

{
switch (eRequestType)
{
case
PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::InAppConsumable:
case   PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::InAppNonConsumable:
{
OnCallBack(mPrevRequestType, mPrevRequestedData, msResult);
OnCallBack -= mEventRegtokenCookie;
}
break;
default:
break;
}
}

void ExternalInterfaceHandler::SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE eReqType, Platform::String ^strRequesdData, CallBackHandler^ OnRecieverCallBack)
{
if (OnRecieverCallBack != nullptr)
{
mPrevRequestedData = strRequesdData;
mPrevRequestType = eReqType;
mEventRegtokenCookie = OnCallBack += OnRecieverCallBack; 
//standard registration for Cx/C++
}
switch (eReqType)
{
case PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Show_FullScreen_Ads:
{
try
{
//make sure some 30 secs Delay between two full screen ads
time_t timep=time(NULL);
struct tm * timeinfo;
time(&timep);
timeinfo = localtime(&timep);
int presentTime = timeinfo->tm_sec;
if (abs(presentTime - _mfPrevTimeOfAdsDisplay) >= 30)
{
_mfPrevTimeOfAdsDisplay = presentTime;
  if (CSCallback != nullptr)
       CSCallback->OnSendRequest(eReqType, strRequesdData);

}
}
catch (Platform::Exception ^e)
{
}
}
break;
case  PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Show_Banner_Top_Ads:
case  PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Show_Banner_Bottom_Ads:
case PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Hide_Banner_Ads:
case PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Initialize:
case PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::InAppConsumable:
case PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::InAppNonConsumable:
{
if (CSCallback != nullptr)
     CSCallback->OnSendRequest(eReqType, strRequesdData);

}

break;
default:
break;
}//Switch
}//SendRequest
}
Note: What this essentially does is that it defines a virtual class that can be derived in you own code for the communication purpose.
After Adding the above two files
- Include the ICallBackHandler.h file in the required cpp class where you will need to communicate with the c#code
- Add using namespace PhoneDirect3DXamlAppComponent
- Add using namespace Platform (This is so that the String^ works without errors)
- Define the function that you will be using as a call back in your code (use the following code as a template)
#include<ICallBackHandler.h>
using namespace PhoneDirect3DXamlAppComponent;
using namespace Platform;
// Declare a call back function as follows:
public:
void OnIAPCallBack(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE          eReqType,Platform::String^ strRequestedData, Platform::String^ strPurchaseStatus);
// Use the call back function as follows for IAP calls

ExternalInterfaceHandler::Instance-> SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::InAppConsumable,

"1", ref new CallBackHandler([this](PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE eRequestType, Platform::String ^mRequestedData, Platform::String^ mRequestedResult){OnIAPCallBack(eRequestType, mRequestedData, mRequestedResult); }));

// use the call back function as follows for Advertising calls (show ads (banner, full screen), hide ads)

ExternalInterfaceHandler::Instance->SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Show_Banner_Bottom_Ads, "", nullptr);

ExternalInterfaceHandler::Instance->SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Show_Banner_Top_Ads, "", nullptr);

ExternalInterfaceHandler::Instance->SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Show_FullScreen_Ads, "", nullptr);

ExternalInterfaceHandler::Instance->SendRequest(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE::Hide_Banner_Ads, "", nullptr);

Definition for Call back Function:

void PlayMenu::OnIAPCallBack(PhoneDirect3DXamlAppComponent::eEXTERNAL_REQ_TYPE eReqType, Platform::String^ strRequestedData, Platform::String^ strPurchaseStatus)
{
if (strPurchaseStatus == "true")
{
//Here purchase completed successfully so give the coins or levels or reward the user with purchased goods
}
else
{
//Here purchase completed failed so don't give any goods
}
}
2) Now let’s build the project and next open the MainPage.xaml.cs file
I) Add this class in MainPage.xaml.cs:
public class WINRTBridgeInterface : ICallBackHandler
{
InterstitialAd interstitialAd;
AdView bannerad;
private const string Admob_Banner_Id = "ca-app-pub-6086640554461020/1726002193";
private const string Admob_Intenstial_Id = "ca-app-pub-6086640554461020/3202735395";
private string InAppIdstringId = "Sampleproductid";
private MainPage m_MainPage = null;
private Direct3DInterop m_d3dInterop = null;
public WINRTBridgeInterface()
{
ExternalInterfaceHandler.SetCallback(this);
}
public void Initialize(MainPage mainPage,Direct3DInterop d3dInterop)
{
m_MainPage = mainPage;
m_d3dInterop = d3dInterop;
}
private void OnAdReceived(object sender, AdEventArgs e)
{
interstitialAd.ShowAd();
}

public void OnSendRequest(eEXTERNAL_REQ_TYPE eReqType, String   strRequestedData)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
switch (eReqType)
{
case eEXTERNAL_REQ_TYPE.InAppConsumable:
case eEXTERNAL_REQ_TYPE.InAppNonConsumable:
{
Deployment.Current.Dispatcher.BeginInvoke(async () =>
{
strRequestedData = InAppIdstringId + strRequestedData;
string productId = strRequestedData;
if (eReqType == eEXTERNAL_REQ_TYPE.InAppConsumable)
{
try
{
var licence = Store.CurrentApp.LicenseInformation.ProductLicenses[productId];
if (licence.IsActive)
{
Store.CurrentApp.ReportProductFulfillment(productId);
}
else
{
await Store.CurrentApp.RequestProductPurchaseAsync(productId, false);
var mproductLicense = Store.CurrentApp.LicenseInformation.ProductLicenses[productId];
if (mproductLicense.IsConsumable && mproductLicense.IsActive)
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "true");
Store.CurrentApp.ReportProductFulfillment(mproductLicense.ProductId);
}
else
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "false");                                             }
}
}
catch
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "false");
}
}//consumable goods
else if (eReqType == eEXTERNAL_REQ_TYPE.InAppNonConsumable)
{
try
{
if (Store.CurrentApp.LicenseInformation.ProductLicenses[productId].IsActive)
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "true");                                        }
else
{
await Store.CurrentApp.RequestProductPurchaseAsync(productId, false);
var licence = Store.CurrentApp.LicenseInformation.ProductLicenses[productId];
if (licence.IsActive)
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "true");
}
else
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "false");                                               }
}
}
catch
{
ExternalInterfaceHandler.Instance.Reciever(eReqType, strRequestedData, "false");                                    
}
}//Durable goods
});
}
break;
case eEXTERNAL_REQ_TYPE.Show_Banner_Top_Ads:
{
try
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (DeviceNetworkInformation.IsNetworkAvailable) //check if net                           is available or not
{
if (bannerad != null && m_MainPage.LayoutRoot.Children.Contains(bannerad))
{
bannerad.VerticalAlignment = VerticalAlignment.Top;
bannerad.Visibility = Visibility.Visible;
}
else
{
bannerad = new AdView();
bannerad.Format = AdFormats.Banner;
bannerad.VerticalAlignment = VerticalAlignment.Top;
bannerad.AdUnitID = Admob_Banner_Id;
m_MainPage.LayoutRoot.Children.Add(bannerad);
AdRequest adrequest = new AdRequest();
bannerad.LoadAd(adrequest);
}
}
});
}
catch
{
}
}
break;
case eEXTERNAL_REQ_TYPE.Show_Banner_Bottom_Ads:
{
try
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (DeviceNetworkInformation.IsNetworkAvailable) //internet availablity
{
if (bannerad != null && m_MainPage.LayoutRoot.Children.Contains(bannerad))
{
bannerad.VerticalAlignment = VerticalAlignment.Bottom;
bannerad.Visibility = Visibility.Visible;
}
else
{
bannerad = new AdView();
bannerad.Format = AdFormats.Banner;
bannerad.VerticalAlignment = VerticalAlignment.Bottom;
bannerad.AdUnitID = Admob_Banner_Id;
m_MainPage.LayoutRoot.Children.Add(bannerad);
AdRequest adrequest = new AdRequest();
bannerad.LoadAd(adrequest);
}
}
});
}
catch
{
}
}
break;
case eEXTERNAL_REQ_TYPE.Show_FullScreen_Ads:
{
try
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (DeviceNetworkInformation.IsNetworkAvailable) //check if net is available or not
{
interstitialAd = new InterstitialAd(Admob_Intenstial_Id);
AdRequest adRequest = new AdRequest();
interstitialAd.ReceivedAd += OnAdReceived;
interstitialAd.LoadAd(adRequest);
}
});
}
catch
{
}
}
break;
case eEXTERNAL_REQ_TYPE.Hide_Banner_Ads:
case eEXTERNAL_REQ_TYPE.Hide_FullScreen_Ads:
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (bannerad != null && m_MainPage.LayoutRoot.Children.Contains(bannerad))
{
bannerad.Visibility = Visibility.Collapsed;
}
});
}
break;
}
});
}
}
  II) And again in the MainPage.xaml.cs file update the following function
private void DrawingSurface_Loaded(object sender, RoutedEventArgs e)
{
// add these lines, this is important coz all call backs initialized with these lines only
WINRTBridgeInterface WINRTBridgeObj = new WINRTBridgeInterface();
WINRTBridgeObj.Initialize(this, m_d3dInterop);
}
Congratulations you have successfully finished the setup and now your code can communicate between c++ to c# and vice versa. Cheers!!!!!!
Thanks!

No comments:

Post a Comment