diff --git a/Editor/QonversionDependencies.xml b/Editor/QonversionDependencies.xml index 8a11b2a..d41b48b 100644 --- a/Editor/QonversionDependencies.xml +++ b/Editor/QonversionDependencies.xml @@ -1,11 +1,11 @@ - + - + diff --git a/Runtime/Android/Plugins/com/qonversion/unitywrapper/QonversionWrapper.java b/Runtime/Android/Plugins/com/qonversion/unitywrapper/QonversionWrapper.java index 99e7abf..4d2e6b8 100644 --- a/Runtime/Android/Plugins/com/qonversion/unitywrapper/QonversionWrapper.java +++ b/Runtime/Android/Plugins/com/qonversion/unitywrapper/QonversionWrapper.java @@ -17,7 +17,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import io.qonversion.sandwich.PurchaseResultListener; import io.qonversion.sandwich.QonversionSandwich; import io.qonversion.sandwich.ResultListener; import io.qonversion.sandwich.SandwichError; @@ -117,7 +116,7 @@ public static synchronized void checkEntitlements(String unityCallbackName) { } public static synchronized void purchase(String productId, @Nullable String offerId, boolean applyOffer, String unityCallbackName) { - qonversionSandwich.purchase(productId, offerId, applyOffer, getPurchaseResultListener(unityCallbackName)); + qonversionSandwich.purchase(productId, offerId, applyOffer, getResultListener(unityCallbackName)); } public static synchronized void updatePurchase( @@ -128,7 +127,7 @@ public static synchronized void updatePurchase( @Nullable String updatePolicyKey, String unityCallbackName ) { - qonversionSandwich.updatePurchase(productId, offerId, applyOffer, oldProductId, updatePolicyKey, getPurchaseResultListener(unityCallbackName)); + qonversionSandwich.updatePurchase(productId, offerId, applyOffer, oldProductId, updatePolicyKey, getResultListener(unityCallbackName)); } public static synchronized void restore(String unityCallbackName) { @@ -180,6 +179,10 @@ public static synchronized void detachUserFromRemoteConfiguration(String remoteC qonversionSandwich.detachUserFromRemoteConfiguration(remoteConfigurationId, getResultListener(unityCallbackName)); } + public static synchronized void isFallbackFileAccessible(String unityCallbackName) { + qonversionSandwich.isFallbackFileAccessible(getResultListener(unityCallbackName)); + } + public static synchronized void checkTrialIntroEligibility(String productIds, String unityCallbackName) { try { ObjectMapper mapper = new ObjectMapper(); @@ -206,24 +209,6 @@ public void onError(@NonNull SandwichError error) { }; } - private static PurchaseResultListener getPurchaseResultListener(@NotNull String methodName) { - return new PurchaseResultListener() { - @Override - public void onSuccess(@NonNull Map data) { - sendMessageToUnity(data, methodName); - } - - @Override - public void onError(@NonNull SandwichError error, boolean isCancelled) { - final ObjectMapper mapper = new ObjectMapper(); - final ObjectNode rootNode = Utils.createErrorNode(error); - final JsonNode isCancelledNode = mapper.convertValue(isCancelled, JsonNode.class); - rootNode.set("isCancelled", isCancelledNode); - sendMessageToUnity(rootNode, methodName); - } - }; - } - private static ResultListener getRemoteConfigResultListener(@Nullable String contextKey, @NotNull String methodName) { return new ResultListener() { @Override diff --git a/Runtime/Android/QonversionWrapperAndroid.cs b/Runtime/Android/QonversionWrapperAndroid.cs index 08c3172..fd6a51f 100644 --- a/Runtime/Android/QonversionWrapperAndroid.cs +++ b/Runtime/Android/QonversionWrapperAndroid.cs @@ -183,6 +183,11 @@ public void DetachUserFromRemoteConfiguration(string remoteConfigurationId, stri CallQonversion("detachUserFromRemoteConfiguration", remoteConfigurationId, callbackName); } + public void IsFallbackFileAccessible(string callbackName) + { + CallQonversion("isFallbackFileAccessible", callbackName); + } + public void CheckTrialIntroEligibility(string productIdsJson, string callbackName) { CallQonversion("checkTrialIntroEligibility", productIdsJson, callbackName); diff --git a/Runtime/Scripts/Dto/Eligibility.cs b/Runtime/Scripts/Dto/Eligibility.cs index b7da7f0..ba99b30 100644 --- a/Runtime/Scripts/Dto/Eligibility.cs +++ b/Runtime/Scripts/Dto/Eligibility.cs @@ -23,7 +23,7 @@ private EligibilityStatus FormatEligibilityStatus(object status) switch (value) { case "non_intro_or_trial_product": - result = EligibilityStatus.NonIntroProduct; + result = EligibilityStatus.NonIntroOrTrialProduct; break; case "intro_or_trial_ineligible": result = EligibilityStatus.Ineligible; diff --git a/Runtime/Scripts/Dto/EligibilityStatus.cs b/Runtime/Scripts/Dto/EligibilityStatus.cs index c3815fa..496ac51 100644 --- a/Runtime/Scripts/Dto/EligibilityStatus.cs +++ b/Runtime/Scripts/Dto/EligibilityStatus.cs @@ -3,7 +3,7 @@ public enum EligibilityStatus { Unknown, - NonIntroProduct, + NonIntroOrTrialProduct, Ineligible, Eligible } diff --git a/Runtime/Scripts/Dto/ProductStoreDetails/ProductInstallmentPlanDetails.cs b/Runtime/Scripts/Dto/ProductStoreDetails/ProductInstallmentPlanDetails.cs new file mode 100644 index 0000000..0432345 --- /dev/null +++ b/Runtime/Scripts/Dto/ProductStoreDetails/ProductInstallmentPlanDetails.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace QonversionUnity +{ + /// + /// This class represents the details about the installment plan for a subscription product. + /// + public class ProductInstallmentPlanDetails + { + /// Committed payments count after a user signs up for this subscription plan. + public readonly int CommitmentPaymentsCount; + + /// Subsequent committed payments count after this subscription plan renews. + /// + /// Returns 0 if the installment plan doesn't have any subsequent commitment, + /// which means this subscription plan will fall back to a normal + /// non-installment monthly plan when the plan renews. + public readonly int SubsequentCommitmentPaymentsCount; + + public ProductInstallmentPlanDetails(Dictionary dict) + { + if (dict.TryGetValue("commitmentPaymentsCount", out object value)) CommitmentPaymentsCount = (int)(long)value; + if (dict.TryGetValue("subsequentCommitmentPaymentsCount", out value)) SubsequentCommitmentPaymentsCount = (int)(long)value; + } + + public override string ToString() + { + return $"{nameof(CommitmentPaymentsCount)}: {CommitmentPaymentsCount}, " + + $"{nameof(SubsequentCommitmentPaymentsCount)}: {SubsequentCommitmentPaymentsCount}"; + } + } +} \ No newline at end of file diff --git a/Runtime/Scripts/Dto/ProductStoreDetails/ProductInstallmentPlanDetails.cs.meta b/Runtime/Scripts/Dto/ProductStoreDetails/ProductInstallmentPlanDetails.cs.meta new file mode 100644 index 0000000..c3fdfbb --- /dev/null +++ b/Runtime/Scripts/Dto/ProductStoreDetails/ProductInstallmentPlanDetails.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e15d639930374a54829f77585619d381 +timeCreated: 1719504789 \ No newline at end of file diff --git a/Runtime/Scripts/Dto/ProductStoreDetails/ProductOfferDetails.cs b/Runtime/Scripts/Dto/ProductStoreDetails/ProductOfferDetails.cs index c698568..a0f1f6c 100644 --- a/Runtime/Scripts/Dto/ProductStoreDetails/ProductOfferDetails.cs +++ b/Runtime/Scripts/Dto/ProductStoreDetails/ProductOfferDetails.cs @@ -29,6 +29,9 @@ public class ProductOfferDetails /// A base plan phase details. [CanBeNull] public readonly ProductPricingPhase BasePlan; + /// Additional details of an installment plan, if exists. + [CanBeNull] public readonly ProductInstallmentPlanDetails InstallmentPlanDetails; + /// A trial phase details, if exists. [CanBeNull] public readonly ProductPricingPhase IntroPhase; @@ -81,6 +84,11 @@ public ProductOfferDetails(Dictionary dict) { BasePlan = new ProductPricingPhase(basePlan); } + + if (dict.TryGetValue("installmentPlanDetails", out value) && value is Dictionary installmentPlan) + { + InstallmentPlanDetails = new ProductInstallmentPlanDetails(installmentPlan); + } if (dict.TryGetValue("introPhase", out value) && value is Dictionary introPhase) { @@ -117,6 +125,7 @@ public override string ToString() $"{nameof(Tags)}: {tags}, " + $"{nameof(PricingPhases)}: {pricingPhases}, " + $"{nameof(BasePlan)}: {BasePlan}, " + + $"{nameof(InstallmentPlanDetails)}: {InstallmentPlanDetails}, " + $"{nameof(IntroPhase)}: {IntroPhase}, " + $"{nameof(TrialPhase)}: {TrialPhase}, " + $"{nameof(HasTrial)}: {HasTrial}, " + diff --git a/Runtime/Scripts/Dto/ProductStoreDetails/ProductStoreDetails.cs b/Runtime/Scripts/Dto/ProductStoreDetails/ProductStoreDetails.cs index 0f346c6..49edbeb 100644 --- a/Runtime/Scripts/Dto/ProductStoreDetails/ProductStoreDetails.cs +++ b/Runtime/Scripts/Dto/ProductStoreDetails/ProductStoreDetails.cs @@ -74,6 +74,10 @@ public class ProductStoreDetails /// they will need to make a new payment to extend their plan. public readonly bool IsPrepaid; + /// True, if the subscription product is installment, which means that users commit + /// to pay for a specified amount of periods every month. + public readonly bool IsInstallment; + public ProductStoreDetails(Dictionary dict) { if (dict.TryGetValue("productId", out object value)) ProductId = value as string; @@ -119,6 +123,7 @@ public ProductStoreDetails(Dictionary dict) if (dict.TryGetValue("isInApp", out value)) IsInApp = (bool)value; if (dict.TryGetValue("isSubscription", out value)) IsSubscription = (bool)value; if (dict.TryGetValue("isPrepaid", out value)) IsPrepaid = (bool)value; + if (dict.TryGetValue("isInstallment", out value)) IsInstallment = (bool)value; } public override string ToString() @@ -144,7 +149,8 @@ public override string ToString() $"{nameof(ProductType)}: {ProductType}, " + $"{nameof(IsInApp)}: {IsInApp}, " + $"{nameof(IsSubscription)}: {IsSubscription}, " + - $"{nameof(IsPrepaid)}: {IsPrepaid}"; + $"{nameof(IsPrepaid)}: {IsPrepaid}" + + $"{nameof(IsInstallment)}: {IsInstallment}"; } } } \ No newline at end of file diff --git a/Runtime/Scripts/Dto/QonversionError.cs b/Runtime/Scripts/Dto/QonversionError.cs index 98b6e99..93047b9 100644 --- a/Runtime/Scripts/Dto/QonversionError.cs +++ b/Runtime/Scripts/Dto/QonversionError.cs @@ -1,15 +1,16 @@ +using System; using System.Collections.Generic; namespace QonversionUnity { public class QonversionError { - public string Code; + public QErrorCode Code; public string Message; public QonversionError(Dictionary dict) { - if (dict.TryGetValue("code", out object value)) Code = value as string; + if (dict.TryGetValue("code", out object value)) Code = FormatErrorCode(value); string message = ""; if (dict.TryGetValue("description", out object description)) { @@ -27,7 +28,7 @@ public QonversionError(Dictionary dict) Message = message; } - internal QonversionError(string code, string message) + internal QonversionError(QErrorCode code, string message) { Code = code; Message = message; @@ -38,5 +39,54 @@ public override string ToString() return $"{nameof(Code)}: {Code}, " + $"{nameof(Message)}: {Message}"; } + + private QErrorCode FormatErrorCode(object code) + { + return Enum.TryParse(code.ToString(), out QErrorCode parsedSource) + ? parsedSource + : QErrorCode.Unknown; + } + } + + public enum QErrorCode + { + Unknown, // Unknown error + ApiRateLimitExceeded, // API requests rate limit exceeded + AppleStoreError, // Apple Store error received + BackendError, // There was a backend error + BillingUnavailable, // The Billing service is unavailable on the device + ClientInvalid, // Client is not allowed to issue the request, etc + CloudServiceNetworkConnectionFailed, // The device could not connect to the network + CloudServicePermissionDenied, // User is not allowed to access cloud service information + CloudServiceRevoked, // User has revoked permission to use this cloud service + FailedToReceiveData, // Could not receive data + FeatureNotSupported, // The requested feature is not supported + FraudPurchase, // Fraud purchase was detected + IncorrectRequest, // Request failed + InternalError, // Internal backend error + InvalidClientUid, // Client Uid is invalid or not set + 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 + 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. + PaymentNotAllowed, // This device is not allowed to make the payment + PlayStoreError, // There was an issue with the Play Store service + PrivacyAcknowledgementRequired, // User needs to acknowledge Apple's privacy policy + ProductAlreadyOwned, // Failed to purchase since item is already owned + ProductNotFound, // Failed to purchase since the Qonversion product was not found + ProductNotOwned, // Failed to consume purchase since item is not owned + ProjectConfigError, // The project is not configured or configured incorrectly in the Qonversion Dashboard + PurchaseCanceled, // User pressed back or canceled a dialog for purchase + PurchaseInvalid, // Failure of purchase + PurchasePending, // Purchase is pending + PurchaseUnspecified, // Unspecified state of the purchase + ReceiptValidationError, // Receipt validation error + RemoteConfigurationNotAvailable, // Remote configuration is not available for the current user or for the provided context key + ResponseParsingFailed, // A problem occurred while serializing or deserializing data + StoreProductNotAvailable, // Requested product is not available for purchase or its product id was not found + UnauthorizedRequestData, // App is attempting to use SKPayment's requestData property, but does not have the appropriate entitlement + UnknownClientPlatform, // The current platform is not supported } } \ No newline at end of file diff --git a/Runtime/Scripts/IQonversion.cs b/Runtime/Scripts/IQonversion.cs index 5856c99..6f4362c 100644 --- a/Runtime/Scripts/IQonversion.cs +++ b/Runtime/Scripts/IQonversion.cs @@ -137,6 +137,12 @@ public interface IQonversion /// Callback that will be called when response is received. public void DetachUserFromRemoteConfiguration(string remoteConfigurationId, Qonversion.OnAttachUserResponseReceived callback); + /// + /// Call this function to check if the fallback file is accessible. + /// + /// Callback that will be called when response is received. + public void IsFallbackFileAccessible(Qonversion.OnFallbackFileAccessibilityResponseReceived callback); + /// /// You can check if a user is eligible for an introductory offer, including a free trial. /// You can show only a regular price for users who are not eligible for an introductory offer. diff --git a/Runtime/Scripts/Internal/Mapper.cs b/Runtime/Scripts/Internal/Mapper.cs index 8441a8e..393ac90 100644 --- a/Runtime/Scripts/Internal/Mapper.cs +++ b/Runtime/Scripts/Internal/Mapper.cs @@ -7,17 +7,6 @@ namespace QonversionUnity { internal class Mapper { - internal static bool GetIsCancelledFromJson(string jsonStr) - { - if (!(Json.Deserialize(jsonStr) is Dictionary result)) - { - Debug.LogError("Could not parse purchase result"); - return false; - } - - return result.TryGetValue("isCancelled", out var isCancelled) && Convert.ToBoolean(isCancelled); - } - internal static Dictionary EntitlementsFromJson(string jsonStr) { var result = new Dictionary(); @@ -117,6 +106,19 @@ internal static string ScreenIdFromJson(string jsonStr) return screenResult.GetString("screenId", ""); } + internal static bool IsFallbackFileAccessibleFromJson(string jsonStr) + { + var isAccessible = false; + if (!(Json.Deserialize(jsonStr) is Dictionary rawResult)) + { + Debug.LogError("Could not parse fallback file accessibility"); + return false; + } + if (rawResult.TryGetValue("success", out object value)) isAccessible = (bool)value; + + return isAccessible; + } + internal static Dictionary EligibilitiesFromJson(string jsonStr) { var result = new Dictionary(); diff --git a/Runtime/Scripts/Internal/QonversionInternal.cs b/Runtime/Scripts/Internal/QonversionInternal.cs index 7188ea5..91b5a48 100644 --- a/Runtime/Scripts/Internal/QonversionInternal.cs +++ b/Runtime/Scripts/Internal/QonversionInternal.cs @@ -25,8 +25,9 @@ internal class QonversionInternal : MonoBehaviour, IQonversion private const string OnUserPropertiesMethodName = "OnUserProperties"; private const string OnAttachUserMethodName = "OnAttachUser"; private const string OnDetachUserMethodName = "OnDetachUser"; + private const string OnIsFallbackFileAccessibleMethodName = "OnIsFallbackFileAccessible"; - private const string SdkVersion = "7.5.0"; + private const string SdkVersion = "8.0.0"; private const string SdkSource = "unity"; private const string DefaultRemoteConfigContextKey = ""; @@ -53,6 +54,7 @@ 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; } public event Qonversion.OnPromoPurchasesReceived PromoPurchasesReceived { @@ -205,6 +207,13 @@ public void DetachUserFromRemoteConfiguration(string remoteConfigurationId, Qonv instance.DetachUserFromRemoteConfiguration(remoteConfigurationId, OnDetachUserMethodName); } + public void IsFallbackFileAccessible(Qonversion.OnFallbackFileAccessibilityResponseReceived callback) + { + FallbackFileCallback = callback; + IQonversionWrapper instance = GetNativeWrapper(); + instance.IsFallbackFileAccessible(OnIsFallbackFileAccessibleMethodName); + } + public void CheckTrialIntroEligibility(IList productIds, Qonversion.OnEligibilitiesReceived callback) { var productIdsJson = Json.Serialize(productIds); @@ -494,6 +503,15 @@ private void OnDetachUser(string jsonString) } } + private void OnIsFallbackFileAccessible(string jsonString) + { + if (FallbackFileCallback == null) return; + + var isAccessible = Mapper.IsFallbackFileAccessibleFromJson(jsonString); + + FallbackFileCallback(isAccessible); + } + // Called from the native SDK - Called when eligibilities received from the checkTrialIntroEligibilityForProductIds() method private void OnEligibilities(string jsonString) { @@ -623,7 +641,7 @@ private void HandlePurchaseResult(Qonversion.OnPurchaseResultReceived callback, var error = Mapper.ErrorFromJson(jsonString); if (error != null) { - var isCancelled = Mapper.GetIsCancelledFromJson(jsonString); + var isCancelled = error.Code == QErrorCode.PurchaseCanceled; callback(null, error, isCancelled); } else diff --git a/Runtime/Scripts/Internal/wrappers/qonversion/IQonversionWrapper.cs b/Runtime/Scripts/Internal/wrappers/qonversion/IQonversionWrapper.cs index 861c654..17008ab 100644 --- a/Runtime/Scripts/Internal/wrappers/qonversion/IQonversionWrapper.cs +++ b/Runtime/Scripts/Internal/wrappers/qonversion/IQonversionWrapper.cs @@ -29,6 +29,7 @@ internal interface IQonversionWrapper void DetachUserFromExperiment(string experimentId, string callbackName); void AttachUserToRemoteConfiguration(string remoteConfigurationId, string callbackName); void DetachUserFromRemoteConfiguration(string remoteConfigurationId, string callbackName); + void IsFallbackFileAccessible(string callbackName); void CheckTrialIntroEligibility(string productIdsJson, string callbackName); void SetAppleSearchAdsAttributionEnabled(bool enable); void Identify(string userID, string callbackName); diff --git a/Runtime/Scripts/Internal/wrappers/qonversion/QonversionWrapperNoop.cs b/Runtime/Scripts/Internal/wrappers/qonversion/QonversionWrapperNoop.cs index 90e8fb6..1cf461c 100644 --- a/Runtime/Scripts/Internal/wrappers/qonversion/QonversionWrapperNoop.cs +++ b/Runtime/Scripts/Internal/wrappers/qonversion/QonversionWrapperNoop.cs @@ -95,6 +95,10 @@ public void DetachUserFromRemoteConfiguration(string remoteConfigurationId, stri { } + public void IsFallbackFileAccessible(string callbackName) + { + } + public void StoreSdkInfo(string version, string source) { } diff --git a/Runtime/Scripts/Qonversion.cs b/Runtime/Scripts/Qonversion.cs index f245c40..554992a 100644 --- a/Runtime/Scripts/Qonversion.cs +++ b/Runtime/Scripts/Qonversion.cs @@ -66,6 +66,7 @@ public static IQonversion Initialize(QonversionConfig config) public delegate void OnAttachUserResponseReceived(bool success, QonversionError error); public delegate void OnEligibilitiesReceived(Dictionary eligibilities, QonversionError error); public delegate void OnUserInfoReceived(User userInfo, QonversionError error); + public delegate void OnFallbackFileAccessibilityResponseReceived(bool success); /// /// Delegate fires each time a promo purchase from the App Store happens. diff --git a/Runtime/iOS/Plugins/Common/UtilityBridge.m b/Runtime/iOS/Plugins/Common/UtilityBridge.m index bc04293..633cfb6 100644 --- a/Runtime/iOS/Plugins/Common/UtilityBridge.m +++ b/Runtime/iOS/Plugins/Common/UtilityBridge.m @@ -37,7 +37,6 @@ + (NSDictionary *)convertError:(SandwichError *)error { NSMutableDictionary *result = [NSMutableDictionary new]; result[@"error"] = errorDict; - result[@"isCancelled"] = error.additionalInfo[@"isCancelled"]; return [result copy]; } diff --git a/Runtime/iOS/Plugins/QonversionBridge.m b/Runtime/iOS/Plugins/QonversionBridge.m index 93c83ce..84ebb84 100644 --- a/Runtime/iOS/Plugins/QonversionBridge.m +++ b/Runtime/iOS/Plugins/QonversionBridge.m @@ -232,6 +232,14 @@ void _detachUserFromRemoteConfiguration(const char* remoteConfigurationId, const }]; } +void _isFallbackFileAccessible(const char* unityCallbackName) { + NSString *callbackName = [UtilityBridge convertCStringToNSString:unityCallbackName]; + + [qonversionSandwich isFallbackFileAccessibleWithCompletion:^(NSDictionary * _Nullable result, SandwichError * _Nullable error) { + [UtilityBridge handleResult:result error:error callbackName:callbackName unityListener:unityListenerName]; + }]; +} + void _checkTrialIntroEligibility(const char* productIdsJson, const char* unityCallbackName) { NSString *callbackName = [UtilityBridge convertCStringToNSString:unityCallbackName]; NSString *productIdsJsonStr = [UtilityBridge convertCStringToNSString:productIdsJson]; diff --git a/Runtime/iOS/QonversionWrapperIOS.cs b/Runtime/iOS/QonversionWrapperIOS.cs index b17a40b..cc56b04 100644 --- a/Runtime/iOS/QonversionWrapperIOS.cs +++ b/Runtime/iOS/QonversionWrapperIOS.cs @@ -3,13 +3,16 @@ #endif using System; -using System.Collections.Generic; +using UnityEngine; +using System.IO; namespace QonversionUnity { internal class QonversionWrapperIOS : IQonversionWrapper { #if UNITY_IOS + private const string FallbackFileName = "qonversion_ios_fallbacks.json"; + [DllImport("__Internal")] private static extern void _initialize(string gameObjectName); @@ -88,6 +91,9 @@ internal class QonversionWrapperIOS : IQonversionWrapper [DllImport("__Internal")] private static extern void _detachUserFromRemoteConfiguration(string remoteConfigurationId, string callbackName); + [DllImport("__Internal")] + private static extern void _isFallbackFileAccessible(string callbackName); + [DllImport("__Internal")] private static extern void _checkTrialIntroEligibility(string productIdsJson, string callbackName); @@ -101,6 +107,21 @@ internal class QonversionWrapperIOS : IQonversionWrapper public void Initialize(string gameObjectName) { #if UNITY_IOS + try + { + string filePath = Path.Combine(Application.streamingAssetsPath, FallbackFileName); + + if (File.Exists(filePath)) + { + string result = System.IO.File.ReadAllText(filePath); + File.WriteAllText(Application.persistentDataPath + "/" + FallbackFileName, result); + } + } + catch (Exception e) + { + Debug.LogWarning("Fallback file is not accessible. " + e); + } + _initialize(gameObjectName); #endif } @@ -124,14 +145,14 @@ public void SyncHistoricalData() { #if UNITY_IOS _syncHistoricalData(); -#endif +#endif } public void SyncStoreKit2Purchases() { #if UNITY_IOS _syncStoreKit2Purchases(); -#endif +#endif } public void SyncPurchases() @@ -296,6 +317,13 @@ public void DetachUserFromRemoteConfiguration(string remoteConfigurationId, stri #endif } + public void IsFallbackFileAccessible(string callbackName) + { +#if UNITY_IOS + _isFallbackFileAccessible(callbackName); +#endif + } + public void CheckTrialIntroEligibility(string productIdsJson, string callbackName) { #if UNITY_IOS diff --git a/package.json b/package.json index 9335ea5..070810b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.qonversion.unity", "displayName": "Qonversion", - "version": "7.5.0", + "version": "8.0.0", "unity": "2018.3", "description": "Empower your mobile app marketing and product decisions with precise subscription data.", "author": {