Skip to content

Commit

Permalink
Release 8.2.0
Browse files Browse the repository at this point in the history
Release 8.2.0
  • Loading branch information
SpertsyanKM authored Nov 21, 2024
2 parents 8f6d2d2 + 01f24b9 commit 67ac2ea
Show file tree
Hide file tree
Showing 18 changed files with 254 additions and 15 deletions.
4 changes: 2 additions & 2 deletions Editor/QonversionDependencies.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<dependencies>
<androidPackages>
<androidPackage spec="io.qonversion.sandwich:sandwich:5.1.7" />
<androidPackage spec="io.qonversion.sandwich:sandwich:5.2.0" />
<androidPackage spec="com.fasterxml.jackson.core:jackson-databind:2.11.1" />
<androidPackage spec="org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.61" />
</androidPackages>
<iosPods>
<iosPod name="QonversionSandwich" version="5.1.7" />
<iosPod name="QonversionSandwich" version="5.2.0" />
</iosPods>
</dependencies>
4 changes: 4 additions & 0 deletions Runtime/Android/QonversionWrapperAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public void CheckEntitlements(string callbackName)
{
CallQonversion("checkEntitlements", callbackName);
}

public void GetPromotionalOffer(string productId, string discountId, string callbackName)
{
}

public void Purchase(string productId, PurchaseOptions purchaseOptions, string callbackName) {
var updatePolicyKey = purchaseOptions.UpdatePolicy == null
Expand Down
28 changes: 28 additions & 0 deletions Runtime/Scripts/Dto/PromotionalOffer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;

namespace QonversionUnity
{
public class PromotionalOffer
{
public readonly SKProductDiscount ProductDiscount;
public readonly SKPaymentDiscount PaymentDiscount;

public PromotionalOffer(Dictionary<string, object> dict)
{
if (dict.TryGetValue("productDiscount", out object value) && value is Dictionary<string, object> productDiscount)
{
ProductDiscount = new SKProductDiscount(productDiscount);
}
if (dict.TryGetValue("paymentDiscount", out value) && value is Dictionary<string, object> paymentDiscount)
{
PaymentDiscount = new SKPaymentDiscount(paymentDiscount);
}
}

public override string ToString()
{
return $"{nameof(ProductDiscount)}: {ProductDiscount}, " +
$"{nameof(PaymentDiscount)}: {PaymentDiscount}";
}
}
}
3 changes: 3 additions & 0 deletions Runtime/Scripts/Dto/PromotionalOffer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions Runtime/Scripts/Dto/PurchaseOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,34 @@ public class PurchaseOptions

public readonly int Quantity;

[CanBeNull] public readonly PromotionalOffer PromotionalOffer;

public PurchaseOptions(
[CanBeNull] string offerId,
bool applyOffer,
[CanBeNull] Product oldProduct,
[CanBeNull] PurchaseUpdatePolicy? updatePolicy,
[CanBeNull] List<string> contextKeys,
int quantity)
int quantity,
[CanBeNull] PromotionalOffer promotionalOffer)
{
OfferId = offerId;
ApplyOffer = applyOffer;
OldProduct = oldProduct;
UpdatePolicy = updatePolicy;
ContextKeys = contextKeys;
Quantity = quantity;
PromotionalOffer = promotionalOffer;
}

public override string ToString() {
return $"{nameof(OfferId)}: {OfferId}, " +
$"{nameof(ApplyOffer)}: {ApplyOffer}, " +
$"{nameof(OldProduct)}: {OldProduct}, " +
$"{nameof(UpdatePolicy)}: {UpdatePolicy}, " +
$"{nameof(ContextKeys)}: {ContextKeys}";
$"{nameof(ContextKeys)}: {ContextKeys}, " +
$"{nameof(Quantity)}: {Quantity}, " +
$"{nameof(PromotionalOffer)}: {PromotionalOffer}";
}
}
}
14 changes: 13 additions & 1 deletion Runtime/Scripts/Dto/PurchaseOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class PurchaseOptionsBuilder {
[CanBeNull] private PurchaseUpdatePolicy? _updatePolicy;
[CanBeNull] private List<string> _contextKeys;
private int _quantity = 1;
[CanBeNull] private PromotionalOffer _promotionalOffer;

/// <summary>
/// iOS only.
Expand Down Expand Up @@ -94,13 +95,24 @@ public PurchaseOptionsBuilder SetContextKeys(List<string> contextKeys)
return this;
}

