Skip to content

Commit

Permalink
Merge pull request #253 from qonversion/release/8.1.0
Browse files Browse the repository at this point in the history
Release 8.1.0
  • Loading branch information
SpertsyanKM authored Sep 6, 2024
2 parents b400377 + 2081567 commit 6f2d21d
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 46 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.0.4" />
<androidPackage spec="io.qonversion.sandwich:sandwich:5.1.3" />
<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.0.4" />
<iosPod name="QonversionSandwich" version="5.1.3" />
</iosPods>
</dependencies>
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
public class QonversionWrapper {
public static String TAG = "QonversionWrapper";
public static String ENTITLEMENTS_UPDATE_LISTENER = "OnReceivedUpdatedEntitlements";
public static String NATIVE_MODULE_ERROR_CODE = "NativeModuleError";

private static MessageSender messageSender;
private static QonversionSandwich qonversionSandwich;
Expand Down Expand Up @@ -95,7 +96,7 @@ public static synchronized void attribution(String conversionData, String attrib

qonversionSandwich.addAttributionData(attributionProvider, conversionInfo);
} catch (JsonProcessingException e) {
handleSerializationException(e);
handleSerializationException(e, null);
}
}

Expand All @@ -115,8 +116,34 @@ public static synchronized void checkEntitlements(String unityCallbackName) {
qonversionSandwich.checkEntitlements(getResultListener(unityCallbackName));
}

