How to implement IAP on windows?

How to implement IAP on windows?
0.0 0

#1

Hi!

Has anybody ever implemented IAP in Windows 10/8.1 game?

It’s not a big deal of information over the Internet about this issue :frowning:


#2

Use the following code but make sure you call it on ui thread otherwise it will crash

	create_task(APP::RequestProductPurchaseAsync(productId)).then([this ,productId](task<PurchaseResults^> currentTask)
	{
		try
		{
			PurchaseResults^ results = currentTask.get();
			switch (results->Status)
			{
			case ProductPurchaseStatus::Succeeded:
			{
			GrantFeatureLocally(productId, results->TransactionId);
			FulfillProduct1(productId, results->TransactionId);
		
			
			}
				break;
			case ProductPurchaseStatus::NotFulfilled:
				if (!IsLocallyFulfilled(results->TransactionId))
				{
					GrantFeatureLocally(productId,results->TransactionId);

					
				}
				FulfillProduct1(productId, results->TransactionId);
				break;
			case ProductPurchaseStatus::NotPurchased:
			{
				NotifyUser("Product 1 was not purchased.");
			

			}


				break;
			}
		}
		catch (Platform::Exception^ exception)
		{
			NotifyUser("Unable to buy Product 1.");
			
		}
	});

}

}


#3

Thank you very much!
I have discovered something like this too. But how to call it from the UI thread?


#4

I did a hack on this one :joy: … i used a timer to call it since timer runs on ui thread …the timer call a method that calls the IAP … I m sure someone here knows the real way to do it but if it works it works lol

auto timer = ref new Windows::UI::Xaml::DispatcherTimer();
TimeSpan ts;
ts.Duration = 500;
timer->Interval = ts;
timer->Start();


#5

Ok, so I’ve done something like this:

using namespace WinInApp;

InAppManager::InAppManager() {
	// init here
	CCLOG("Creating InApp Manager...");
}

void InAppManager::LoadInAppPurchaseProxyFile()
{
	CCLOG("Loading proxy file...");
}

void InAppManager::InAppPurchaseRefreshScenario()
{
}
void InAppManager::StartTimerAndRegisterHandler() {
	CCLOG("Start timer");
	auto timer = ref new Windows::UI::Xaml::DispatcherTimer();
	TimeSpan ts;
	ts.Duration = 5000;
	timer->Interval = ts;
	timer->Start();
	auto registrationtoken = timer->Tick += ref new EventHandler<Object^>(this, &InAppManager::OnTick);
	CCLOG("Timer setup ok.");
}

void InAppManager::OnTick(Object^ sender, Object^ e) {
	// do something on each tick here ...
	CCLOG("Tick...");
}

Than first time I tried to call

	auto m_pInapp = ref new WinInApp::InAppManager();
	m_pInapp->StartTimerAndRegisterHandler();

from the scene where my game runs.
It just stuck on this: auto timer = ref new Windows::UI::Xaml::DispatcherTimer(); Just showstop, doing nothing, no crash, just not going any further.

After I placed it to the App.xaml.cpp it just crashes after message “Timer setup ok.” and never goes to OnTick method.
Can you please reveal a bit more about your hack?


#6

I did it this way …

  1. i created a timer iin the App class , this timer calls the onTick method every 0.5sec .
    2, The onTick method queries the InAppPurchase i created to find if the user wants to buy anything …so the if a user pressed a button on the game …the event is put into the InAppPurchase
  2. The timer onTick queries for the the event and shows calls the windows store
  3. The returned result is returned to the InAppPurchase

Hope the hack code helps :sunglasses:

// setup in App App::OnLaunched
auto timer = ref new Windows::UI::Xaml::DispatcherTimer();
TimeSpan ts;
ts.Duration = 500;
timer->Interval = ts;
timer->Start();
auto registrationtoken = timer->Tick += ref new EventHandler<Object^>(this, &App::OnTick);

///

consumedTransactionIds = ref new Platform::Collections::Vector<Platform::Guid>();
LoadInAppPurchaseConsumablesProxyFile();

the onTick Method in App class

void App::OnTick(Object^ sender, Object^ e) {
// do something on each tick here …

if (InAppPurhase::getInstance()->ready())
{
	
	Platform::String^ productId = stringToPlatformString(InAppPurhase::getInstance()->getPurchaseItemName());
	//jkbujauto productName = "Gold";
	create_task(APP::RequestProductPurchaseAsync(productId)).then([this ,productId](task<PurchaseResults^> currentTask)
	{
		try
		{
			PurchaseResults^ results = currentTask.get();
			switch (results->Status)
			{
			case ProductPurchaseStatus::Succeeded:
			{
			GrantFeatureLocally(productId, results->TransactionId);
			FulfillProduct1(productId, results->TransactionId);
			 InAppPurhase::getInstance()->onResults(true);
			
			}
				break;
			case ProductPurchaseStatus::NotFulfilled:
				//if (!IsLocallyFulfilled(results->TransactionId))
				{
					GrantFeatureLocally(productId,results->TransactionId);

					InAppPurhase::getInstance()->onResults(true);
				}
				FulfillProduct1(productId, results->TransactionId);
				break;
			case ProductPurchaseStatus::NotPurchased:
			{
				NotifyUser("Product 1 was not purchased.");
				InAppPurhase::getInstance()->onResults(false);

			}


				break;
			}
		}
		catch (Platform::Exception^ exception)
		{
			NotifyUser("Unable to buy Product 1.");
			InAppPurhase::getInstance()->onResults(false);
		}
	});

}

}


#7

Thanks! Looks like it works now.

How do you switch to real purchases instead of CurrentAppSimulator? You still need to load info, but not from the xlm-file, right?

As I understand you leave something like this:

        eventRegistrationToken = (CurrentAppSimulator::LicenseInformation->LicenseChanged += ref new LicenseChangedEventHandler(this, &InAppPurchase::InAppPurchaseRefreshScenario));
            create_task(CurrentApp::LoadListingInformationAsync()).then([this](task<ListingInformation^> currentTask)
            {
                try
                {
                    ListingInformation^ listing = currentTask.get();
                    auto product1 = listing->ProductListings->Lookup("product1");
                    auto product2 = listing->ProductListings->Lookup("product2");
                }
                catch(Platform::Exception^ exception)
                {
                    rootPage->NotifyUser("LoadListingInformationAsync API call failed", NotifyType::ErrorMessage);
                }
            });

#8

Yea you load from the store when its live . just replace CurrentAppSimulator with App and leave out the load xml .

create_task(CurrentApp::LoadListingInformationAsync()).then([this](task<ListingInformation^> currentTask)
{
try
{
ListingInformation^ listing = currentTask.get();
}
}


#9

Following code will execute task in UI thread without timer hack:

Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
    Windows::UI::Core::CoreDispatcherPriority::Normal, 
    ref new Windows::UI::Core::DispatchedHandler([this] {
        create_task(Store::CurrentAppSimulator::RequestProductPurchaseAsync("product1")).then([this](task<Store::PurchaseResults^> currentTask) {
        ...
        });
    }));

#10

Also you can use UI and GL thread helper methods from this pull request: https://github.com/cocos2d/cocos2d-x/pull/18067

To run transaction inside UI thread:

cocos2d::GLViewImpl::sharedOpenGLView()->RunOnUIThread(ref new Windows::UI::Core::DispatchedHandler([this] {
    ...
}));

To complete transaction callback inside GL thread:

cocos2d::GLViewImpl::sharedOpenGLView()->RunOnGLThread(ref new Windows::UI::Core::DispatchedHandler([this] {
    ...
}));