/// <summary>
/// Set the promotional offer details.
/// </summary>
/// <param name="promoOffer">Promotional offer details.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetPromotionalOffer(PromotionalOffer promoOffer)
{
_promotionalOffer = promoOffer;
return this;
}

/// <summary>
/// Generate a <see cref="PurchaseOptions"/> instance with all the provided options.
/// </summary>
/// <returns>The complete <see cref="PurchaseOptions"/> instance.</returns>
public PurchaseOptions Build()
{
return new PurchaseOptions(_offerId, _applyOffer, _oldProduct, _updatePolicy, _contextKeys, _quantity);
return new PurchaseOptions(_offerId, _applyOffer, _oldProduct, _updatePolicy, _contextKeys, _quantity, _promotionalOffer);
}
}
}
28 changes: 28 additions & 0 deletions Runtime/Scripts/Dto/SkProduct/SKPraymentDiscount.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;

namespace QonversionUnity
{
public class SKPaymentDiscount {
public readonly string Identifier;
public readonly string KeyIdentifier;
public readonly string Nonce;
public readonly string Signature;
public readonly long Timestamp;

public SKPaymentDiscount(Dictionary<string, object> dict) {
if (dict.TryGetValue("identifier", out object value)) Identifier = value as string;
if (dict.TryGetValue("keyIdentifier", out value)) KeyIdentifier = value as string;
if (dict.TryGetValue("nonce", out value)) Nonce = value as string;
if (dict.TryGetValue("signature", out value)) Signature = value as string;
if (dict.TryGetValue("timestamp", out object timestamp)) Timestamp = (long)timestamp;
}

public override string ToString() {
return $"{nameof(Identifier)}: {Identifier}, " +
$"{nameof(KeyIdentifier)}: {KeyIdentifier}, " +
$"{nameof(Nonce)}: {Nonce}, " +
$"{nameof(Signature)}: {Signature}, " +
$"{nameof(Timestamp)}: {Timestamp}";
}
}
}
3 changes: 3 additions & 0 deletions Runtime/Scripts/Dto/SkProduct/SKPraymentDiscount.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Runtime/Scripts/Dto/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public class Transaction
/// Offer code.
[CanBeNull] public readonly string OfferCode;

/// Promo offer id.
[CanBeNull] public readonly string PromoOfferId;

/// Transaction date.
public readonly DateTime TransactionDate;

Expand All @@ -40,6 +43,7 @@ public Transaction(Dictionary<string, object> dict)
if (dict.TryGetValue("originalTransactionId", out object value)) OriginalTransactionId = value as string;
if (dict.TryGetValue("transactionId", out value)) TransactionId = value as string;
if (dict.TryGetValue("offerCode", out value)) OfferCode = value as string;
if (dict.TryGetValue("promoOfferId", out value)) PromoOfferId = value as string;
if (dict.TryGetValue("transactionTimestamp", out value)) TransactionDate = FormatDate(value);
if (dict.TryGetValue("expirationTimestamp", out value) && value != null) ExpirationDate = FormatDate(value);
if (dict.TryGetValue("transactionRevocationTimestamp", out value) && value != null) TransactionRevocationDate = FormatDate(value);
Expand All @@ -53,6 +57,7 @@ public override string ToString()
return $"{nameof(OriginalTransactionId)}: {OriginalTransactionId}, " +
$"{nameof(TransactionId)}: {TransactionId}, " +
$"{nameof(OfferCode)}: {OfferCode}, " +
$"{nameof(PromoOfferId)}: {PromoOfferId}, " +
$"{nameof(TransactionDate)}: {TransactionDate}, " +
$"{nameof(ExpirationDate)}: {ExpirationDate}, " +
$"{nameof(TransactionRevocationDate)}: {TransactionRevocationDate}, " +
Expand Down
13 changes: 13 additions & 0 deletions Runtime/Scripts/IQonversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ public interface IQonversion
/// </summary>
public void SyncStoreKit2Purchases();

