diff --git a/SingularSDK/Editor/SingularSDKDependencies.xml b/SingularSDK/Editor/SingularSDKDependencies.xml index 8d7eebf..5a1790e 100644 --- a/SingularSDK/Editor/SingularSDKDependencies.xml +++ b/SingularSDK/Editor/SingularSDKDependencies.xml @@ -1,6 +1,6 @@ - + https://maven.singular.net diff --git a/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.11.1.jar b/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.12.0.jar similarity index 90% rename from SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.11.1.jar rename to SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.12.0.jar index 51e01af..13b04a8 100644 Binary files a/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.11.1.jar and b/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.12.0.jar differ diff --git a/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.11.1.jar.meta b/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.12.0.jar.meta similarity index 93% rename from SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.11.1.jar.meta rename to SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.12.0.jar.meta index 14daeec..9bda986 100644 --- a/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.11.1.jar.meta +++ b/SingularSDK/Plugins/Android/SingularUnityBridge-KIDS-6.12.0.jar.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 145b4dda965ae4bafb8d00486dab8330 +guid: b906e1852190a47a9ac90f29d743ee69 PluginImporter: externalObjects: {} serializedVersion: 2 diff --git a/SingularSDK/Runtime/SingularSDK.asmdef b/SingularSDK/Runtime/SingularSDK.asmdef index 08ed0b1..ffb1204 100644 --- a/SingularSDK/Runtime/SingularSDK.asmdef +++ b/SingularSDK/Runtime/SingularSDK.asmdef @@ -2,7 +2,8 @@ "name": "SingularSDK", "rootNamespace": "", "references": [ - "UnityEngine.Purchasing" + "UnityEngine.Purchasing", + "Unity.Purchasing" ], "includePlatforms": [], "excludePlatforms": [], @@ -14,9 +15,14 @@ "versionDefines": [ { "name": "com.unity.purchasing", - "expression": "", - "define": "SINGULAR_SDK_IAP_ENABLED" - } + "expression": "[4.0,5.0)", + "define": "SINGULAR_SDK_IAP_ENABLED__IAP_4" + }, + { + "name": "com.unity.purchasing", + "expression": "[5.0,6.0)", + "define": "SINGULAR_SDK_IAP_ENABLED__IAP_5" + } ], "noEngineReferences": false } \ No newline at end of file diff --git a/SingularSDK/Runtime/SingularSDK.cs b/SingularSDK/Runtime/SingularSDK.cs index c755fc7..575f593 100644 --- a/SingularSDK/Runtime/SingularSDK.cs +++ b/SingularSDK/Runtime/SingularSDK.cs @@ -6,9 +6,9 @@ using System.Text.RegularExpressions; using Newtonsoft.Json; using UnityEngine; -#if SINGULAR_SDK_IAP_ENABLED +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 || SINGULAR_SDK_IAP_ENABLED__IAP_5 using UnityEngine.Purchasing; -#endif // SINGULAR_SDK_IAP_ENABLED +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 || SINGULAR_SDK_IAP_ENABLED__IAP_5 namespace Singular { @@ -30,9 +30,11 @@ public class SingularSDK : MonoBehaviour public static bool Initialized { get; private set; } = false; private const string UNITY_WRAPPER_NAME = "Unity"; - private const string UNITY_VERSION = "5.5.1-KIDS"; + private const string UNITY_VERSION = "5.6.0-KIDS"; - // ios-only: + #endregion // init properties + + #region iOS-only [Obsolete] public bool autoIAPComplete = false; public bool clipboardAttribution = false; @@ -1185,34 +1187,103 @@ private void SingularSdidReceived(string result) #region IAP -#if SINGULAR_SDK_IAP_ENABLED + private const string EVENT_NAME_IAP = "__iap__"; + +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + + public static void InAppPurchase(Order order) + { + InAppPurchase(order, EVENT_NAME_IAP, null, false); + } + + public static void InAppPurchase(Order order, Dictionary attributes) + { + InAppPurchase(order, EVENT_NAME_IAP, attributes, false); + } - public static void InAppPurchase(IEnumerable products, Dictionary attributes, bool isRestored - = false) { - InAppPurchase("__iap__", products, attributes, isRestored); + public static void InAppPurchase(Order order, bool isRestored) + { + InAppPurchase(order, EVENT_NAME_IAP, null, isRestored); + } + + public static void InAppPurchase(Order order, string eventName, Dictionary attributes) + { + InAppPurchase(order, eventName, attributes, false); + } + + public static void InAppPurchase(Order order, + string eventName, + Dictionary attributes, + bool isRestored) + { + if (order == null) + { + SingularUnityLogger.LogDebug("order is null, ignoring IAP event."); + return; + } + + foreach (var cartItem in order.CartOrdered.Items()) + { + Product product = cartItem.Product; + if (product != null) + { + InAppPurchase(eventName, + product, + order, + attributes, + isRestored); + } + } + } +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 + public static void InAppPurchase(IEnumerable products, Dictionary attributes, bool isRestored = false) { + InAppPurchase(EVENT_NAME_IAP, products, attributes, isRestored); } - public static void InAppPurchase(string eventName, IEnumerable products, Dictionary attributes, bool isRestored - = false) { + public static void InAppPurchase(string eventName, IEnumerable products, Dictionary attributes, bool isRestored = false) { foreach (var item in products) { InAppPurchase(eventName, item, attributes, isRestored); } } public static void InAppPurchase(Product product, Dictionary attributes, bool isRestored = false) { - InAppPurchase("__iap__", product, attributes, isRestored); + InAppPurchase(EVENT_NAME_IAP, product, attributes, isRestored); } - - public static void InAppPurchase(string eventName, Product product, Dictionary attributes, bool isRestored - = false) { +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 + +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 || SINGULAR_SDK_IAP_ENABLED__IAP_5 + public static void InAppPurchase(string eventName, + Product product, +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + Order order, +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + Dictionary attributes, + bool isRestored = false) + { if (Application.isEditor) { + SingularUnityLogger.LogDebug("running in editor, ignoring IAP event."); return; } - + if (product == null) { + SingularUnityLogger.LogDebug("product is null, ignoring IAP event."); return; } - + +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + if (order == null) { + SingularUnityLogger.LogDebug("order is null, ignoring IAP event."); + return; + } +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + + if (String.IsNullOrEmpty(eventName)) + { + eventName = EVENT_NAME_IAP; + } + double revenue = (double)product.metadata.localizedPrice; // Restored transactions are not counted as revenue. This is to be consistent with the iOS SDK @@ -1220,22 +1291,44 @@ public static void InAppPurchase(string eventName, Product product, Dictionary purchaseData = null; #if UNITY_IOS - purchaseData = BuildIOSPurchaseAttributes(product, attributes, isRestored); + purchaseData = BuildIOSPurchaseAttributes(product, attributes, isRestored +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + , order +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + ); + #elif UNITY_ANDROID - purchaseData = BuildAndroidPurchaseAttributes(product, attributes, isRestored); + purchaseData = BuildAndroidPurchaseAttributes(product, attributes, isRestored +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + , order +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + ); #endif Event(purchaseData, eventName); } } #if UNITY_IOS - private static Dictionary BuildIOSPurchaseAttributes(Product product, Dictionary attributes, bool isRestored) { - + private static Dictionary BuildIOSPurchaseAttributes(Product product, Dictionary attributes, bool isRestored +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + , Order order +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + ) { var transactionData = new Dictionary(); if (product.definition != null) { @@ -1245,7 +1338,7 @@ private static Dictionary BuildIOSPurchaseAttributes(Product pro if (product.definition.payout != null) { transactionData["pq"] = product.definition.payout.quantity; } -#endif +#endif // UNITY_2017_2_OR_NEWER } if (product.metadata != null) { @@ -1258,11 +1351,16 @@ private static Dictionary BuildIOSPurchaseAttributes(Product pro transactionData["pt"] = @"o"; transactionData["pc"] = @""; transactionData["ptc"] = isRestored; +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 transactionData["pti"] = product.transactionID; transactionData["ptr"] = ExtractIOSTransactionReceipt(product.receipt); +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + transactionData["pti"] = order.Info.TransactionID; + transactionData["ptr"] = ExtractIOSTransactionReceipt(order.Info.Receipt); +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 transactionData["is_revenue_event"] = true; - - + // Restored transactions are not counted as revenue if (isRestored) { transactionData["original_price"] = transactionData["pp"]; @@ -1285,30 +1383,48 @@ private static string ExtractIOSTransactionReceipt(string receipt) { Dictionary values = JsonConvert.DeserializeObject>(receipt); - if (!values.ContainsKey("Payload")) { + const string payloadParamKey = "Payload"; + + if (!values.ContainsKey(payloadParamKey)) { return null; } - return values["Payload"]; + return values[payloadParamKey]; } -#endif +#endif // UNITY_IOS #if UNITY_ANDROID - private static Dictionary BuildAndroidPurchaseAttributes(Product product, Dictionary attributes, bool isRestored) { + private static Dictionary BuildAndroidPurchaseAttributes(Product product, Dictionary attributes, bool isRestored +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + , Order order +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + ) { var transactionData = new Dictionary(); +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 if (product.receipt == null) { return attributes; } - +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + if (order.Info.Receipt == null) { + return attributes; + } +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 + if (attributes != null) { foreach (var item in attributes) { transactionData[item.Key] = item.Value; } } - var values = JsonConvert.DeserializeObject>(product.receipt); +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 + var values = JsonConvert.DeserializeObject>(product.receipt); +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + var values = JsonConvert.DeserializeObject>(order.Info.Receipt); +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 if (values.ContainsKey("signature")) { transactionData["receipt_signature"] = values["signature"]; @@ -1320,7 +1436,14 @@ private static Dictionary BuildAndroidPurchaseAttributes(Product // this string manipulation is done in order to deal with problematic descaping on server and validating receipts. // for more information: https://singularlabs.atlassian.net/browse/SDKDEV-88 - string receipt = Regex.Replace(product.receipt, @"\\+n", ""); + + +#if SINGULAR_SDK_IAP_ENABLED__IAP_4 + string receipt = Regex.Replace(product.receipt, @"\\+n", ""); +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 +#if SINGULAR_SDK_IAP_ENABLED__IAP_5 + string receipt = Regex.Replace(order.Info.Receipt, @"\\+n", ""); +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_5 transactionData["receipt"] = receipt; transactionData["is_revenue_event"] = true; @@ -1331,10 +1454,10 @@ private static Dictionary BuildAndroidPurchaseAttributes(Product return transactionData; } -#endif - - #endif // SINGULAR_SDK_IAP_ENABLED +#endif // UNITY_ANDROID +#endif // SINGULAR_SDK_IAP_ENABLED__IAP_4 || SINGULAR_SDK_IAP_ENABLED__IAP_5 + #endregion // end region IAP #region Revenue @@ -1453,7 +1576,8 @@ public static void Revenue(string currency, double amount, Dictionary