Skip to content

Commit

Permalink
Add macOS implementaiton
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmontemagno committed Feb 7, 2021
1 parent 289df30 commit 7d5c0cb
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
82 changes: 67 additions & 15 deletions src/Plugin.InAppBilling/InAppBilling.apple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,36 @@
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using UIKit;

namespace Plugin.InAppBilling
{
/// <summary>
/// Implementation for InAppBilling
/// </summary>
[Preserve(AllMembers = true)]
public class InAppBillingImplementation : BaseInAppBilling
public class InAppBillingImplementation : BaseInAppBilling, ISKProductsRequestDelegate
{
static bool IsiOS112 => UIDevice.CurrentDevice.CheckSystemVersion(11, 2);
#if __IOS__ || __TVOS__
static bool HasIntroductoryPrice => UIKit.UIDevice.CurrentDevice.CheckSystemVersion(11, 2);
#else
static bool initIntro, hasIntro;
static bool HasIntroductoryPrice
{
get
{
if (initIntro)
return hasIntro;

initIntro = true;


using var info = new NSProcessInfo();
hasIntro = info.IsOperatingSystemAtLeastVersion(new NSOperatingSystemVersion(10,13,2));
return hasIntro;

}
}
#endif

/// <summary>
/// Gets or sets a callback for out of band purchases to complete.
Expand All @@ -38,13 +57,15 @@ public InAppBillingImplementation()
/// </summary>
public override bool InTestingMode { get; set; }

/// <summary>
/// Get product information of a specific product
/// </summary>
/// <param name="productIds">Sku or Id of the product(s)</param>
/// <param name="itemType">Type of product offering</param>
/// <returns></returns>
public async override Task<IEnumerable<InAppBillingProduct>> GetProductInfoAsync(ItemType itemType, params string[] productIds)
public IntPtr Handle => throw new NotImplementedException();

/// <summary>
/// Get product information of a specific product
/// </summary>
/// <param name="productIds">Sku or Id of the product(s)</param>
/// <param name="itemType">Type of product offering</param>
/// <returns></returns>
public async override Task<IEnumerable<InAppBillingProduct>> GetProductInfoAsync(ItemType itemType, params string[] productIds)
{
var products = await GetProductAsync(productIds);

Expand All @@ -56,8 +77,8 @@ public async override Task<IEnumerable<InAppBillingProduct>> GetProductInfoAsync
ProductId = p.ProductIdentifier,
Description = p.LocalizedDescription,
CurrencyCode = p.PriceLocale?.CurrencyCode ?? string.Empty,
LocalizedIntroductoryPrice = IsiOS112 ? (p.IntroductoryPrice?.LocalizedPrice() ?? string.Empty) : string.Empty,
MicrosIntroductoryPrice = IsiOS112 ? (long)((p.IntroductoryPrice?.Price?.DoubleValue ?? 0) * 1000000d) : 0
LocalizedIntroductoryPrice = HasIntroductoryPrice ? (p.IntroductoryPrice?.LocalizedPrice() ?? string.Empty) : string.Empty,
MicrosIntroductoryPrice = HasIntroductoryPrice ? (long)((p.IntroductoryPrice?.Price?.DoubleValue ?? 0) * 1000000d) : 0
});
}

Expand Down Expand Up @@ -175,7 +196,9 @@ public async override Task<InAppBillingPurchase> PurchaseAsync(string productId,
Id = p.TransactionIdentifier,
ProductId = p.Payment?.ProductIdentifier ?? string.Empty,
State = p.GetPurchaseState(),
#if __IOS__ || __TVOS__
PurchaseToken = p.TransactionReceipt?.GetBase64EncodedString(NSDataBase64EncodingOptions.None) ?? string.Empty
#endif
};

if (verifyPurchase == null)
Expand Down Expand Up @@ -203,7 +226,9 @@ Task<bool> ValidateReceipt(IInAppBillingVerifyPurchase verifyPurchase, string pr
}