/// <summary>
/// iOS only.
/// Retrieve the promotional offer for the product if it exists.
/// Make sure to call this function before displaying product details to the user.
/// The generated signature for the promotional offer is valid for a single transaction.
/// If the purchase fails, you need to call this function again to obtain a new promotional offer signature.
/// Use this signature to complete the purchase through the purchase function, along with the purchase options object.
/// </summary>
/// <param name="product">Product you want to purchase.</param>
/// <param name="discount">Discount to create promotional offer signature.</param>
/// <param name="callback">Callback that will be called when response is received.</param>
public void GetPromotionalOffer(Product product, SKProductDiscount discount, Qonversion.OnPromotionalOfferReceived callback);

/// <summary>
/// Make a purchase and validate it through server-to-server using Qonversion's Backend.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions Runtime/Scripts/Internal/Mapper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using QonversionUnity.MiniJSON;
using UnityEngine;

Expand Down Expand Up @@ -141,6 +142,17 @@ internal static Dictionary<string, Eligibility> EligibilitiesFromJson(string jso
return result;
}

[CanBeNull] internal static PromotionalOffer PromotionalOfferFromJson(string jsonStr)
{
if (!(Json.Deserialize(jsonStr) is Dictionary<string, object> promoOfferInfo))
{
Debug.LogError("Could not parse PromotionalOffer");
return null;
}

return new PromotionalOffer(promoOfferInfo);
}

