Skip to content

Commit

Permalink
Merge pull request #35 from qonversion/release/3.2.0
Browse files Browse the repository at this point in the history
Release/3.2.0
  • Loading branch information
Maria-Bordunova authored Oct 15, 2021
2 parents e746f03 + fc3468f commit ac491fa
Show file tree
Hide file tree
Showing 20 changed files with 531 additions and 86 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.android.sdk:sdk:3.1.1" />
<androidPackage spec="io.qonversion.android.sdk:sdk:3.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="Qonversion" version="2.17.1" />
<iosPod name="Qonversion" version="2.18.0" />
</iosPods>
</dependencies>
80 changes: 72 additions & 8 deletions Runtime/Android/Plugins/com/qonversion/unitywrapper/Mapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import com.android.billingclient.api.SkuDetails;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qonversion.android.sdk.dto.QPermission;
import com.qonversion.android.sdk.dto.eligibility.QEligibility;
import com.qonversion.android.sdk.dto.eligibility.QIntroEligibilityStatus;
import com.qonversion.android.sdk.dto.offerings.QOffering;
import com.qonversion.android.sdk.dto.offerings.QOfferings;
import com.qonversion.android.sdk.dto.products.QProduct;
import com.qonversion.android.sdk.dto.products.QProductDuration;
import com.qonversion.android.sdk.dto.products.QProductType;
import com.qonversion.android.sdk.dto.products.QTrialDuration;

import java.util.ArrayList;
Expand All @@ -18,6 +20,15 @@
import java.util.Map;