Task<SKPaymentTransaction> PurchaseAsync(string productId)
TaskCompletionSource<SKProduct> productTCS;

async Task<SKPaymentTransaction> PurchaseAsync(string productId)
{
var tcsTransaction = new TaskCompletionSource<SKPaymentTransaction>();

Expand Down Expand Up @@ -257,13 +282,35 @@ Task<SKPaymentTransaction> PurchaseAsync(string productId)

paymentObserver.TransactionCompleted += handler;

#if __IOS__ || __TVOS__

var payment = SKPayment.CreateFrom(productId);
#else
productTCS?.TrySetCanceled();
productTCS = new TaskCompletionSource<SKProduct>();
var productIdentifiers = NSSet.MakeNSObjectSet<NSString>(new NSString[] { new NSString(productId) });
var productsRequest = new SKProductsRequest(productIdentifiers);
productsRequest.Delegate = this; // for SKProductsRequestDelegate.ReceivedResponse
productsRequest.Start();
var product = await productTCS.Task;
if (product == null)
throw new InAppBillingPurchaseException(PurchaseError.InvalidProduct);

var payment = SKPayment.CreateFrom(product);
//var payment = SKPayment.CreateFrom((SKProduct)SKProduct.FromObject(new NSString(productId)));
#endif
SKPaymentQueue.DefaultQueue.AddPayment(payment);

return tcsTransaction.Task;
return await tcsTransaction.Task;
}


public void ReceivedResponse(SKProductsRequest request, SKProductsResponse response)
{
productTCS?.TrySetResult(response?.Products?.FirstOrDefault());
}


/// <summary>
/// Consume a purchase with a purchase token.
/// </summary>
Expand Down Expand Up @@ -341,6 +388,7 @@ public override void Dispose(bool disposing)

base.Dispose(disposing);
}

}


Expand Down Expand Up @@ -471,11 +519,15 @@ public static InAppBillingPurchase ToIABPurchase(this SKPaymentTransaction trans
if (p == null)
return null;

#if __IOS__ || __TVOS__
var finalToken = p.TransactionReceipt?.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
if (string.IsNullOrEmpty(finalToken))
finalToken = transaction.TransactionReceipt?.GetBase64EncodedString(NSDataBase64EncodingOptions.None);

return new InAppBillingPurchase
#else
var finalToken = string.Empty;
#endif
return new InAppBillingPurchase
{
TransactionDateUtc = NSDateToDateTimeUtc(transaction.TransactionDate),
Id = p.TransactionIdentifier,
Expand Down
9 changes: 7 additions & 2 deletions src/Plugin.InAppBilling/Plugin.InAppBilling.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;MonoAndroid10.0;Xamarin.iOS10;Xamarin.TVOS10</TargetFrameworks>
<TargetFrameworks>netstandard2.0;MonoAndroid10.0;Xamarin.iOS10;Xamarin.TVOS10;Xamarin.Mac20</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);uap10.0.16299;</TargetFrameworks>
<AssemblyName>Plugin.InAppBilling</AssemblyName>
<RootNamespace>Plugin.InAppBilling</RootNamespace>
Expand Down Expand Up @@ -61,6 +61,7 @@
<Compile Include="**\*.netstandard.cs" />
</ItemGroup>


<ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
<Compile Include="**\*.uwp.cs" />
</ItemGroup>
Expand All @@ -77,7 +78,7 @@

<ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
<Compile Include="**\*.android.cs" />
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.2" />
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
<PackageReference Include="Xamarin.Android.Google.BillingClient" Version="3.0.0" />
<!--<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.6.1" />-->
</ItemGroup>
Expand All @@ -90,4 +91,8 @@
<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.TVOS')) ">
<Compile Include="**\*.apple.cs" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.Mac')) ">
<Compile Include="**\*.apple.cs" />
</ItemGroup>
</Project>

0 comments on commit 7d5c0cb

Please sign in to comment.