diff --git a/nuget/readme.txt b/nuget/readme.txt
index e621428..5ceb5f5 100644
--- a/nuget/readme.txt
+++ b/nuget/readme.txt
@@ -1,5 +1,13 @@
In-App Billing Plugin for .NET MAUI, Xamarin, & Windows
+Version 7.0+ - Major Android updates
+1.) You must compile and target against Android 12 or higher
+2.) Android: Now using Android Billing v6
+3.) Android: Major changes to Android product details, subscriptions, and more
+
+Please read through: https://developer.android.com/google/play/billing/migrate-gpblv6
+
+
Version 5.0+ has significant updates!
1.) We have removed IInAppBillingVerifyPurchase from all methods. All data required to handle this yourself is returned.
2.) iOS ReceiptURL data is avaialble via ReceiptData
diff --git a/src/InAppBillingTests/InAppBillingTests.Mac/InAppBillingTests.Mac.csproj b/src/InAppBillingTests/InAppBillingTests.Mac/InAppBillingTests.Mac.csproj
index f4816b3..04d3e4f 100644
--- a/src/InAppBillingTests/InAppBillingTests.Mac/InAppBillingTests.Mac.csproj
+++ b/src/InAppBillingTests/InAppBillingTests.Mac/InAppBillingTests.Mac.csproj
@@ -95,10 +95,6 @@
{6D4D9135-F225-4626-A9CE-32BDF97AEA89}
InAppBillingTests
-
- {C570E25E-259F-4D4C-88F0-B2982815192D}
- Plugin.InAppBilling
-
\ No newline at end of file
diff --git a/src/InAppBillingTests/InAppBillingTests.iOS/InAppBillingTests.iOS.csproj b/src/InAppBillingTests/InAppBillingTests.iOS/InAppBillingTests.iOS.csproj
index 24f89de..b6b5bb7 100644
--- a/src/InAppBillingTests/InAppBillingTests.iOS/InAppBillingTests.iOS.csproj
+++ b/src/InAppBillingTests/InAppBillingTests.iOS/InAppBillingTests.iOS.csproj
@@ -159,9 +159,5 @@
{6D4D9135-F225-4626-A9CE-32BDF97AEA89}
InAppBillingTests
-
- {C570E25E-259F-4D4C-88F0-B2982815192D}
- Plugin.InAppBilling
-
\ No newline at end of file
diff --git a/src/Plugin.InAppBilling/Converters.android.cs b/src/Plugin.InAppBilling/Converters.android.cs
index 134ec7d..521b501 100644
--- a/src/Plugin.InAppBilling/Converters.android.cs
+++ b/src/Plugin.InAppBilling/Converters.android.cs
@@ -54,27 +54,39 @@ internal static InAppBillingPurchase ToIABPurchase(this PurchaseHistoryRecord pu
};
}
- internal static InAppBillingProduct ToIAPProduct(this SkuDetails product)
+ internal static InAppBillingProduct ToIAPProduct(this ProductDetails product)
{
+ var oneTime = product.GetOneTimePurchaseOfferDetails();
+ var subs = product.GetSubscriptionOfferDetails()?.Select(s => new SubscriptionOfferDetail
+ {
+ BasePlanId = s.BasePlanId,
+ OfferId = s.OfferId,
+ OfferTags = s.OfferTags?.ToList(),
+ OfferToken = s.OfferToken,
+ PricingPhases = s?.PricingPhases?.PricingPhaseList?.Select(p =>
+ new PricingPhase
+ {
+ BillingCycleCount = p.BillingCycleCount,
+ BillingPeriod = p.BillingPeriod,
+ FormattedPrice = p.FormattedPrice,
+ PriceAmountMicros = p.PriceAmountMicros,
+ PriceCurrencyCode = p.PriceCurrencyCode,
+ RecurrenceMode = p.RecurrenceMode
+ }).ToList()
+ });
+
return new InAppBillingProduct
{
Name = product.Title,
Description = product.Description,
- CurrencyCode = product.PriceCurrencyCode,
- LocalizedPrice = product.Price,
- ProductId = product.Sku,
- MicrosPrice = product.PriceAmountMicros,
+ CurrencyCode = oneTime?.PriceCurrencyCode,
+ LocalizedPrice = oneTime?.FormattedPrice,
+ ProductId = product.ProductId,
+ MicrosPrice = oneTime?.PriceAmountMicros ?? 0,
+
AndroidExtras = new InAppBillingProductAndroidExtras
{
- SubscriptionPeriod = product.SubscriptionPeriod,
- LocalizedIntroductoryPrice = product.IntroductoryPrice,
- MicrosIntroductoryPrice = product.IntroductoryPriceAmountMicros,
- FreeTrialPeriod = product.FreeTrialPeriod,
- IconUrl = product.IconUrl,
- IntroductoryPriceCycles = product.IntroductoryPriceCycles,
- IntroductoryPricePeriod = product.IntroductoryPricePeriod,
- MicrosOriginalPriceAmount = product.OriginalPriceAmountMicros,
- OriginalPrice = product.OriginalPrice
+
}
};
}
diff --git a/src/Plugin.InAppBilling/InAppBilling.android.cs b/src/Plugin.InAppBilling/InAppBilling.android.cs
index 8efbf84..b80ed71 100644
--- a/src/Plugin.InAppBilling/InAppBilling.android.cs
+++ b/src/Plugin.InAppBilling/InAppBilling.android.cs
@@ -3,12 +3,10 @@
using System.Linq;
using System.Threading.Tasks;
using Android.App;
-using Java.Security;
-using Java.Security.Spec;
-using Java.Lang;
-using System.Text;
using Android.BillingClient.Api;
using Android.Content;
+using static Android.BillingClient.Api.BillingClient;
+using BillingResponseCode = Android.BillingClient.Api.BillingResponseCode;
#if NET
using Microsoft.Maui.ApplicationModel;
#else
@@ -17,10 +15,10 @@
namespace Plugin.InAppBilling
{
- ///
- /// Implementation for Feature
- ///
- [Preserve(AllMembers = true)]
+ ///
+ /// Implementation for Feature
+ ///
+ [Preserve(AllMembers = true)]
public class InAppBillingImplementation : BaseInAppBilling
{
///
@@ -33,10 +31,10 @@ public class InAppBillingImplementation : BaseInAppBilling
/// This is set from the MainApplication.cs file that was laid down by the plugin
///
/// The context.
- Activity Activity =>
- Platform.CurrentActivity ?? throw new NullReferenceException("Current Activity is null, ensure that the MainActivity.cs file is configuring Xamarin.Essentials in your source code so the In App Billing can use it.");
+ static Activity Activity =>
+ Platform.CurrentActivity ?? throw new NullReferenceException("Current Activity is null, ensure that the MainActivity.cs file is configuring Xamarin.Essentials/.NET MAUI in your source code so the In App Billing can use it.");
- Context Context => Android.App.Application.Context;
+ static Context Context => Application.Context;
///
/// Default Constructor for In App Billing Implementation on Android
@@ -67,7 +65,7 @@ public override Task ConnectAsync(bool enablePendingPurchases = true)
tcsConnect?.TrySetCanceled();
tcsConnect = new TaskCompletionSource();
- BillingClientBuilder = BillingClient.NewBuilder(Context);
+ BillingClientBuilder = NewBuilder(Context);
BillingClientBuilder.SetListener(OnPurchasesUpdated);
if (enablePendingPurchases)
BillingClient = BillingClientBuilder.EnablePendingPurchases().Build();
@@ -146,47 +144,51 @@ public async override Task> GetProductInfoAsync
var skuType = itemType switch
{
- ItemType.InAppPurchase => BillingClient.SkuType.Inapp,
- ItemType.InAppPurchaseConsumable => BillingClient.SkuType.Inapp,
- _ => BillingClient.SkuType.Subs
+ ItemType.InAppPurchase => ProductType.Inapp,
+ ItemType.InAppPurchaseConsumable => ProductType.Inapp,
+ _ => ProductType.Subs
};
- if(skuType == BillingClient.SkuType.Subs)
+ if (skuType == ProductType.Subs)
{
- var result = BillingClient.IsFeatureSupported(BillingClient.FeatureType.Subscriptions);
+ var result = BillingClient.IsFeatureSupported(FeatureType.Subscriptions);
ParseBillingResult(result);
}
- var skuDetailsParams = SkuDetailsParams.NewBuilder()
- .SetType(skuType)
- .SetSkusList(productIds)
- .Build();
- var skuDetailsResult = await BillingClient.QuerySkuDetailsAsync(skuDetailsParams);
+ var productList = productIds.Select(p => QueryProductDetailsParams.Product.NewBuilder()
+ .SetProductType(skuType)
+ .SetProductId(p)
+ .Build()).ToList();
+
+ var skuDetailsParams = QueryProductDetailsParams.NewBuilder().SetProductList(productList);
+
+ var skuDetailsResult = await BillingClient.QueryProductDetailsAsync(skuDetailsParams.Build());
ParseBillingResult(skuDetailsResult?.Result);
- return skuDetailsResult.SkuDetails.Select(product => product.ToIAPProduct());
+ return skuDetailsResult.ProductDetails.Select(product => product.ToIAPProduct());
}
-
- public override Task> GetPurchasesAsync(ItemType itemType)
+
+ public override async Task> GetPurchasesAsync(ItemType itemType)
{
if (BillingClient == null)
throw new InAppBillingPurchaseException(PurchaseError.ServiceUnavailable, "You are not connected to the Google Play App store.");
var skuType = itemType switch
{
- ItemType.InAppPurchase => BillingClient.SkuType.Inapp,
- ItemType.InAppPurchaseConsumable => BillingClient.SkuType.Inapp,
- _ => BillingClient.SkuType.Subs
+ ItemType.InAppPurchase => ProductType.Inapp,
+ ItemType.InAppPurchaseConsumable => ProductType.Inapp,
+ _ => ProductType.Subs
};
- var purchasesResult = BillingClient.QueryPurchases(skuType);
+ var query = QueryPurchasesParams.NewBuilder().SetProductType(skuType).Build();
+ var purchasesResult = await BillingClient.QueryPurchasesAsync(query);
- ParseBillingResult(purchasesResult.BillingResult);
+ ParseBillingResult(purchasesResult.Result);
- return Task.FromResult(purchasesResult.PurchasesList.Select(p => p.ToIABPurchase()));
+ return purchasesResult.Purchases.Select(p => p.ToIABPurchase());
}
///
@@ -201,11 +203,12 @@ public override async Task> GetPurchasesHistor
var skuType = itemType switch
{
- ItemType.InAppPurchase => BillingClient.SkuType.Inapp,
- ItemType.InAppPurchaseConsumable => BillingClient.SkuType.Inapp,
- _ => BillingClient.SkuType.Subs
+ ItemType.InAppPurchase => ProductType.Inapp,
+ ItemType.InAppPurchaseConsumable => ProductType.Inapp,
+ _ => ProductType.Subs
};
+ //TODO: Binding needs updated
var purchasesResult = await BillingClient.QueryPurchaseHistoryAsync(skuType);
@@ -219,7 +222,7 @@ public override async Task> GetPurchasesHistor
/// Purchase token of original subscription
/// Proration mode (1 - ImmediateWithTimeProration, 2 - ImmediateAndChargeProratedPrice, 3 - ImmediateWithoutProration, 4 - Deferred)
/// Purchase details
- public override async Task UpgradePurchasedSubscriptionAsync(string newProductId, string purchaseTokenOfOriginalSubscription,SubscriptionProrationMode prorationMode = SubscriptionProrationMode.ImmediateWithTimeProration)
+ public override async Task UpgradePurchasedSubscriptionAsync(string newProductId, string purchaseTokenOfOriginalSubscription, SubscriptionProrationMode prorationMode = SubscriptionProrationMode.ImmediateWithTimeProration)
{
if (BillingClient == null || !IsConnected)
{
@@ -240,25 +243,25 @@ public override async Task UpgradePurchasedSubscriptionAsy
async Task UpgradePurchasedSubscriptionInternalAsync(string newProductId, string purchaseTokenOfOriginalSubscription, SubscriptionProrationMode prorationMode)
{
- var itemType = BillingClient.SkuType.Subs;
+ var itemType = ProductType.Subs;
if (tcsPurchase?.Task != null && !tcsPurchase.Task.IsCompleted)
{
return null;
}
- var skuDetailsParams = SkuDetailsParams.NewBuilder()
- .SetType(itemType)
- .SetSkusList(new List { newProductId })
- .Build();
+ var productList = QueryProductDetailsParams.Product.NewBuilder()
+ .SetProductType(itemType)
+ .SetProductId(newProductId)
+ .Build();
- var skuDetailsResult = await BillingClient.QuerySkuDetailsAsync(skuDetailsParams);
- ParseBillingResult(skuDetailsResult?.Result);
+ var skuDetailsParams = QueryProductDetailsParams.NewBuilder().SetProductList(new[] { productList }).Build();
+
+ var skuDetailsResult = await BillingClient.QueryProductDetailsAsync(skuDetailsParams);
- var skuDetails = skuDetailsResult?.SkuDetails.FirstOrDefault();
+ ParseBillingResult(skuDetailsResult.Result);
- if (skuDetails == null)
- throw new ArgumentException($"{newProductId} does not exist");
+ var skuDetails = skuDetailsResult.ProductDetails.FirstOrDefault() ?? throw new ArgumentException($"{newProductId} does not exist");
//1 - BillingFlowParams.ProrationMode.ImmediateWithTimeProration
//2 - BillingFlowParams.ProrationMode.ImmediateAndChargeProratedPrice
@@ -267,16 +270,21 @@ async Task UpgradePurchasedSubscriptionInternalAsync(strin
//5 - BillingFlowParams.ProrationMode.ImmediateAndChargeFullPrice
var updateParams = BillingFlowParams.SubscriptionUpdateParams.NewBuilder()
- .SetOldSkuPurchaseToken(purchaseTokenOfOriginalSubscription)
- .SetReplaceSkusProrationMode((int)prorationMode)
+ .SetOldPurchaseToken(purchaseTokenOfOriginalSubscription)
+ .SetReplaceProrationMode((int)prorationMode)
+ .Build();
+
+ var prodDetailsParams = BillingFlowParams.ProductDetailsParams.NewBuilder()
+ .SetProductDetails(skuDetails)
+ .SetOfferToken(skuDetails.GetSubscriptionOfferDetails()?.FirstOrDefault()?.OfferToken)
.Build();
var flowParams = BillingFlowParams.NewBuilder()
- .SetSkuDetails(skuDetails)
+ .SetProductDetailsParamsList(new[] { prodDetailsParams })
.SetSubscriptionUpdateParams(updateParams)
.Build();
- tcsPurchase = new TaskCompletionSource<(BillingResult billingResult, IList purchases)>();
+ tcsPurchase = new TaskCompletionSource<(BillingResult billingResult, IList purchases)>();
var responseCode = BillingClient.LaunchBillingFlow(Activity, flowParams);
ParseBillingResult(responseCode);
@@ -285,12 +293,12 @@ async Task UpgradePurchasedSubscriptionInternalAsync(strin
ParseBillingResult(result.billingResult);
//we are only buying 1 thing.
- var androidPurchase = result.purchases?.FirstOrDefault(p => p.Skus.Contains(newProductId));
+ var androidPurchase = result.purchases?.FirstOrDefault(p => p.Products.Contains(newProductId));
//for some reason the data didn't come back
if (androidPurchase == null)
{
- var purchases = await GetPurchasesAsync(itemType == BillingClient.SkuType.Inapp ? ItemType.InAppPurchase : ItemType.Subscription);
+ var purchases = await GetPurchasesAsync(itemType == ProductType.Inapp ? ItemType.InAppPurchase : ItemType.Subscription);
return purchases.FirstOrDefault(p => p.ProductId == newProductId);
}
@@ -323,58 +331,73 @@ public async override Task PurchaseAsync(string productId,
{
case ItemType.InAppPurchase:
case ItemType.InAppPurchaseConsumable:
- return await PurchaseAsync(productId, BillingClient.SkuType.Inapp, obfuscatedAccountId, obfuscatedProfileId);
+ return await PurchaseAsync(productId, ProductType.Inapp, obfuscatedAccountId, obfuscatedProfileId);
case ItemType.Subscription:
- var result = BillingClient.IsFeatureSupported(BillingClient.FeatureType.Subscriptions);
+ var result = BillingClient.IsFeatureSupported(FeatureType.Subscriptions);
ParseBillingResult(result);
- return await PurchaseAsync(productId, BillingClient.SkuType.Subs, obfuscatedAccountId, obfuscatedProfileId);
+ return await PurchaseAsync(productId, ProductType.Subs, obfuscatedAccountId, obfuscatedProfileId);
}
return null;
}
async Task PurchaseAsync(string productSku, string itemType, string obfuscatedAccountId = null, string obfuscatedProfileId = null)
- {
+ {
- var skuDetailsParams = SkuDetailsParams.NewBuilder()
- .SetType(itemType)
- .SetSkusList(new List { productSku })
+ var productList = QueryProductDetailsParams.Product.NewBuilder()
+ .SetProductType(itemType)
+ .SetProductId(productSku)
.Build();
- var skuDetailsResult = await BillingClient.QuerySkuDetailsAsync(skuDetailsParams);
- ParseBillingResult(skuDetailsResult?.Result);
+ var skuDetailsParams = QueryProductDetailsParams.NewBuilder().SetProductList(new[] { productList });
+
+ var skuDetailsResult = await BillingClient.QueryProductDetailsAsync(skuDetailsParams.Build());
- var skuDetails = skuDetailsResult.SkuDetails.FirstOrDefault();
+ ParseBillingResult(skuDetailsResult.Result);
+
+ var skuDetails = skuDetailsResult.ProductDetails.FirstOrDefault() ?? throw new ArgumentException($"{productSku} does not exist");
+ var productDetailsParamsList = itemType == ProductType.Subs ?
+ BillingFlowParams.ProductDetailsParams.NewBuilder()
+ .SetProductDetails(skuDetails)
+ .SetOfferToken(skuDetails.GetSubscriptionOfferDetails()?.FirstOrDefault()?.OfferToken)
+ .Build()
+ : BillingFlowParams.ProductDetailsParams.NewBuilder()
+ .SetProductDetails(skuDetails)
+ .Build();
+
+ var billingFlowParams = BillingFlowParams.NewBuilder()
+ .SetProductDetailsParamsList(new[] { productDetailsParamsList });
- if (skuDetails == null)
- throw new ArgumentException($"{productSku} does not exist");
- var flowParamsBuilder = BillingFlowParams.NewBuilder()
- .SetSkuDetails(skuDetails);
if (!string.IsNullOrWhiteSpace(obfuscatedAccountId))
- flowParamsBuilder.SetObfuscatedAccountId(obfuscatedAccountId);
+ billingFlowParams.SetObfuscatedAccountId(obfuscatedAccountId);
if (!string.IsNullOrWhiteSpace(obfuscatedProfileId))
- flowParamsBuilder.SetObfuscatedProfileId(obfuscatedProfileId);
+ billingFlowParams.SetObfuscatedProfileId(obfuscatedProfileId);
+
+ var flowParams = billingFlowParams.Build();
+
- var flowParams = flowParamsBuilder.Build();
tcsPurchase = new TaskCompletionSource<(BillingResult billingResult, IList purchases)>();
+
+
var responseCode = BillingClient.LaunchBillingFlow(Activity, flowParams);
- ParseBillingResult(responseCode);
+
+ ParseBillingResult(responseCode);
var result = await tcsPurchase.Task;
ParseBillingResult(result.billingResult);
//we are only buying 1 thing.
- var androidPurchase = result.purchases?.FirstOrDefault(p => p.Skus.Contains(productSku));
+ var androidPurchase = result.purchases?.FirstOrDefault(p => p.Products.Contains(productSku));
//for some reason the data didn't come back
if (androidPurchase == null)
{
- var purchases = await GetPurchasesAsync(itemType == BillingClient.SkuType.Inapp ? ItemType.InAppPurchase : ItemType.Subscription);
+ var purchases = await GetPurchasesAsync(itemType == ProductType.Inapp ? ItemType.InAppPurchase : ItemType.Subscription);
return purchases.FirstOrDefault(p => p.ProductId == productSku);
}
@@ -403,10 +426,11 @@ async Task PurchaseAsync(string productSku, string itemTyp
return items;
}
- //inapp:{Context.PackageName}:{productSku}
+
///
/// Consume a purchase with a purchase token.
+ /// in app:{Context.PackageName}:{productSku}
///
/// Id or Sku of product
/// Original Purchase Token
@@ -418,7 +442,7 @@ public override async Task ConsumePurchaseAsync(string productId, string t
throw new InAppBillingPurchaseException(PurchaseError.ServiceUnavailable, "You are not connected to the Google Play App store.");
}
-
+
var consumeParams = ConsumeParams.NewBuilder()
.SetPurchaseToken(transactionIdentifier)
.Build();
@@ -426,14 +450,17 @@ public override async Task ConsumePurchaseAsync(string productId, string t
var result = await BillingClient.ConsumeAsync(consumeParams);
- return ParseBillingResult(result.BillingResult);
+ return ParseBillingResult(result.BillingResult);
}
- bool ParseBillingResult(BillingResult result)
+ static bool ParseBillingResult(BillingResult result)
{
- if(result == null)
+ if (result == null)
throw new InAppBillingPurchaseException(PurchaseError.GeneralError);
+ if ((int)result.ResponseCode == Android.BillingClient.Api.BillingClient.BillingResponseCode.NetworkError)
+ throw new InAppBillingPurchaseException(PurchaseError.ServiceTimeout);//Network connection is down
+
return result.ResponseCode switch
{
BillingResponseCode.Ok => true,
@@ -450,7 +477,7 @@ bool ParseBillingResult(BillingResult result)
BillingResponseCode.ItemUnavailable => throw new InAppBillingPurchaseException(PurchaseError.ItemUnavailable),
_ => false,
};
- }
+ }
}
}
-
+
diff --git a/src/Plugin.InAppBilling/Plugin.InAppBilling.csproj b/src/Plugin.InAppBilling/Plugin.InAppBilling.csproj
index 7750022..010af4f 100644
--- a/src/Plugin.InAppBilling/Plugin.InAppBilling.csproj
+++ b/src/Plugin.InAppBilling/Plugin.InAppBilling.csproj
@@ -1,8 +1,9 @@
- netstandard2.0;MonoAndroid10.0;Xamarin.iOS10;Xamarin.TVOS10;Xamarin.Mac20;net6.0-android;net6.0-ios;net6.0-maccatalyst;net6.0-tvos;net6.0-macos
+
+ netstandard2.0;MonoAndroid12.0;Xamarin.iOS10;Xamarin.TVOS10;Xamarin.Mac20;net6.0-android;net6.0-ios;net6.0-maccatalyst;net6.0-tvos;net6.0-macos
$(TargetFrameworks);uap10.0.19041;net6.0-windows10.0.19041;
- 9.0
+ 10.0
Plugin.InAppBilling
Plugin.InAppBilling
$(AssemblyName) ($(TargetFramework))
@@ -97,14 +98,14 @@
-
-
+
+
-
-
+
+
diff --git a/src/Plugin.InAppBilling/Shared/InAppBillingProduct.shared.cs b/src/Plugin.InAppBilling/Shared/InAppBillingProduct.shared.cs
index a4f24a8..a8f8b59 100644
--- a/src/Plugin.InAppBilling/Shared/InAppBillingProduct.shared.cs
+++ b/src/Plugin.InAppBilling/Shared/InAppBillingProduct.shared.cs
@@ -26,13 +26,13 @@ public class InAppBillingProductAppleExtras
public bool IsFamilyShareable { get; set; }
///
- /// iOS 11.2: gets information about product discunt
+ /// iOS 11.2: gets information about product discount
///
public InAppBillingProductDiscount IntroductoryOffer { get; set; } = null;
///
- /// iOS 12.2: gets information about product discunt
+ /// iOS 12.2: gets information about product discount
///
public List Discounts { get; set; } = null;
}
@@ -87,51 +87,56 @@ public class InAppBillingProductWindowsExtras
public class InAppBillingProductAndroidExtras
{
///
- /// Subscription period, specified in ISO 8601 format.
- ///
- public string SubscriptionPeriod { get; set; }
-
- ///
- /// Trial period, specified in ISO 8601 format.
- ///
- public string FreeTrialPeriod { get; set; }
-
- ///
- /// Icon of the product if present
- ///
- public string IconUrl { get; set; }
-
- ///
- /// Gets or sets the localized introductory price.
- ///
- /// The localized introductory price.
- public string LocalizedIntroductoryPrice { get; set; }
-
- ///
- /// Number of subscription billing periods for which the user will be given the introductory price, such as 3
- ///
- public int IntroductoryPriceCycles { get; set; }
-
- ///
- /// Billing period of the introductory price, specified in ISO 8601 format
- ///
- public string IntroductoryPricePeriod { get; set; }
-
- ///
- /// Introductory price of the product in micro-units
- ///
- /// The introductory price.
- public Int64 MicrosIntroductoryPrice { get; set; }
-
- ///
- /// Formatted original price of the item, including its currency sign.
- ///
- public string OriginalPrice { get; set; }
-
- ///
- /// Original price in micro-units, where 1,000,000, micro-units equal one unit of the currency
+ /// The period details for products that are subscriptions.
///
- public long MicrosOriginalPriceAmount { get; set; }
+ public List SubscriptionOfferDetails { get; set; }
+
+ /////
+ ///// Subscription period, specified in ISO 8601 format.
+ /////
+ //public string SubscriptionPeriod { get; set; }
+
+ /////
+ ///// Trial period, specified in ISO 8601 format.
+ /////
+ //public string FreeTrialPeriod { get; set; }
+
+ /////
+ ///// Icon of the product if present
+ /////
+ //public string IconUrl { get; set; }
+
+ /////
+ ///// Gets or sets the localized introductory price.
+ /////
+ ///// The localized introductory price.
+ //public string LocalizedIntroductoryPrice { get; set; }
+
+ /////
+ ///// Number of subscription billing periods for which the user will be given the introductory price, such as 3
+ /////
+ //public int IntroductoryPriceCycles { get; set; }
+
+ /////
+ ///// Billing period of the introductory price, specified in ISO 8601 format
+ /////
+ //public string IntroductoryPricePeriod { get; set; }
+
+ /////
+ ///// Introductory price of the product in micro-units
+ /////
+ ///// The introductory price.
+ //public Int64 MicrosIntroductoryPrice { get; set; }
+
+ /////
+ ///// Formatted original price of the item, including its currency sign.
+ /////
+ //public string OriginalPrice { get; set; }
+
+ /////
+ ///// Original price in micro-units, where 1,000,000, micro-units equal one unit of the currency
+ /////
+ //public long MicrosOriginalPriceAmount { get; set; }
}
diff --git a/src/Plugin.InAppBilling/Shared/InAppBillingProductDiscount.shared.cs b/src/Plugin.InAppBilling/Shared/InAppBillingProductDiscount.shared.cs
index 36d43f5..32212d4 100644
--- a/src/Plugin.InAppBilling/Shared/InAppBillingProductDiscount.shared.cs
+++ b/src/Plugin.InAppBilling/Shared/InAppBillingProductDiscount.shared.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace Plugin.InAppBilling
{
@@ -128,4 +129,23 @@ public enum ProductDiscountType
///
Unknown
}
+
+ public class SubscriptionOfferDetail
+ {
+ public string BasePlanId { get; set; }
+ public string OfferId { get; set; }
+ public List OfferTags { get; set; }
+ public string OfferToken { get; set; }
+ public List PricingPhases { get; set; }
+ }
+
+ public class PricingPhase
+ {
+ public int BillingCycleCount { get; set; }
+ public string BillingPeriod { get; set; }
+ public string FormattedPrice { get; set; }
+ public long PriceAmountMicros { get; set; }
+ public string PriceCurrencyCode { get; set; }
+ public int RecurrenceMode { get; set; }
+ }
}