public final class Mapper {
private static final String ID = "id";
private static final String STORE_ID = "store_id";
private static final String TYPE = "type";
private static final String OFFERING_ID = "offeringId";
private static final String DURATION = "duration";
private static final String TRIAL_DURATION = "trialDuration";
private static final String STORE_PRODUCT = "storeProduct";
private static final String PRETTY_PRICE = "prettyPrice";
private static final String SKU_DETAILS_JSON = "originalJson";

static List<Map<String, Object>> mapPermissions(Map<String, QPermission> permissions) {
List<Map<String, Object>> result = new ArrayList<>();
Expand Down Expand Up @@ -57,30 +68,83 @@ static List<Map<String, Object>> mapProducts(Map<String, QProduct> products) {
static Map<String, Object> mapProduct(QProduct product) {
Map<String, Object> result = new HashMap<>();

result.put("id", product.getQonversionID());
result.put("store_id", product.getStoreID());
result.put("type", product.getType().getType());
result.put(ID, product.getQonversionID());
result.put(STORE_ID, product.getStoreID());
result.put(TYPE, product.getType().getType());

String offeringId = product.getOfferingID();
result.put(OFFERING_ID, offeringId);

QProductDuration duration = product.getDuration();
if (duration != null) {
result.put("duration", duration.getType());
result.put(DURATION, duration.getType());
}

QTrialDuration trialDuration = product.getTrialDuration();
if (trialDuration != null) {
result.put("trialDuration", trialDuration.getType());
result.put(TRIAL_DURATION, trialDuration.getType());
}

SkuDetails skuDetails = product.getSkuDetail();
if (skuDetails != null) {
Map<String, Object> mappedSkuDetails = mapSkuDetails(skuDetails);
result.put("storeProduct", mappedSkuDetails);
result.put("prettyPrice", product.getPrettyPrice());
result.put(STORE_PRODUCT, mappedSkuDetails);
result.put(PRETTY_PRICE, product.getPrettyPrice());
}

return result;
}

static QProduct mapProductFromJson(String productJson) throws Exception {
ObjectMapper mapper = new ObjectMapper();

TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {};
Map<String, Object> map = mapper.readValue(productJson, typeRef);

String id = String.valueOf(map.get(ID));
String storeId = String.valueOf(map.get(STORE_ID));
String offeringId = String.valueOf(map.get(OFFERING_ID));
String prettyPrice = String.valueOf(map.get(PRETTY_PRICE));

Object skuDetailsObj = map.get(STORE_PRODUCT);
SkuDetails skuDetails = mapSkuDetailsFromObject(skuDetailsObj);

Integer type = (Integer) map.get(TYPE);
if (type == null) return null;
QProductType qProductType = QProductType.Companion.fromType(type);

QProductDuration qProductDuration = null;
Integer duration = (Integer) map.get(DURATION);
if (duration != null) {
qProductDuration = QProductDuration.Companion.fromType(duration);
}

QTrialDuration qTrialDuration = null;
Integer trialDuration = (Integer) map.get(TRIAL_DURATION);
if (trialDuration != null) {
qTrialDuration = QTrialDuration.Companion.fromType(trialDuration);
}

QProduct product = new QProduct(id, storeId, qProductType, qProductDuration);
product.setOfferingID(offeringId);
product.setSkuDetail(skuDetails);
product.setPrettyPrice(prettyPrice);
product.setTrialDuration(qTrialDuration);

return product;
}

static private SkuDetails mapSkuDetailsFromObject(Object map) throws Exception {
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {
};

Map<String, Object> skuDetailsMap = mapper.convertValue(map, typeRef);
String originalJson = String.valueOf(skuDetailsMap.get(SKU_DETAILS_JSON));

return new SkuDetails(originalJson);
}

static private Map<String, Object> mapSkuDetails(SkuDetails skuDetails) {
Map<String, Object> result = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import android.content.SharedPreferences;
import android.util.Log;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.qonversion.android.sdk.QUserProperties;

import com.qonversion.android.sdk.QonversionEligibilityCallback;
import com.qonversion.android.sdk.QonversionErrorCode;
import com.qonversion.android.sdk.QonversionOfferingsCallback;
import com.qonversion.android.sdk.QonversionProductsCallback;
import com.qonversion.android.sdk.dto.eligibility.QEligibility;
Expand Down Expand Up @@ -118,6 +118,14 @@ public static synchronized void setUserId(String value) {
Qonversion.setUserID(value);
}

public static synchronized void identify(String value) {
Qonversion.identify(value);
}

public static synchronized void logout() {
Qonversion.logout();
}

public static synchronized void checkPermissions(String unityCallbackName) {
Qonversion.checkPermissions(new QonversionPermissionsCallback() {
@Override
Expand Down Expand Up @@ -146,6 +154,30 @@ public void onError(@NotNull QonversionError error) {
});
}

public static synchronized void purchaseProduct(String productJson, String unityCallbackName) {
try {
QProduct product = Mapper.mapProductFromJson(productJson);
if (product == null) {
QonversionError error = new QonversionError(QonversionErrorCode.PurchaseInvalid, "Qonversion Product is null");
handleErrorResponse(error, unityCallbackName);
return;
}
Qonversion.purchase(UnityPlayer.currentActivity, product, new QonversionPermissionsCallback() {
@Override
public void onSuccess(@NotNull Map<String, QPermission> permissions) {
handlePermissionsResponse(permissions, unityCallbackName);
}

@Override
public void onError(@NotNull QonversionError error) {
handleErrorResponse(error, unityCallbackName);
}
});
} catch (Exception e) {
handleException(e);
}
}

public static synchronized void updatePurchase(String productId, String oldProductId, int prorationMode, String unityCallbackName) {
Qonversion.updatePurchase(UnityPlayer.currentActivity, productId, oldProductId, prorationMode, new QonversionPermissionsCallback() {
@Override
Expand All @@ -160,6 +192,30 @@ public void onError(@NotNull QonversionError error) {
});
}

public static synchronized void updatePurchaseWithProduct(String newProductJson, String oldProductId, int prorationMode, String unityCallbackName) {
try {
QProduct product = Mapper.mapProductFromJson(newProductJson);
if (product == null) {
QonversionError error = new QonversionError(QonversionErrorCode.PurchaseInvalid, "Qonversion Product is null");
handleErrorResponse(error, unityCallbackName);
return;
}
Qonversion.updatePurchase(UnityPlayer.currentActivity, product, oldProductId, prorationMode, new QonversionPermissionsCallback() {
@Override
public void onSuccess(@NotNull Map<String, QPermission> permissions) {
handlePermissionsResponse(permissions, unityCallbackName);
}

@Override
public void onError(@NotNull QonversionError error) {
handleErrorResponse(error, unityCallbackName);
}
});
} catch (Exception e) {
handleException(e);
}
}

public static synchronized void restore(String unityCallbackName) {
Qonversion.restore(new QonversionPermissionsCallback() {
@Override
Expand Down Expand Up @@ -223,7 +279,7 @@ public void onError(@NotNull QonversionError error) {
}
});
} catch (JsonProcessingException e) {
handleJsonProcessingException(e);
handleException(e);
}
}

Expand Down Expand Up @@ -252,11 +308,11 @@ private static void sendMessageToUnity(@NotNull Object objectToConvert, @NotNull
String json = mapper.writeValueAsString(objectToConvert);
UnityPlayer.UnitySendMessage(unityListenerName, methodName, json);
} catch (JsonProcessingException e) {
handleJsonProcessingException(e);
handleException(e);
}
}

private static void handleJsonProcessingException(JsonProcessingException e) {
private static void handleException(Exception e) {
Log.e(TAG, "An error occurred while serializing data: " + e.getLocalizedMessage());
}
}
24 changes: 24 additions & 0 deletions Runtime/Android/QonversionWrapperAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public void SetAdvertisingID()
{
}

public void SetAppleSearchAdsAttributionEnabled(bool enable)
{
}

public void AddAttributionData(string conversionData, AttributionSource source)
{
string attibutionSource;
Expand Down Expand Up @@ -81,6 +85,16 @@ public void AddAttributionData(string conversionData, AttributionSource source)
}
}

public void Identify(string userID)
{
CallQonversion("identify", userID);
}

public void Logout()
{
CallQonversion("logout");
}

public void CheckPermissions(string callbackName)
{
CallQonversion("checkPermissions", callbackName);
Expand All @@ -91,6 +105,11 @@ public void Purchase(string productId, string callbackName)
CallQonversion("purchase", productId, callbackName);
}

public void PurchaseProduct(string productJson, string callbackName)
{
CallQonversion("purchaseProduct", productJson, callbackName);
}

public void Restore(string callbackName)
{
CallQonversion("restore", callbackName);
Expand All @@ -101,6 +120,11 @@ public void UpdatePurchase(string productId, string oldProductId, ProrationMode
CallQonversion("updatePurchase", productId, oldProductId, (int)prorationMode, callbackName);
}

public void UpdatePurchaseWithProduct(string productJson, string oldProductId, ProrationMode prorationMode, string callbackName)
{
CallQonversion("updatePurchaseWithProduct", productJson, oldProductId, (int)prorationMode, callbackName);
}

public void Products(string callbackName)
{
CallQonversion("products", callbackName);
Expand Down
5 changes: 5 additions & 0 deletions Runtime/Scripts/IQonversionWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ internal interface IQonversionWrapper
void AddAttributionData(string conversionData, AttributionSource source);
void CheckPermissions(string callbackName);
void Purchase(string productId, string callbackName);
void PurchaseProduct(string productJson, string callbackName);
void Restore(string callbackName);
void UpdatePurchase(string productId, string oldProductId, ProrationMode prorationMode, string callbackName);
void UpdatePurchaseWithProduct(string productJson, string oldProductId, ProrationMode prorationMode, string callbackName);
void Products(string callbackName);
void Offerings(string callbackName);
void CheckTrialIntroEligibilityForProductIds(string productIdsJson, string callbackName);
void SetAppleSearchAdsAttributionEnabled(bool enable);
void Identify(string userID);
void Logout();
}
}
2 changes: 2 additions & 0 deletions Runtime/Scripts/Models/Offering.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;

namespace QonversionUnity
{
Expand All @@ -19,6 +20,7 @@ public Offering(Dictionary<string, object> dict)
}
}

[CanBeNull]
public Product ProductForID(string id)
{
return Products.Find(product => product.QonversionId == id);
Expand Down
1 change: 1 addition & 0 deletions Runtime/Scripts/Models/Offerings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public Offerings(Dictionary<string, object> dict)
}
}

[CanBeNull]
public Offering OfferingForID(string id)
{
return AvailableOfferings.Find(offering => offering.Id == id);
Expand Down
10 changes: 9 additions & 1 deletion Runtime/Scripts/Models/Product.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using QonversionUnity.MiniJSON;
using UnityEngine;

namespace QonversionUnity
Expand All @@ -15,12 +16,14 @@ public class Product
[Tooltip("Create Products: (https://qonversion.io/docs/create-products")]
[CanBeNull] public readonly string StoreId;

/// Associated Offering Id
[CanBeNull] public readonly string OfferingId;

/// Product type.
[Tooltip("Products types: https://qonversion.io/docs/product-types")]
public readonly QProductType Type;

/// Product duration.

[Tooltip("Products durations: https://qonversion.io/docs/product-durations")]
public readonly QProductDuration Duration;

Expand Down Expand Up @@ -53,14 +56,19 @@ public class Product
/// Formatted introductory price of a subscription, including its currency sign, such as €2.99
[CanBeNull] public readonly string PrettyIntroductoryPrice;

internal readonly string OriginalJson;

public Product(Dictionary<string, object> dict)
{
OriginalJson = Json.Serialize(dict);

if (dict.TryGetValue("id", out object value)) QonversionId = value as string;
if (dict.TryGetValue("store_id", out value)) StoreId = value as string;
if (dict.TryGetValue("type", out value)) Type = FormatType(value);
if (dict.TryGetValue("duration", out value)) Duration = FormatDuration(value);
if (dict.TryGetValue("trialDuration", out value)) TrialDuration = FormatTrialDuration(value);
if (dict.TryGetValue("prettyPrice", out value)) PrettyPrice = value as string;
if (dict.TryGetValue("offeringId", out value)) OfferingId = value as string;

if (dict.TryGetValue("storeProduct", out value))
{
Expand Down
Loading

0 comments on commit ac491fa

Please sign in to comment.