internal static User UserFromJson(string jsonStr)
{
if (!(Json.Deserialize(jsonStr) is Dictionary<string, object> userInfo))
Expand Down
74 changes: 72 additions & 2 deletions Runtime/Scripts/Internal/QonversionInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ internal class QonversionInternal : MonoBehaviour, IQonversion
private const string OnAttachUserMethodName = "OnAttachUser";
private const string OnDetachUserMethodName = "OnDetachUser";
private const string OnIsFallbackFileAccessibleMethodName = "OnIsFallbackFileAccessible";
private const string OnPromotionalOfferMethodName = "OnPromotionalOffer";

private const string SdkVersion = "8.1.3";
private const string SdkVersion = "8.2.0";
private const string SdkSource = "unity";

private const string DefaultRemoteConfigContextKey = "";
Expand All @@ -54,7 +55,9 @@ internal class QonversionInternal : MonoBehaviour, IQonversion
private Qonversion.OnUserPropertiesReceived UserPropertiesCallback { get; set; }
private Qonversion.OnAttachUserResponseReceived AttachUserCallback { get; set; }
private Qonversion.OnAttachUserResponseReceived DetachUserCallback { get; set; }
private Qonversion.OnFallbackFileAccessibilityResponseReceived FallbackFileCallback { get; set; }
private Qonversion.OnFallbackFileAccessibilityResponseReceived FallbackFileCallback { get; set; }

private Dictionary<string, List<Qonversion.OnPromotionalOfferReceived>> PromotionalOfferCallbacks { get; } = new Dictionary<string, List<Qonversion.OnPromotionalOfferReceived>>();

public event Qonversion.OnPromoPurchasesReceived PromoPurchasesReceived
{
Expand Down Expand Up @@ -113,6 +116,24 @@ public void SyncStoreKit2Purchases()
instance.SyncStoreKit2Purchases();
}

public void GetPromotionalOffer(Product product, SKProductDiscount discount, Qonversion.OnPromotionalOfferReceived callback)
{
if (discount.Identifier == null)
{
callback.Invoke(null, new QonversionError(QErrorCode.IncorrectRequest, "Discount identifier is null"));
return;
}

var id = GetPromotionalOfferCallbackIdentifier(product.QonversionId, discount.Identifier);
if (!PromotionalOfferCallbacks.ContainsKey(id)) {
PromotionalOfferCallbacks[id] = new List<Qonversion.OnPromotionalOfferReceived>();
}
PromotionalOfferCallbacks[id].Add(callback);

IQonversionWrapper instance = GetNativeWrapper();
instance.GetPromotionalOffer(product.QonversionId, discount.Identifier, OnPromotionalOfferMethodName);
}

public void Purchase(PurchaseModel purchaseModel, Qonversion.OnPurchaseResultReceived callback)
{
PurchaseCallback = callback;
Expand Down Expand Up @@ -523,6 +544,50 @@ private void OnIsFallbackFileAccessible(string jsonString)
FallbackFileCallback(isAccessible);
}

private void OnPromotionalOffer(string jsonString)
{
if (PromotionalOfferCallbacks.Count == 0) return;

string key = null;
if (
Json.Deserialize(jsonString) is Dictionary<string, object> dict &&
dict.TryGetValue("productId", out var productId) &&
dict.TryGetValue("discountId", out var discountId)
) {
key = GetPromotionalOfferCallbackIdentifier(productId as string, discountId as string);
}

var error = Mapper.ErrorFromJson(jsonString);
if (error != null)
{
if (key == null) {
foreach (var callbacksForKey in PromotionalOfferCallbacks)
{
callbacksForKey.Value.ForEach(callback => callback(null, error));
}

PromotionalOfferCallbacks.Clear();
return;
}

if (PromotionalOfferCallbacks.ContainsKey(key))
{
PromotionalOfferCallbacks[key].ForEach(callback => callback(null, error));
PromotionalOfferCallbacks[key].Clear();
}
}
else if (key != null)
{
var promotionalOffer = Mapper.PromotionalOfferFromJson(jsonString);

if (PromotionalOfferCallbacks.ContainsKey(key))
{
PromotionalOfferCallbacks[key].ForEach(callback => callback(promotionalOffer, null));
PromotionalOfferCallbacks[key].Clear();
}
}
}

// Called from the native SDK - Called when eligibilities received from the checkTrialIntroEligibilityForProductIds() method
private void OnEligibilities(string jsonString)
{
Expand Down Expand Up @@ -662,6 +727,11 @@ private void HandlePurchaseResult(Qonversion.OnPurchaseResultReceived callback,
}
}

private string GetPromotionalOfferCallbackIdentifier(string productId, string discountId)
{
return productId + "$%" + discountId;
}

private IQonversionWrapper GetNativeWrapper()
{
if (_nativeWrapperInstance != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal interface IQonversionWrapper
void SyncPurchases();
void AddAttributionData(string conversionData, string providerName);
void CheckEntitlements(string callbackName);
void GetPromotionalOffer(string productId, string discountId, string callbackName);
void Purchase(string productId, PurchaseOptions purchaseOptions, string callbackName);
void Purchase(PurchaseModel purchaseModel, string callbackName);
void Restore(string callbackName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public void CheckEntitlements(string callbackName)
{
}

public void GetPromotionalOffer(string productId, string discountId, string callbackName)
{
}

public void Purchase(PurchaseModel purchaseModel, string callbackName)
{
}
Expand Down
1 change: 1 addition & 0 deletions Runtime/Scripts/Qonversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public static IQonversion Initialize(QonversionConfig config)
public delegate void OnEligibilitiesReceived(Dictionary<string, Eligibility> eligibilities, QonversionError error);
public delegate void OnUserInfoReceived(User userInfo, QonversionError error);
public delegate void OnFallbackFileAccessibilityResponseReceived(bool success);
public delegate void OnPromotionalOfferReceived(PromotionalOffer promotionalOffer, QonversionError error);

/// <summary>
/// Delegate fires each time a promo purchase from the App Store happens.
Expand Down
Loading

0 comments on commit 67ac2ea

Please sign in to comment.