public static synchronized void purchase(String productId, @Nullable String offerId, boolean applyOffer, String unityCallbackName) {
qonversionSandwich.purchase(productId, offerId, applyOffer, getResultListener(unityCallbackName));
public static synchronized void purchase(
String productId,
@Nullable String offerId,
boolean applyOffer,
@Nullable String oldProductId,
@Nullable String updatePolicyKey,
@Nullable String contextKeys,
String unityCallbackName
) {
try {
List<String> contextKeysList = null;
if (contextKeys != null) {
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<String>> typeRef = new TypeReference<List<String>>() {};
contextKeysList = mapper.readValue(contextKeys, typeRef);
}
qonversionSandwich.purchase(
productId,
offerId,
applyOffer,
oldProductId,
updatePolicyKey,
contextKeysList,
getResultListener(unityCallbackName)
);
} catch (JsonProcessingException e) {
handleSerializationException(e, unityCallbackName);
}
}

public static synchronized void updatePurchase(
Expand All @@ -127,7 +154,7 @@ public static synchronized void updatePurchase(
@Nullable String updatePolicyKey,
String unityCallbackName
) {
qonversionSandwich.updatePurchase(productId, offerId, applyOffer, oldProductId, updatePolicyKey, getResultListener(unityCallbackName));
purchase(productId, offerId, applyOffer, oldProductId, updatePolicyKey, null, unityCallbackName);
}

public static synchronized void restore(String unityCallbackName) {
Expand Down Expand Up @@ -159,7 +186,7 @@ public static synchronized void remoteConfigList(String contextKeysJson, boolean

qonversionSandwich.remoteConfigList(contextKeys, includeEmptyContextKey, getResultListener(unityCallbackName));
} catch (JsonProcessingException e) {
handleSerializationException(e);
handleSerializationException(e, unityCallbackName);
}
}

Expand Down Expand Up @@ -191,7 +218,7 @@ public static synchronized void checkTrialIntroEligibility(String productIds, St

qonversionSandwich.checkTrialIntroEligibility(productIdList, getResultListener(unityCallbackName));
} catch (JsonProcessingException e) {
handleSerializationException(e);
handleSerializationException(e, unityCallbackName);
}
}

Expand Down Expand Up @@ -232,15 +259,27 @@ private static void handleErrorResponse(@NotNull SandwichError error, @NotNull S
sendMessageToUnity(rootNode, methodName);
}

private static void handleLocalException(@NotNull String message, @NotNull Exception e, @Nullable String unityCallbackName) {
if (unityCallbackName == null) {
return;
}

final ObjectNode rootNode = Utils.createErrorNode(NATIVE_MODULE_ERROR_CODE, message, e.getLocalizedMessage());

sendMessageToUnity(rootNode, unityCallbackName);
}

private static void sendMessageToUnity(@NotNull Object objectToConvert, @NotNull String methodName) {
try {
messageSender.sendMessageToUnity(objectToConvert, methodName);
} catch (JsonProcessingException e) {
handleSerializationException(e);
handleSerializationException(e, methodName);
}
}

private static void handleSerializationException(JsonProcessingException e) {
private static void handleSerializationException(JsonProcessingException e, @Nullable String methodName) {
Log.e(TAG, "An error occurred while serializing data: " + e.getLocalizedMessage());

handleLocalException("An error occurred while serializing data", e, methodName);
}
}
14 changes: 11 additions & 3 deletions Runtime/Android/Plugins/com/qonversion/unitywrapper/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@
import com.fasterxml.jackson.databind.node.ObjectNode;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import io.qonversion.sandwich.SandwichError;

public class Utils {

public static ObjectNode createErrorNode(@NotNull SandwichError error) {
return createErrorNode(error.getCode(), error.getDescription(), error.getAdditionalMessage());
}

public static ObjectNode createErrorNode(String code, String description, @Nullable String additionalMessage) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode errorNode = mapper.createObjectNode();
errorNode.put("code", error.getCode());
errorNode.put("description", error.getDescription());
errorNode.put("additionalMessage", error.getAdditionalMessage());
errorNode.put("code", code);
errorNode.put("description", description);
if (additionalMessage != null) {
errorNode.put("additionalMessage", additionalMessage);
}

ObjectNode rootNode = mapper.createObjectNode();
rootNode.set("error", errorNode);
Expand Down
26 changes: 25 additions & 1 deletion Runtime/Android/QonversionWrapperAndroid.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using QonversionUnity.MiniJSON;
using UnityEngine;

namespace QonversionUnity
Expand Down Expand Up @@ -106,13 +107,36 @@ public void CheckEntitlements(string callbackName)
CallQonversion("checkEntitlements", callbackName);
}

public void Purchase(string productId, PurchaseOptions purchaseOptions, string callbackName) {
var updatePolicyKey = purchaseOptions.UpdatePolicy == null
? null
: Enum.GetName(typeof(PurchaseUpdatePolicy), purchaseOptions.UpdatePolicy);
var contextKeysJson = purchaseOptions.ContextKeys == null
? null
: Json.Serialize(purchaseOptions.ContextKeys);

CallQonversion(
"purchase",
productId,
purchaseOptions.OfferId,
purchaseOptions.ApplyOffer,
purchaseOptions.OldProduct?.QonversionId,
updatePolicyKey,
contextKeysJson,
callbackName
);
}

public void Purchase(PurchaseModel purchaseModel, string callbackName)
{
CallQonversion(
"purchase",
purchaseModel.ProductId,
purchaseModel.OfferId,
purchaseModel.ApplyOffer,
null,
null,
null,
callbackName
);
}
Expand All @@ -123,7 +147,7 @@ public void Restore(string callbackName)
}

