I create a new IAP in store with the Product ID "Donate".
Then I make request to this IAP in the app, here is the code:
var purchaseResults = await CurrentApp.RequestProductPurchaseAsync("Donate");
However, when I call the function in my windows app, an error message dialog is shown:
Choose another item : This in-app purchase item is no longer available in My App Name
and I tried call var listingInfo = await CurrentApp.LoadListingInformationAsync();var productListings = listingInfo.ProductListings;It seems that there is no product in the list.
How would this happened? Thanks!
If you are building your app based on Windows SDK 14393(or higher), I strongly recommend StoreContext class instead of CurrentApp, StoreContext is more convenient to implement an IAP action, and it is also easy to debug.
For your case, you could use the purchase api like this:
private readonly StoreContext context = StoreContext.GetDefault();
// you can get the StoreId of Iap product from your dashboard of Windows Dev Center
var result = await context.RequestPurchaseAsync(product.StoreId);
if (result.Status == StorePurchaseStatus.Succeeded)
{
// successfully purchased
}
else if (result.Status == StorePurchaseStatus.AlreadyPurchased)
{
// purchased already
}
else if (result.Status == StorePurchaseStatus.NotPurchased)
{
// purchase progress cancelled by user
}
else if (result.Status == StorePurchaseStatus.ServerError || result.Status == StorePurchaseStatus.NetworkError)
{
// error occured
}
and you could also list your IAP product like this:
var result = await context.GetAssociatedStoreProductsAsync(new string[] { "Durable" });
if (result.ExtendedError != null)
{
// error
}
else
{
// list all durable iap product
var products = result.Products.Values;
}
Related
I'm implementing the InAppBilling plugin in my Xamarin Forms 5 app for auto-renewing subscriptions.
I have the "subscriptions" set up on Google Play and they're active. When I ask for a list of subscription items, I get the list fine but when I try make a purchase, I get the following error that indicates the item is not available.
I'm running this on a real device connected to my laptop via USB. Any idea what I'm doing wrong?
Here's my purchase subscription method which is directly from documentation here:
public async Task<bool> Subscribe(string productId)
{
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync();
if (!connected)
return false;
//check purchases
var purchase = await billing.PurchaseAsync(productId, ItemType.Subscription);
//possibility that a null came through.
if (purchase == null)
{
//did not purchase
return false;
}
else
{
//purchased!
if (Device.RuntimePlatform == Device.Android)
{
// Must call AcknowledgePurchaseAsync else the purchase will be refunded
//await billing.AcknowledgePurchaseAsync(purchase.PurchaseToken);
}
return true;
}
}
catch (InAppBillingPurchaseException purchaseEx)
{
//Billing Exception handle this based on the type
throw new Exception("Error: " + purchaseEx);
}
catch (Exception ex)
{
//Something else has gone wrong, log it
throw new Exception();
}
finally
{
await billing.DisconnectAsync();
}
}
As I mentioned before, I see the subscription items available and active on Google Play. I also made sure, I'm getting them from "Subscriptions" and NOT "In-App Products". I'm using the ID that I copy and paste from the "Product ID" column on Google Play Console -- see below:
Any idea what the issue here may be?
So i'm using Azure Notification Hub, and in that i followed their tutorial where they had mentioned to use FCM for Android , configure it and use their API key, and creating a certificate for iOS, which is working flawless
But the problem is i'm working on Xamarin forms, and i'd like to know if i could do the registration manually through API, and i've already written a method to do that in my API Service
public async Task<string> RegisterDevice([FromBody] string handle = null)
{
string newRegistrationId = null;
//newRegistrationId = await hub.CreateRegistrationIdAsync();
//// make sure there are no existing registrations for this push handle (used for iOS and Android)
//if (handle != null)
//{
// var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
// foreach (var registration in registrations)
// {
// if (newRegistrationId == null)
// {
// newRegistrationId = registration.RegistrationId;
// }
// else
// {
// await hub.DeleteRegistrationAsync(registration);
// }
// }
//}
newRegistrationId = await hub.CreateRegistrationIdAsync();
return newRegistrationId;
}
But i'm not able to understand how the device would be linked to this registration ID and/or what is a pns handle, i know the abbreviation but i dont know how to use it in this case or if at all is it necessary?
Any help would be deeply appreciated
While registering Azure Notification Hub, If you want to ask for Push permissions after login, you have to call RegisterForRemoteNotifications(); (iOS) & CreateNotificationChannel(); (Android) after Login.
What you're asking would require a few steps-
You would have to created a DependencyService like this, which would require creating an Interface like IPushRegistrationService with a RegisterForPush() function that would basically be called after login:
var pushService = DependencyService.Get<IPushRegistrationService>();
pushService.RegisterForPush();
Hi I am developing a xamarin forms application that targets both android and ios. I want to add google pay as my payment option to order items in android.
please help me is there any documentation available.
welcome to StackOverflow.
Google Pay does not process payments, and as such, it needs to reference your existing processor or gateway to do that. Here is a list of currently supported processors.
As Leo pointed out, you can integrate Google Pay in Xamarin using Xamarin's libs including Google Play Services.
During the integration, make sure to use the right configuration based on the payment processor of your choice. Follow this link to see some examples for different processors.
Hope it helps.
First of all, Google pay must be installed on the device.
Place these three methods in your MainActivity.cs
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == gpay_requestCode)
{
if (data != null)
{
string response = data.GetStringExtra("response");
string[] resArray = response.Split("&");
string txnId = resArray[0].Split("=")[1].ToString();
string responseCode = resArray[1].Split("=")[1].ToString();
string status = resArray[2].Split("=")[1].ToString();
string txnRef = resArray[3].Split("=")[1].ToString();
if (status == "SUCCESS")
{
Toast.MakeText(this, "Payment Success", ToastLength.Long).Show();
}
else
{
Toast.MakeText(this, "Payment Failed", ToastLength.Long).Show();
}
}
else
{
Toast.MakeText(this, "Payment Failed", ToastLength.Long).Show();
}
}
}
private void PayViaGooglePay()
{
if (IsGooglePayInstalled())
{
//Generate random unique number for transaction reference ID
string transId = $"UPI{Guid.NewGuid().ToString().Substring(0, 8)}";
using (var uri = new Android.Net.Uri.Builder()
.Scheme("upi")
.Authority("pay")
.AppendQueryParameter("pa", "yourgooglepayusername#test")//Google pay email
.AppendQueryParameter("pn", "Test Name") //Google pay name
.AppendQueryParameter("pn", "Sending Amount of 1 JOD") // Google pay note
.AppendQueryParameter("mc", "0000") //
.AppendQueryParameter("tr", transId) //transaction reference ID
.AppendQueryParameter("tn", "Pay to Test Name") //Transaction note
.AppendQueryParameter("am", "1") // Amount
.AppendQueryParameter("cu", "JOD") //Currency
.Build())
{
Intent = new Intent(Intent.ActionView);
Intent.SetData(uri);
Intent.SetPackage("com.google.android.apps.nbu.paisa.user");
StartActivityForResult(Intent, gpay_requestCode);
}
}
}
private bool IsGooglePayInstalled()
{
PackageManager pm = this.PackageManager;
bool installed = false;
try
{
pm.GetPackageInfo("com.google.android.apps.nbu.paisa.user", PackageInfoFlags.Activities);
installed = true;
}
catch (PackageManager.NameNotFoundException e)
{
Toast.MakeText(this, "Google Pay Is Not Installed", ToastLength.Long).Show();
}
return installed;
}
Because you can't call any of these methods from your shared project, you need to create a messaging center and call it wherever you wish.
Place the messaging center in your OnCreate method in the same MainActivity.cs
MessagingCenter.Subscribe<string>(this, "PayViaGooglePay", (value) =>
{
PayViaGooglePay();
});
And then you can call it wherever you want, just put this code wherever you need it
MessagingCenter.Send<string>("", "PayViaGooglePay");
I hope this helps :)
I'm trying to create a chatbot where in order to avoid the user opening the chat window and not knowing the available options, I want to give some basic instructions when the user opens the chat window.
Is there any trigger available when the user opens a chat window? Maybe then I can check, and if there's not an ongoing conversation I could provide basic instructions.
I did some googling and found nothing about this. Is it possible to do something like this, and if not, is there a way to mitigate this problem, and provide the user with information regarding the chatbot capabilities and supported instructions?
Facebook does not allow bots to initiate a conversation, unlike Skype or other platforms.
There are still some tricks you can do :
Go on the Settings of your Facebook page, then Messaging and check "Show a Messenger Greeting" as below, and write your greeting sentence.
The result will look like this :
You can also set a "Get Started" button to trigger an event.
Here's the doc :
"https://developers.facebook.com/docs/messenger-platform/thread-settings/get-started-button"
You can monitor for two event types: ConversationUpdate and ContactRelationUpdate.
The first one (ConversationUpdate) is called when a user is added or removed from the conversation. So, there's a place where you can introduce available options. It will be each type the new conversation has started. So, it may become annoying, you may add a check - do not show it if the user has been using the bot for some time.
The second (ContactRelationUpdate) is called when a user adds or removes the bot to/from the contacts. In general, it is only called once per user action.
Here's the extract from the Bot-Frameworks examples:
For Node.Js
bot.on('conversationUpdate', function (message) {
// Check for group conversations
if (message.address.conversation.isGroup) {
// Send a hello message when bot is added
if (message.membersAdded) {
message.membersAdded.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Hello everyone!");
bot.send(reply);
}
});
}
// Send a goodbye message when bot is removed
if (message.membersRemoved) {
message.membersRemoved.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Goodbye");
bot.send(reply);
}
});
}
}
});
bot.on('contactRelationUpdate', function (message) {
if (message.action === 'add') {
var name = message.user ? message.user.name : null;
var reply = new builder.Message()
.address(message.address)
.text("Hello %s... Thanks for adding me. Say 'hello' to see some great demos.", name || 'there');
bot.send(reply);
} else {
// delete their data
}
});
For C#
private void HandleMessage(Activity message)
{
if (message.Type == ActivityTypes.ConversationUpdate)
{
if (activity.MembersAdded.Any(m => m.Id == activity.Recipient.Id))
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = activity.CreateReply();
response.Text = "Hi! I am Bot. Here's what you can do...";
await connector.Conversations.ReplyToActivityAsync(response);
}
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
if (Activity.AsContactRelationUpdateActivity().Action == ContactRelationUpdateActionTypes.Add)
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = activity.CreateReply();
response.Text = "Hi! I am Bot. Thanks for adding me. Here's what you can do...";
}
}
return null;
}
I think the acid answer is not.
But you can intercept the IConversationUpdateActivity type message to know if the user has added the bot to a conversation. In the C# project template you can find a code block that ask for this message type but do nothing.
i'm trying to open app store application programmatically in my app.
what i'm trying to do is that i'm calling a service to check at the current app version and if it needs update i should open app store application to let the user update the my app.
note: the app not published yet to the store, i'm still in coding phase.
i tried to use the following code in ViewDidLoad method, but it's not working (nothing happened):
var nsurl = new NSUrl("itms://itunes.apple.com");
UIApplication.SharedApplication.OpenUrl(nsurl);
A direct link via itms: will only work in an actual device, if you are testing on a simulator, use https://itunes.apple.com/us/genre/ios/id36?mt=8 instead.
I would recommend using itms:// link on the actual device as it prevents the redirects that user sees when using a https:// link to open iTunes.
bool isSimulator = Runtime.Arch == Arch.SIMULATOR;
NSUrl itunesLink;
if (isSimulator)
{
itunesLink = new NSUrl("https://itunes.apple.com/us/genre/ios/id36?mt=8");
}
else
{
itunesLink = new NSUrl("itms://itunes.apple.com");
}
UIApplication.SharedApplication.OpenUrl(itunesLink, new NSDictionary() { }, null);
Instead of opening the external Store app on the device, you might want to consider keeping the user inside of your app by using a SKStoreProductViewController:
bool isSimulator = Runtime.Arch == Arch.SIMULATOR;
if (!isSimulator)
{
var storeViewController = new SKStoreProductViewController();
storeViewController.Delegate = this;
var id = SKStoreProductParameterKey.ITunesItemIdentifier;
var productDictionaryKeys = new NSDictionary("SKStoreProductParameterITunesItemIdentifier", 123456789);
var parameters = new StoreProductParameters(productDictionaryKeys);
storeViewController.LoadProduct(parameters, (bool loaded, NSError error) =>
{
if ((error == null) && loaded)
{
this.PresentViewController(storeViewController, true, () =>
{
Console.WriteLine("SKStoreProductViewController Completed");
});
}
if (error != null)
{
throw new NSErrorException(error);
}
});
}
else
{
var itunesLink = new NSUrl("https://itunes.apple.com/us/genre/ios/id36?mt=8");
UIApplication.SharedApplication.OpenUrl(itunesLink, new NSDictionary() { }, null);
}
NSBundle.MainBundle.InfoDictionary["CFBundleVersion"]
Returns you the current app version.
To open the Apple Appstore just let the user navigate to the appstore link, Apple will automaticly detect that the user is using an iPhone and will open the Appstore for them.
Test yourself:
Open the following link in safari: Whatsapp in the Appstore
It will automatically open the appstore.
When you create app on iTunesConnect you can get url to your future app in AppStore even if you didn't release it yet. You can find it under App Information tab:
In your app you can just open it:
var nsurl = new NSUrl("https://itunes.apple.com/us/app/mygreatapp/id123456789");
UIApplication.SharedApplication.OpenUrl(nsurl);