I tried the following code for in-app purchase. I'm using CurrentAppSimulator for testing purpose.
private async void history_Click(object sender, RoutedEventArgs e)
{
bool OK = true;
// Get the license info
// The next line is commented out for testing.
// licenseInformation = CurrentApp.LicenseInformation;
// The next line is commented out for production/release.
LicenseInformation licenseInformation = CurrentAppSimulator.LicenseInformation;
if (!licenseInformation.ProductLicenses["PremiumFeatures"].IsActive)
{
try
{
// The customer doesn't own this feature, so
// show the purchase dialog.
await CurrentAppSimulator.RequestProductPurchaseAsync("PremiumFeatures", false);
// the in-app purchase was successful
OK = true;
}
catch (Exception)
{
// The in-app purchase was not completed because
// an error occurred.
OK = false;
}
}
else
{
// The customer already owns this feature.
OK = true;
}
if (OK)
{
Frame.Navigate(typeof(HistoryPage));
}
}
However, the dialog keep pop up, every time I perform history_Click, even I choose S_OK. I expect licenseInformation.ProductLicenses["PremiumFeatures"].IsActive should changed to true, after I buy the PremiumFeatures.
I guess, perhaps when the in-app purchase was successful, I need to turn on IsActive flag, so that it will not show me purchase dialog again.
// the in-app purchase was successful
OK = true;
// Compile error!!!
licenseInformation.ProductLicenses["PremiumFeatures"].IsActive = true;
OK. Seems like IsActive is a read only field. So, may I know, what is the correct way to handle purchase successful case?
Update :
After looking at Trial app and in-app purchase sample, I realize having the following code can have IsActive changed from false to true automatically, after purchasing successful. (But why it works?)
private async Task LoadInAppPurchaseProxyFileAsync()
{
StorageFolder proxyDataFolder = await Package.Current.InstalledLocation.GetFolderAsync("data");
StorageFile proxyFile = await proxyDataFolder.GetFileAsync("in-app-purchase.xml");
licenseChangeHandler = new LicenseChangedEventHandler(InAppPurchaseRefreshScenario);
CurrentAppSimulator.LicenseInformation.LicenseChanged += licenseChangeHandler;
await CurrentAppSimulator.ReloadSimulatorAsync(proxyFile);
// setup application upsell message
ListingInformation listing = await CurrentAppSimulator.LoadListingInformationAsync();
var product1 = listing.ProductListings["product1"];
var product2 = listing.ProductListings["product2"];
Product1SellMessage.Text = "You can buy " + product1.Name + " for: " + product1.FormattedPrice + ".";
Product2SellMessage.Text = "You can buy " + product2.Name + " for: " + product2.FormattedPrice + ".";
}
However, the "Is already bought" status is not persistence. If I close the app and start it again, it will thought my "Premium Feature" to "is not bought yet".
How am I suppose the make this behavior persistence?
PLEASE READ
I would assume, based on your experience, that App.IsTrial is set to true. You cannot commit a purchase while the app is in trial mode or (for any other reason) is not active. Please note that I am referring to the App and not the feature/product. Once the app is active your purchase will succeed.
As far as I know it's not automatically updated when you click OK. It only returns the correct status like it should do in the Windows Store.
What I think is an option to do, but I haven't implemented it myself is to use ReloadSimulatorAsync(proxyFile) method. Before you call this method you have to update the in-app-purchase.xml yourself save it and pass the file to the ReloadSimulatorAsync method.
Personally I would use the manual update of the xml file. But I can't Judge about that for your application / application flow.
A good start for automating this process is the sample "In-app purchase" app which you can find here. If you look in the code file InAppPurchase.xaml.cs you will see already a bit of code for your own implementation.
I'm just gonna clear this out. When executing
try {
await CurrentAppSimulator.RequestProductPurchaseAsync("PremiumFeatures", false);
OK = true
}
catch (Exception)
{
OK = false;
}
OK will not only be true if the user bought the feature, it will also be true if he cancels the buy or he cant be identified or he disables his network connection. So this is the wrong way to check if the purchase was successfull. Basically Anobik was right, you have to check afterwards if the license is purchased so the right code would be:
if (!licenseInformation.ProductLicenses["PremiumFeatures"].IsActive)
{
try
{
// The customer doesn't own this feature, so
// show the purchase dialog.
await CurrentAppSimulator.RequestProductPurchaseAsync("PremiumFeatures", false);
if (licenseInformation.ProductLicenses["PremiumFeatures"].IsActive)
{
// the in-app purchase was successful
OK = true;
//Success in purchase use ur own code block
}
else
{
OK = false;
//error in purchase use your own code block
}
}
catch (Exception)
{
// The in-app purchase was not completed because
// an error occurred.
OK = false;
}
}
else
{
// The customer already owns this feature.
OK = true;
}
if (OK)
{
Frame.Navigate(typeof(HistoryPage));
}
But still, if you compile you will see that it doesn't work. I think, this is because the CurrentAppSimulator will not make a permanent change to the license.
I hope this is true :)
It is not necessary to check if the license IsActive immediately after the purchase. Instead, you can (you'd better) store the result of RequestProductPurchaseAsync, which is of type PurchaseResults and has a Status property. The latter in its turn is a ProductPurchaseStatus enum value, and if it is Succeeded, you can proceed without checking the license.
You are only missing one if else condition to handle the in app purchase
Here's the code
private async void history_Click(object sender, RoutedEventArgs e)
{
bool OK = true;
// Get the license info
// The next line is commented out for testing.
// licenseInformation = CurrentApp.LicenseInformation;
// The next line is commented out for production/release.
LicenseInformation licenseInformation = CurrentAppSimulator.LicenseInformation;
if (!licenseInformation.ProductLicenses["PremiumFeatures"].IsActive)
{
try
{
// The customer doesn't own this feature, so
// show the purchase dialog.
await CurrentAppSimulator.RequestProductPurchaseAsync("PremiumFeatures", false);
if (licenseInformation.ProductLicenses["PremiumFeatures"].IsActive)
{
// the in-app purchase was successful
OK = true;
//Success in purchase use ur own code block
}
else
{
OK = false;
//error in purchase use your own code block
}
}
catch (Exception)
{
// The in-app purchase was not completed because
// an error occurred.
OK = false;
}
}
else
{
// The customer already owns this feature.
OK = true;
}
if (OK)
{
Frame.Navigate(typeof(HistoryPage));
}
}
Related
I am using jamesmontenegro InAppBilling and I have a small issue regarding payments.
The code is working fine but after the payment is handled by Google Play Store, the app doesn't handle the procedure and doesn't return if the purchase was successfully leading to not being able to consume the purchased item.
Here is the simple code
public static async Task<bool> PurchaseItem(string productId, string payload)
{
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync(ItemType.InAppPurchase);
if (!connected)
{
//we are offline or can't connect, don't try to purchase
return false;
}
//check purchases
var purchase = await billing.PurchaseAsync(productId, ItemType.InAppPurchase, payload);
//possibility that a null came through.
if (purchase == null)
{
//did not purchase
Debug.WriteLine("purchased but not consumed");
return true;
}
else if (purchase.State == PurchaseState.Purchased)
{
//purchased, we can now consume the item or do it later
//If we are on iOS we are done, else try to consume the purchase
//Device.RuntimePlatform comes from Xamarin.Forms, you can also use a conditional flag or the DeviceInfo plugin
if (Device.RuntimePlatform == Device.iOS)
return true;
var consumedItem = await CrossInAppBilling.Current.ConsumePurchaseAsync(purchase.ProductId, purchase.PurchaseToken);
if (consumedItem != null)
{
//Consumed!!
Debug.WriteLine("purchased and consumed");
return true;
}
}
return false;
}
Nothing is actually running after PurchaseAsync is called as the thread changes to Google Play Store.
Once the payment is finished and the thread goes back to the app it is not possible to handle anything.
Any ideas? There is a workaround for this but I am just wondering if I am doing something wrong here?
How can you implement a 'buy' link into a trial app?
Do you use the same method as for implementing a 'rate' link?
Thanks a lot.
Use the MarketplaceDetailTask launcher:
MarketplaceDetailTask marketplaceDetailTask = new MarketplaceDetailTask();
marketplaceDetailTask.Show();
See:
How to use the Marketplace detail task for Windows Phone
first of all you will have to register that buy in your developer accound as in-app product and then use this ...
public static LicenseInformation licenseInformation;
if (!App.licenseInformation.ProductLicenses["productid"].IsActive)
{
try
{
// The user doesn't own this feature, so
// show the purchase dialog.
await CurrentApp.RequestProductPurchaseAsync("productid", false);
// the in-app purchase was successful
}
catch (Exception)
{
// The in-app purchase was not completed because
// an error occurred.
}
}
else
{
// The user already owns this feature.
}
}
I have this code for my in-app purchase
string receipt = await Store.CurrentApp.RequestProductPurchaseAsync(pID, false);
The documentation states that this method returns a success value even if:
there's no network connection available
the user cancels out of the dialog
the user's authentication fails
You should treat a success result as indicating the async process completed without
errors. To ensure that the transaction itself was successful, check the
LicenseInformation element in the returned receipt.
Is there a quick way to verify the receipt for the particular item actually successful before I unlocked the purchase feature? Currently if there's no error, the feature will always be unlocked because the receipt isn't verified.
My code:
private async void inAppPurchase(string key)
{
if (!Store.CurrentApp.LicenseInformation.ProductLicenses[key].IsActive)
{
try
{
// The customer doesn't own this feature, so
// show the purchase dialog.
MockIAPLib.ListingInformation li = await Store.CurrentApp.LoadListingInformationAsync();
string pID = li.ProductListings[key].ProductId;
//purchase successful
string receipt = await Store.CurrentApp.RequestProductPurchaseAsync(pID, false);
//Check the receipt for
switch (key)
{
case "IsAdsVisibleSetting":
settings.IsAdsVisibleSetting = false;
break;
case "style_2":
fontFolder[key] = true;
settings.AllowedFontSetting = fontFolder;
break;
case "backgrounds_2":
backgroundGroups[key] = true;
settings.AllowedBackgroundGroupsSetting = backgroundGroups;
break;
case "backgrounds_3":
backgroundGroups[key] = true;
settings.AllowedBackgroundGroupsSetting = backgroundGroups;
break;
}
RenderStoreItems();
}
catch (Exception)
{
MessageBox.Show("Sorry, the in-app purchase was not completed because an error occurred.", "Purchasing Error", MessageBoxButton.OK);
}
}
}
after purchase method call, make sure to check the license is active or not before full fulling the goods. If it is consumable type, call ReportProductFulfillment() method.
CurrentApp.LicenseInformation.ProductLicenses[key].IsActive
BTW, in your code includeReceipt value is set as false - will keeps 'receipt' as empty always.
I guess you all misunderstood my question and closed it at How to run a Command in C# and retrieve data from it?
I had said in that post also :-
want to run a Command from command promt and want its output and maipulate its output. If required, want to close the process and display error or appropriate message. To stop the process, I have to press "F4' key on command prompt. Till the process is stopeed or killed, it has to be alive only.
I have created a class to handle running the cmd. And I keep getting the output. But on reading the output's each line I want to stop or throw exception if found anything improper in the output.
I am tying to connect to server via cmd. Server keeps on giving output. Suppose the server gave output as :
Trying to start .....
Cananot load file
.....
Exiting
While retrieving the output, I want to check for lines like "Cannot find file", "Connected Successfully, etc and set properties ccordingly (like connected = true, errorMsg = "Cannot find file". Where I am calling the class, I can take care of those proeprties and stop if found connected == true or errorMsg.length > 0. With this inform the user that "Connection is achieved or error msg stating regarding "Cannot load file" and disconnect the server if errorMsg found.
I didn't find anywhere doing any manipulation on the output receving and that's where I find myself stuck. I found a lot on internet. Am stuck and trying to figre out this part from last 3-4 days. Then have posted here.
I need help in that. Please help me. If requiried I will psot code snippets. But please help me. AND don't close this thread as answered ithout understanding my question fully. This is no duplicate.
My code is class :
public int ConnectToServer()
{
int error = 0;
connected = false;
try
{
process = Process.Start(processInfo);
process.BeginOutputReadLine();
process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
//if (errorMsg.Length > 0)
// throw new Exception(errorMsg);
}
catch (Exception e)
{
Console.WriteLine("Error Processing ConnectToServer : " + e.Message);
connected = false;
errorMsg = e.Message;
error = -1;
return error;
}
return error;
}
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
errorMsg = "";
connected = false;
string d = e.Data;
if (!string.IsNullOrEmpty(d))
{
if (sb != null)
sb.Append(d + "\n");
Console.WriteLine("LINE = " + d);
if (d.IndexOf("Initialization Completed") > 0)
{
connected = true;
Console.WriteLine("********* Connected = " + connected);
}
else if (isInValidLine(d))
{
//throw new Exception(d);
connected = false;
errorMsg = d;
return;
}
}
return;
}
private bool isInValidLine(string line)
{
if (line.IndexOf("Cannot load file") > 0)
{
errorMsg = line;
return true;
}
return false;
}
IS THE ABOVE CLASS CODE CORRECT WITH MY REQUIREMENTS ?
In impementation :
while (!oc.Connected)
{
timepassed = (int)(DateTime.Now - start).TotalMilliseconds;
if (timepassed > timeout)
{
oc.DisconnectServer();
connectedToVpn = false;
throw new Exception("NotConnectedException");
} else if (oc.ErrorMessage.Length > 0)
{
oc.DisconnectServer();
connectedToVpn = false;
throw new Exception(oc.ErrorMessage);
}
Thread.Sleep(100);
}
Here what I am doing is, when I get the output line, I check if it states as Conneced or is invalid. If its invalid, I set the line as the errorMsg. In my while loop I keep chekcing for Connected and errorMessage, but the value of errorMessage stays as "" only. It never gets updated, which tell me that the processing output code is never executed. Nor in debug mode I find the cursor at that line, but the Line = is displayed proeprly in Console. So, don't understand what's going wrong and where.
Hope this helps you more understand.
Thanks
once you have redirected the standard output of the process you have executed you could parse what you receive as it arrives, I believe also line by line, then you can post commands to control your process.
to read output you have redirected the standard output, to send input you should also redirect the standard input of the process.
I am using Waitin RC2, WatiN-2.0.20.1089, Windows XP OS with IE8 With VS2008 and NUnit-2.5.7.10213. I have added the sites to the trusted list, I have thread sleeps, I have tried "WaitForComplete". yet when the script goes "back" I am still getting an unauthorized access exception.
Here is a chunk of my code, the exceptions are never caught inspite of the fact that most of the code is in try catch blocks.
public string FindAllLinks()
{
/*
* This function is designed to find and use all of the links on a given page.
* After clicking on a link it waits for 400 milliseconds on the page so the page
* has some time to load and then the function "hits the back button" reseting
* to the originating page.
* This function is not meant to be recursive.
*/
string message = "";
bool flag = true;
//Get a list of all links from the browser instance
foreach (Link link in browserInstance.Links)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine(link);
try
{//clicking on the link to make sure it leads somewhere
link.Click(); //If the click fails hopefull we will thrwo out of the try block and not execute the next two commands.
//Console.WriteLine(link);
}
catch (Exception)
{//OOPs we have an error let's log a message.
message = message + "The link titled " + link + " was not found, or did not work.\n";
flag = false;
}
if (flag)
{
System.Threading.Thread.Sleep(1000);
//browserInstance.WaitForComplete;
try { browserInstance.Back(); }
catch (UnauthorizedAccessException)
{
//do nothing
}
}//close if flag
}//close for each
//return the message
return (message);
}//Close function
[STAThread]
[Test]
public void TestTitleHomePage()
{
bool testPassed = false;
if (browserInstance.Title.Contains("<title>"))
{
string message = FindAllLinks();
if (message == "") { testPassed = true; }
}//close if
else { message = "The Title was not the same."; }
Assert.IsTrue(testPassed, message);
}// end TestTitleHomePage
I tried your code and I also get the exception. I think I understand what happens. When you first do Browser.Links, you get all the links of the current page, then you navigate to another page and return to the first page, but for WatiN it is a new page. So your enumeration cannot work because you enumerate though the links of the first page.
What I suggest you could do is to get all the Uri of the links, then try them one by one in a new browser
IEnumerable<Uri> uris = Browser.Links.Select(l => l.Uri);
foreach(Uri uri in Uris)
{
try
{
using(var browser = new IE(uri))
{
// do nothing or detect 404, 403, etc errors
}
// no error
}
catch(exception)
{
// log error
}
}