public void UpdatePurchase(PurchaseUpdateModel purchaseUpdateModel, string callbackName) {
string updatePolicyKey = purchaseUpdateModel.UpdatePolicy == null
var updatePolicyKey = purchaseUpdateModel.UpdatePolicy == null
? null
: Enum.GetName(typeof(PurchaseUpdatePolicy), purchaseUpdateModel.UpdatePolicy);

Expand Down
45 changes: 45 additions & 0 deletions Runtime/Scripts/Dto/PurchaseOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;

namespace QonversionUnity
{
public class PurchaseOptions
{
[CanBeNull] public readonly string OfferId;

public readonly bool ApplyOffer;

[CanBeNull] public readonly Product OldProduct;

[CanBeNull] public readonly PurchaseUpdatePolicy? UpdatePolicy;

[CanBeNull] public readonly List<string> ContextKeys;

public readonly int Quantity;

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

public override string ToString() {
return $"{nameof(OfferId)}: {OfferId}, " +
$"{nameof(ApplyOffer)}: {ApplyOffer}, " +
$"{nameof(OldProduct)}: {OldProduct}, " +
$"{nameof(UpdatePolicy)}: {UpdatePolicy}, " +
$"{nameof(ContextKeys)}: {ContextKeys}";
}
}
}
3 changes: 3 additions & 0 deletions Runtime/Scripts/Dto/PurchaseOptions.cs.meta

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

106 changes: 106 additions & 0 deletions Runtime/Scripts/Dto/PurchaseOptionsBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System.Collections.Generic;
using JetBrains.Annotations;

namespace QonversionUnity
{
public class PurchaseOptionsBuilder {
[CanBeNull] private string _offerId;
private bool _applyOffer = true;
[CanBeNull] private Product _oldProduct;
[CanBeNull] private PurchaseUpdatePolicy? _updatePolicy;
[CanBeNull] private List<string> _contextKeys;
private int _quantity = 1;

/// <summary>
/// iOS only.
/// Set quantity of product purchasing. Use for consumable in-app products.
/// </summary>
/// <param name="quantity">Quantity of product purchasing.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetQuantity(int quantity)
{
this._quantity = quantity;
return this;
}

/// <summary>
/// Android only.
/// Set offer for the purchase.
/// </summary>
/// <param name="offer">Concrete offer which you'd like to purchase.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetOffer(ProductOfferDetails offer)
{
_offerId = offer.OfferId;
return this;
}

/// <summary>
/// Android only.
/// Set the offer ID to the purchase.
/// </summary>
/// <param name="offerId">Concrete offer ID which you'd like to purchase.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetOfferId(string offerId)
{
_offerId = offerId;
return this;
}

/// <summary>
/// Android only.
/// Call this function to remove any intro/trial offer from the purchase (use only a bare base plan).
/// </summary>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder RemoveOffer()
{
_applyOffer = false;
return this;
}

/// <summary>
/// Android only.
/// Set Qonversion product from which the upgrade/downgrade will be initialized.
/// </summary>
/// <param name="oldProduct">Qonversion product from which the upgrade/downgrade will be initialized.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetOldProduct(Product oldProduct)
{
_oldProduct = oldProduct;
return this;
}


/// <summary>
/// Android only.
/// Set the update policy for the purchase.
/// </summary>
/// <param name="updatePolicy">Update policy for the purchase.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetUpdatePolicy(PurchaseUpdatePolicy updatePolicy)
{
_updatePolicy = updatePolicy;
return this;
}

/// <summary>
/// Set the context keys associated with a purchase.
/// </summary>
/// <param name="contextKeys">Context keys for the purchase.</param>
/// <returns>Builder instance for chain calls.</returns>
public PurchaseOptionsBuilder SetContextKeys(List<string> contextKeys)
{
_contextKeys = contextKeys;
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);
}
}
}
3 changes: 3 additions & 0 deletions Runtime/Scripts/Dto/PurchaseOptionsBuilder.cs.meta

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

1 change: 1 addition & 0 deletions Runtime/Scripts/Dto/QonversionError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public enum QErrorCode
InvalidCredentials, // Access token is invalid or not set
InvalidStoreCredentials, // This account does not have access to the requested application
LaunchError, // There was an error while launching Qonversion SDK
NativeModuleError, // Something failed during native iOS or Android modules work or communication between Unity and native
NetworkConnectionFailed, // There was a network issue. Make sure that the Internet connection is available on the device
OfferingsNotFound, // No offerings found
PaymentInvalid, // Purchase identifier was invalid, etc.
Expand Down
Loading

0 comments on commit 6f2d21d

Please sign in to comment.