diff --git a/Assets/Adjust/Native/Editor/Dependencies.xml b/Assets/Adjust/Native/Editor/Dependencies.xml index e810465d..4a585d05 100644 --- a/Assets/Adjust/Native/Editor/Dependencies.xml +++ b/Assets/Adjust/Native/Editor/Dependencies.xml @@ -7,7 +7,7 @@ - + diff --git a/Assets/Adjust/Native/iOS/AdjustUnity.mm b/Assets/Adjust/Native/iOS/AdjustUnity.mm index aebcaac7..d11eb5df 100644 --- a/Assets/Adjust/Native/iOS/AdjustUnity.mm +++ b/Assets/Adjust/Native/iOS/AdjustUnity.mm @@ -346,16 +346,7 @@ void _AdjustSetPushToken(const char* pushToken) { void _AdjustProcessDeeplink(const char* deeplink) { if (deeplink != NULL) { NSString *strDeeplink = [NSString stringWithUTF8String:deeplink]; - NSURL *urlDeeplink; - if ([NSString instancesRespondToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) { - urlDeeplink = [NSURL URLWithString:[strDeeplink stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]; - } else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - urlDeeplink = [NSURL URLWithString:[strDeeplink stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - } -#pragma clang diagnostic pop - + NSURL *urlDeeplink = [NSURL URLWithString:strDeeplink]; ADJDeeplink *deeplink = [[ADJDeeplink alloc] initWithDeeplink:urlDeeplink]; [Adjust processDeeplink:deeplink]; } @@ -381,6 +372,13 @@ void _AdjustGetAttribution(AdjustDelegateAttributionGetter callback) { addValueOrEmpty(dictionary, @"costType", attribution.costType); addValueOrEmpty(dictionary, @"costAmount", attribution.costAmount); addValueOrEmpty(dictionary, @"costCurrency", attribution.costCurrency); + + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:attribution.jsonResponse + options:0 + error:nil]; + NSString *strJsonResponse = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + addValueOrEmpty(dictionary, @"jsonResponse", strJsonResponse); + NSData *dataAttribution = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil]; @@ -719,16 +717,7 @@ void _AdjustVerifyAppStorePurchase(const char* transactionId, void _AdjustProcessAndResolveDeeplink(const char* deeplink, AdjustDelegateResolvedDeeplinkCallback callback) { if (deeplink != NULL) { NSString *strDeeplink = [NSString stringWithUTF8String:deeplink]; - NSURL *urlDeeplink; - if ([NSString instancesRespondToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) { - urlDeeplink = [NSURL URLWithString:[strDeeplink stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]; - } else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - urlDeeplink = [NSURL URLWithString:[strDeeplink stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - } -#pragma clang diagnostic pop - + NSURL *urlDeeplink = [NSURL URLWithString:strDeeplink]; ADJDeeplink *deeplink = [[ADJDeeplink alloc] initWithDeeplink:urlDeeplink]; [Adjust processAndResolveDeeplink:deeplink withCompletionHandler:^(NSString * _Nullable resolvedLink) { // TODO: nil checks diff --git a/Assets/Adjust/Native/iOS/AdjustUnityDelegate.mm b/Assets/Adjust/Native/iOS/AdjustUnityDelegate.mm index 9ffe284a..4de69a0f 100644 --- a/Assets/Adjust/Native/iOS/AdjustUnityDelegate.mm +++ b/Assets/Adjust/Native/iOS/AdjustUnityDelegate.mm @@ -124,6 +124,14 @@ - (void)adjustAttributionChangedWannabe:(ADJAttribution *)attribution { forKey:@"costCurrency" toDictionary:dictionary]; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:attribution.jsonResponse + options:0 + error:nil]; + NSString *strJsonResponse = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + [self addValueOrEmpty:strJsonResponse + forKey:@"jsonResponse" + toDictionary:dictionary]; + NSData *dataAttribution = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil]; diff --git a/Assets/Adjust/Scripts/AdjustAndroid.cs b/Assets/Adjust/Scripts/AdjustAndroid.cs index 8653bea2..b4d6d6cf 100644 --- a/Assets/Adjust/Scripts/AdjustAndroid.cs +++ b/Assets/Adjust/Scripts/AdjustAndroid.cs @@ -8,7 +8,7 @@ namespace AdjustSdk #if UNITY_ANDROID public class AdjustAndroid { - private const string sdkPrefix = "unity5.0.7"; + private const string sdkPrefix = "unity5.1.0"; private static bool isDeferredDeeplinkOpeningEnabled = true; private static AndroidJavaClass ajcAdjust = new AndroidJavaClass("com.adjust.sdk.Adjust"); private static AndroidJavaObject ajoCurrentActivity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic("currentActivity"); @@ -721,7 +721,8 @@ private class AttributionChangedListener : AndroidJavaProxy { private Action callback; - public AttributionChangedListener(Action pCallback) : base("com.adjust.sdk.OnAttributionChangedListener") + public AttributionChangedListener(Action pCallback) + : base("com.adjust.sdk.OnAttributionChangedListener") { this.callback = pCallback; } @@ -735,47 +736,56 @@ public void onAttributionChanged(AndroidJavaObject ajoAttribution) return; } - if (ajoAttribution == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustAttribution adjustAttribution = new AdjustAttribution(); - string trackerName = ajoAttribution.Get(AdjustUtils.KeyTrackerName); - adjustAttribution.TrackerName = trackerName == "" ? null : trackerName; - string trackerToken = ajoAttribution.Get(AdjustUtils.KeyTrackerToken); - adjustAttribution.TrackerToken = trackerToken == "" ? null : trackerToken; - string network = ajoAttribution.Get(AdjustUtils.KeyNetwork); - adjustAttribution.Network = network == "" ? null : network; - string campaign = ajoAttribution.Get(AdjustUtils.KeyCampaign); - adjustAttribution.Campaign = campaign == "" ? null : campaign; - string adgroup = ajoAttribution.Get(AdjustUtils.KeyAdgroup); - adjustAttribution.Adgroup = adgroup == "" ? null : adgroup; - string creative = ajoAttribution.Get(AdjustUtils.KeyCreative); - adjustAttribution.Creative = creative == "" ? null : creative; - string clickLabel = ajoAttribution.Get(AdjustUtils.KeyClickLabel); - adjustAttribution.ClickLabel = clickLabel == "" ? null : clickLabel; - string costType = ajoAttribution.Get(AdjustUtils.KeyCostType); - adjustAttribution.CostType = costType == "" ? null : costType; - using (AndroidJavaObject ajoCostAmount = ajoAttribution.Get(AdjustUtils.KeyCostAmount)) - { - if (ajoCostAmount == null) + try { - adjustAttribution.CostAmount = null; + if (ajoAttribution == null) + { + if (callback != null) + { + callback.Invoke(null); + } + return; + } + + AdjustAttribution adjustAttribution = new AdjustAttribution + { + TrackerName = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyTrackerName)), + TrackerToken = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyTrackerToken)), + Network = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyNetwork)), + Campaign = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCampaign)), + Adgroup = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyAdgroup)), + Creative = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCreative)), + ClickLabel = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyClickLabel)), + CostType = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCostType)), + CostCurrency = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCostCurrency)), + FbInstallReferrer = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyFbInstallReferrer)) + }; + + using (AndroidJavaObject ajoCostAmount = ajoAttribution.Get(AdjustUtils.KeyCostAmount)) + { + adjustAttribution.CostAmount = ajoCostAmount != null ? ajoCostAmount.Call("doubleValue") : (double?)null; + } + + string jsonResponse = ajoAttribution.Get(AdjustUtils.KeyJsonResponse); + var jsonResponseNode = JSON.Parse(jsonResponse); + if (jsonResponseNode != null && jsonResponseNode.AsObject != null) + { + adjustAttribution.JsonResponse = new Dictionary(); + AdjustUtils.WriteJsonResponseDictionary(jsonResponseNode.AsObject, adjustAttribution.JsonResponse); + } + + if (callback != null) + { + callback.Invoke(adjustAttribution); + } } - else + catch (Exception) { - double costAmount = ajoCostAmount.Call("doubleValue"); - adjustAttribution.CostAmount = costAmount; + // JSON response reading failed. } - } - string costCurrency = ajoAttribution.Get(AdjustUtils.KeyCostCurrency); - adjustAttribution.CostCurrency = costCurrency == "" ? null : costCurrency; - string fbInstallReferrer = ajoAttribution.Get(AdjustUtils.KeyFbInstallReferrer); - adjustAttribution.FbInstallReferrer = fbInstallReferrer == "" ? null : fbInstallReferrer; - - this.callback(adjustAttribution); + }); } } @@ -783,7 +793,8 @@ private class DeferredDeeplinkListener : AndroidJavaProxy { private Action callback; - public DeferredDeeplinkListener(Action pCallback) : base("com.adjust.sdk.OnDeferredDeeplinkResponseListener") + public DeferredDeeplinkListener(Action pCallback) + : base("com.adjust.sdk.OnDeferredDeeplinkResponseListener") { this.callback = pCallback; } @@ -797,8 +808,15 @@ public bool launchReceivedDeeplink(AndroidJavaObject deeplink) return isDeferredDeeplinkOpeningEnabled; } - string strDeeplink = deeplink.Call("toString"); - callback(strDeeplink); + AdjustThreadDispatcher.RunOnMainThread(() => + { + string strDeeplink = deeplink != null ? deeplink.Call("toString") : null; + if (callback != null) + { + callback.Invoke(strDeeplink); + } + }); + return isDeferredDeeplinkOpeningEnabled; } } @@ -821,39 +839,40 @@ public void onEventTrackingSucceeded(AndroidJavaObject eventSuccessData) return; } - if (eventSuccessData == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustEventSuccess adjustEventSuccess = new AdjustEventSuccess(); - string adid = eventSuccessData.Get(AdjustUtils.KeyAdid); - adjustEventSuccess.Adid = adid == "" ? null : adid; - string message = eventSuccessData.Get(AdjustUtils.KeyMessage); - adjustEventSuccess.Message = message == "" ? null : message; - string timestamp = eventSuccessData.Get(AdjustUtils.KeyTimestamp); - adjustEventSuccess.Timestamp = timestamp == "" ? null : timestamp; - string eventToken = eventSuccessData.Get(AdjustUtils.KeyEventToken); - adjustEventSuccess.EventToken = eventToken == "" ? null : eventToken; - string callbackId = eventSuccessData.Get(AdjustUtils.KeyCallbackId); - adjustEventSuccess.CallbackId = callbackId == "" ? null : callbackId; - try - { - using (AndroidJavaObject ajoJsonResponse = eventSuccessData.Get(AdjustUtils.KeyJsonResponse)) + try { - string jsonResponseString = ajoJsonResponse.Call("toString"); - adjustEventSuccess.BuildJsonResponseFromString(jsonResponseString); + AdjustEventSuccess adjustEventSuccess = new AdjustEventSuccess + { + Adid = AdjustUtils.GetValueOrEmptyToNull(eventSuccessData.Get(AdjustUtils.KeyAdid)), + Message = AdjustUtils.GetValueOrEmptyToNull(eventSuccessData.Get(AdjustUtils.KeyMessage)), + Timestamp = AdjustUtils.GetValueOrEmptyToNull(eventSuccessData.Get(AdjustUtils.KeyTimestamp)), + EventToken = AdjustUtils.GetValueOrEmptyToNull(eventSuccessData.Get(AdjustUtils.KeyEventToken)), + CallbackId = AdjustUtils.GetValueOrEmptyToNull(eventSuccessData.Get(AdjustUtils.KeyCallbackId)) + }; + + using (AndroidJavaObject ajoJsonResponse = eventSuccessData.Get(AdjustUtils.KeyJsonResponse)) + { + if (ajoJsonResponse != null) + { + string jsonResponseString = ajoJsonResponse.Call("toString"); + adjustEventSuccess.BuildJsonResponseFromString(jsonResponseString); + } + } + + if (callback != null) + { + callback.Invoke(adjustEventSuccess); + } } - } - catch (Exception) - { - // JSON response reading failed. - // Native Android SDK should send empty JSON object if none available as of v4.12.5. - // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. - } - - this.callback(adjustEventSuccess); + catch (Exception) + { + // JSON response reading failed. + // Native Android SDK should send empty JSON object if none available as of v4.12.5. + // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. + } + }); } } @@ -875,40 +894,41 @@ public void onEventTrackingFailed(AndroidJavaObject eventFailureData) return; } - if (eventFailureData == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustEventFailure adjustEventFailure = new AdjustEventFailure(); - string adid = eventFailureData.Get(AdjustUtils.KeyAdid); - adjustEventFailure.Adid = adid == "" ? null : adid; - string message = eventFailureData.Get(AdjustUtils.KeyMessage); - adjustEventFailure.Message = message == "" ? null : message; - adjustEventFailure.WillRetry = eventFailureData.Get(AdjustUtils.KeyWillRetry); - string timestamp = eventFailureData.Get(AdjustUtils.KeyTimestamp); - adjustEventFailure.Timestamp = timestamp == "" ? null : timestamp; - string eventToken = eventFailureData.Get(AdjustUtils.KeyEventToken); - adjustEventFailure.EventToken = eventToken == "" ? null : eventToken; - string callbackId = eventFailureData.Get(AdjustUtils.KeyCallbackId); - adjustEventFailure.CallbackId = callbackId == "" ? null : callbackId; - try - { - using (AndroidJavaObject ajoJsonResponse = eventFailureData.Get(AdjustUtils.KeyJsonResponse)) + try { - string jsonResponseString = ajoJsonResponse.Call("toString"); - adjustEventFailure.BuildJsonResponseFromString(jsonResponseString); + AdjustEventFailure adjustEventFailure = new AdjustEventFailure + { + Adid = AdjustUtils.GetValueOrEmptyToNull(eventFailureData.Get(AdjustUtils.KeyAdid)), + Message = AdjustUtils.GetValueOrEmptyToNull(eventFailureData.Get(AdjustUtils.KeyMessage)), + Timestamp = AdjustUtils.GetValueOrEmptyToNull(eventFailureData.Get(AdjustUtils.KeyTimestamp)), + EventToken = AdjustUtils.GetValueOrEmptyToNull(eventFailureData.Get(AdjustUtils.KeyEventToken)), + CallbackId = AdjustUtils.GetValueOrEmptyToNull(eventFailureData.Get(AdjustUtils.KeyCallbackId)), + WillRetry = eventFailureData.Get(AdjustUtils.KeyWillRetry) + }; + + using (AndroidJavaObject ajoJsonResponse = eventFailureData.Get(AdjustUtils.KeyJsonResponse)) + { + if (ajoJsonResponse != null) + { + string jsonResponseString = ajoJsonResponse.Call("toString"); + adjustEventFailure.BuildJsonResponseFromString(jsonResponseString); + } + } + + if (callback != null) + { + callback.Invoke(adjustEventFailure); + } } - } - catch (Exception) - { - // JSON response reading failed. - // Native Android SDK should send empty JSON object if none available as of v4.12.5. - // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. - } - - this.callback(adjustEventFailure); + catch (Exception) + { + // JSON response reading failed. + // Native Android SDK should send empty JSON object if none available as of v4.12.5. + // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. + } + }); } } @@ -916,7 +936,8 @@ private class SessionTrackingSucceededListener : AndroidJavaProxy { private Action callback; - public SessionTrackingSucceededListener(Action pCallback) : base("com.adjust.sdk.OnSessionTrackingSucceededListener") + public SessionTrackingSucceededListener(Action pCallback) + : base("com.adjust.sdk.OnSessionTrackingSucceededListener") { this.callback = pCallback; } @@ -930,35 +951,38 @@ public void onSessionTrackingSucceeded(AndroidJavaObject sessionSuccessData) return; } - if (sessionSuccessData == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustSessionSuccess adjustSessionSuccess = new AdjustSessionSuccess(); - string adid = sessionSuccessData.Get(AdjustUtils.KeyAdid); - adjustSessionSuccess.Adid = adid == "" ? null : adid; - string message = sessionSuccessData.Get(AdjustUtils.KeyMessage); - adjustSessionSuccess.Message = message == "" ? null : message; - string timestamp = sessionSuccessData.Get(AdjustUtils.KeyTimestamp); - adjustSessionSuccess.Timestamp = timestamp == "" ? null : timestamp; - try - { - using (AndroidJavaObject ajoJsonResponse = sessionSuccessData.Get(AdjustUtils.KeyJsonResponse)) + try { - string jsonResponseString = ajoJsonResponse.Call("toString"); - adjustSessionSuccess.BuildJsonResponseFromString(jsonResponseString); + AdjustSessionSuccess adjustSessionSuccess = new AdjustSessionSuccess + { + Adid = AdjustUtils.GetValueOrEmptyToNull(sessionSuccessData.Get(AdjustUtils.KeyAdid)), + Message = AdjustUtils.GetValueOrEmptyToNull(sessionSuccessData.Get(AdjustUtils.KeyMessage)), + Timestamp = AdjustUtils.GetValueOrEmptyToNull(sessionSuccessData.Get(AdjustUtils.KeyTimestamp)) + }; + + using (AndroidJavaObject ajoJsonResponse = sessionSuccessData.Get(AdjustUtils.KeyJsonResponse)) + { + if (ajoJsonResponse != null) + { + string jsonResponseString = ajoJsonResponse.Call("toString"); + adjustSessionSuccess.BuildJsonResponseFromString(jsonResponseString); + } + } + + if (callback != null) + { + callback.Invoke(adjustSessionSuccess); + } } - } - catch (Exception) - { - // JSON response reading failed. - // Native Android SDK should send empty JSON object if none available as of v4.12.5. - // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. - } - - this.callback(adjustSessionSuccess); + catch (Exception) + { + // JSON response reading failed. + // Native Android SDK should send empty JSON object if none available as of v4.12.5. + // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. + } + }); } } @@ -966,7 +990,8 @@ private class SessionTrackingFailedListener : AndroidJavaProxy { private Action callback; - public SessionTrackingFailedListener(Action pCallback) : base("com.adjust.sdk.OnSessionTrackingFailedListener") + public SessionTrackingFailedListener(Action pCallback) + : base("com.adjust.sdk.OnSessionTrackingFailedListener") { this.callback = pCallback; } @@ -980,36 +1005,39 @@ public void onSessionTrackingFailed(AndroidJavaObject sessionFailureData) return; } - if (sessionFailureData == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustSessionFailure adjustSessionFailure = new AdjustSessionFailure(); - string adid = sessionFailureData.Get(AdjustUtils.KeyAdid); - adjustSessionFailure.Adid = adid == "" ? null : adid; - string message = sessionFailureData.Get(AdjustUtils.KeyMessage); - adjustSessionFailure.Message = message == "" ? null : message; - adjustSessionFailure.WillRetry = sessionFailureData.Get(AdjustUtils.KeyWillRetry); - string timestamp = sessionFailureData.Get(AdjustUtils.KeyTimestamp); - adjustSessionFailure.Timestamp = timestamp == "" ? null : timestamp; - try - { - using (AndroidJavaObject ajoJsonResponse = sessionFailureData.Get(AdjustUtils.KeyJsonResponse)) + try { - string jsonResponseString = ajoJsonResponse.Call("toString"); - adjustSessionFailure.BuildJsonResponseFromString(jsonResponseString); + AdjustSessionFailure adjustSessionFailure = new AdjustSessionFailure + { + Adid = AdjustUtils.GetValueOrEmptyToNull(sessionFailureData.Get(AdjustUtils.KeyAdid)), + Message = AdjustUtils.GetValueOrEmptyToNull(sessionFailureData.Get(AdjustUtils.KeyMessage)), + Timestamp = AdjustUtils.GetValueOrEmptyToNull(sessionFailureData.Get(AdjustUtils.KeyTimestamp)), + WillRetry = sessionFailureData.Get(AdjustUtils.KeyWillRetry) + }; + + using (AndroidJavaObject ajoJsonResponse = sessionFailureData.Get(AdjustUtils.KeyJsonResponse)) + { + if (ajoJsonResponse != null) + { + string jsonResponseString = ajoJsonResponse.Call("toString"); + adjustSessionFailure.BuildJsonResponseFromString(jsonResponseString); + } + } + + if (callback != null) + { + callback.Invoke(adjustSessionFailure); + } } - } - catch (Exception) - { - // JSON response reading failed. - // Native Android SDK should send empty JSON object if none available as of v4.12.5. - // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. - } - - this.callback(adjustSessionFailure); + catch (Exception) + { + // JSON response reading failed. + // Native Android SDK should send empty JSON object if none available as of v4.12.5. + // Native Android SDK added special logic to send Unity friendly values as of v4.15.0. + } + }); } } @@ -1017,7 +1045,8 @@ private class GoogleAdIdReadListener : AndroidJavaProxy { private Action callback; - public GoogleAdIdReadListener(Action pCallback) : base("com.adjust.sdk.OnGoogleAdIdReadListener") + public GoogleAdIdReadListener(Action pCallback) + : base("com.adjust.sdk.OnGoogleAdIdReadListener") { this.callback = pCallback; } @@ -1031,7 +1060,13 @@ public void onGoogleAdIdRead(string adid) return; } - this.callback(adid); + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (callback != null) + { + callback.Invoke(adid); + } + }); } } @@ -1039,7 +1074,8 @@ private class VerificationResultListener : AndroidJavaProxy { private Action callback; - public VerificationResultListener(Action pCallback) : base("com.adjust.sdk.OnPurchaseVerificationFinishedListener") + public VerificationResultListener(Action pCallback) + : base("com.adjust.sdk.OnPurchaseVerificationFinishedListener") { this.callback = pCallback; } @@ -1053,18 +1089,36 @@ public void onVerificationFinished(AndroidJavaObject ajoVerificationInfo) return; } - if (ajoVerificationInfo == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustPurchaseVerificationResult purchaseVerificationResult = new AdjustPurchaseVerificationResult(); - purchaseVerificationResult.VerificationStatus = ajoVerificationInfo.Get(AdjustUtils.KeyVerificationStatus); - purchaseVerificationResult.Code = ajoVerificationInfo.Get(AdjustUtils.KeyCode); - purchaseVerificationResult.Message = ajoVerificationInfo.Get(AdjustUtils.KeyMessage); - - this.callback(purchaseVerificationResult); + try + { + if (ajoVerificationInfo == null) + { + if (callback != null) + { + callback.Invoke(null); + } + return; + } + + AdjustPurchaseVerificationResult purchaseVerificationResult = new AdjustPurchaseVerificationResult + { + VerificationStatus = ajoVerificationInfo.Get(AdjustUtils.KeyVerificationStatus), + Code = ajoVerificationInfo.Get(AdjustUtils.KeyCode), + Message = AdjustUtils.GetValueOrEmptyToNull(ajoVerificationInfo.Get(AdjustUtils.KeyMessage)) + }; + + if (callback != null) + { + callback.Invoke(purchaseVerificationResult); + } + } + catch (Exception) + { + // Handle potential errors during the verification process + } + }); } } @@ -1072,7 +1126,8 @@ private class DeeplinkResolutionListener : AndroidJavaProxy { private Action callback; - public DeeplinkResolutionListener(Action pCallback) : base("com.adjust.sdk.OnDeeplinkResolvedListener") + public DeeplinkResolutionListener(Action pCallback) + : base("com.adjust.sdk.OnDeeplinkResolvedListener") { this.callback = pCallback; } @@ -1086,7 +1141,13 @@ public void onDeeplinkResolved(string resolvedLink) return; } - this.callback(resolvedLink); + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (callback != null) + { + callback.Invoke(resolvedLink); + } + }); } } @@ -1094,7 +1155,8 @@ private class AdidReadListener : AndroidJavaProxy { private Action callback; - public AdidReadListener(Action pCallback) : base("com.adjust.sdk.OnAdidReadListener") + public AdidReadListener(Action pCallback) + : base("com.adjust.sdk.OnAdidReadListener") { this.callback = pCallback; } @@ -1108,7 +1170,13 @@ public void onAdidRead(string adid) return; } - this.callback(adid); + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (callback != null) + { + callback.Invoke(adid); + } + }); } } @@ -1116,7 +1184,8 @@ private class AttributionReadListener : AndroidJavaProxy { private Action callback; - public AttributionReadListener(Action pCallback) : base("com.adjust.sdk.OnAttributionReadListener") + public AttributionReadListener(Action pCallback) + : base("com.adjust.sdk.OnAttributionReadListener") { this.callback = pCallback; } @@ -1130,47 +1199,56 @@ public void onAttributionRead(AndroidJavaObject ajoAttribution) return; } - if (ajoAttribution == null) + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(null); - return; - } - - AdjustAttribution adjustAttribution = new AdjustAttribution(); - string trackerName = ajoAttribution.Get(AdjustUtils.KeyTrackerName); - adjustAttribution.TrackerName = trackerName == "" ? null : trackerName; - string trackerToken = ajoAttribution.Get(AdjustUtils.KeyTrackerToken); - adjustAttribution.TrackerToken = trackerToken == "" ? null : trackerToken; - string network = ajoAttribution.Get(AdjustUtils.KeyNetwork); - adjustAttribution.Network = network == "" ? null : network; - string campaign = ajoAttribution.Get(AdjustUtils.KeyCampaign); - adjustAttribution.Campaign = campaign == "" ? null : campaign; - string adgroup = ajoAttribution.Get(AdjustUtils.KeyAdgroup); - adjustAttribution.Adgroup = adgroup == "" ? null : adgroup; - string creative = ajoAttribution.Get(AdjustUtils.KeyCreative); - adjustAttribution.Creative = creative == "" ? null : creative; - string clickLabel = ajoAttribution.Get(AdjustUtils.KeyClickLabel); - adjustAttribution.ClickLabel = clickLabel == "" ? null : clickLabel; - string costType = ajoAttribution.Get(AdjustUtils.KeyCostType); - adjustAttribution.CostType = costType == "" ? null : costType; - using (AndroidJavaObject ajoCostAmount = ajoAttribution.Get(AdjustUtils.KeyCostAmount)) - { - if (ajoCostAmount == null) + try { - adjustAttribution.CostAmount = null; + if (ajoAttribution == null) + { + if (callback != null) + { + callback.Invoke(null); + } + return; + } + + AdjustAttribution adjustAttribution = new AdjustAttribution + { + TrackerName = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyTrackerName)), + TrackerToken = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyTrackerToken)), + Network = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyNetwork)), + Campaign = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCampaign)), + Adgroup = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyAdgroup)), + Creative = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCreative)), + ClickLabel = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyClickLabel)), + CostType = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCostType)), + CostCurrency = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyCostCurrency)), + FbInstallReferrer = AdjustUtils.GetValueOrEmptyToNull(ajoAttribution.Get(AdjustUtils.KeyFbInstallReferrer)) + }; + + using (AndroidJavaObject ajoCostAmount = ajoAttribution.Get(AdjustUtils.KeyCostAmount)) + { + adjustAttribution.CostAmount = ajoCostAmount != null ? ajoCostAmount.Call("doubleValue") : (double?)null; + } + + string jsonResponse = ajoAttribution.Get(AdjustUtils.KeyJsonResponse); + var jsonResponseNode = JSON.Parse(jsonResponse); + if (jsonResponseNode != null && jsonResponseNode.AsObject != null) + { + adjustAttribution.JsonResponse = new Dictionary(); + AdjustUtils.WriteJsonResponseDictionary(jsonResponseNode.AsObject, adjustAttribution.JsonResponse); + } + + if (callback != null) + { + callback.Invoke(adjustAttribution); + } } - else + catch (Exception) { - double costAmount = ajoCostAmount.Call("doubleValue"); - adjustAttribution.CostAmount = costAmount; + // JSON response reading failed. } - } - string costCurrency = ajoAttribution.Get(AdjustUtils.KeyCostCurrency); - adjustAttribution.CostCurrency = costCurrency == "" ? null : costCurrency; - string fbInstallReferrer = ajoAttribution.Get(AdjustUtils.KeyFbInstallReferrer); - adjustAttribution.FbInstallReferrer = fbInstallReferrer == "" ? null : fbInstallReferrer; - - this.callback(adjustAttribution); + }); } } @@ -1178,7 +1256,8 @@ private class AmazonAdIdReadListener : AndroidJavaProxy { private Action callback; - public AmazonAdIdReadListener(Action pCallback) : base("com.adjust.sdk.OnAmazonAdIdReadListener") + public AmazonAdIdReadListener(Action pCallback) + : base("com.adjust.sdk.OnAmazonAdIdReadListener") { this.callback = pCallback; } @@ -1192,7 +1271,13 @@ public void onAmazonAdIdRead(string amazonAdId) return; } - this.callback(amazonAdId); + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (callback != null) + { + callback.Invoke(amazonAdId); + } + }); } } @@ -1201,7 +1286,8 @@ private class SdkVersionReadListener : AndroidJavaProxy private Action callback; private string sdkPrefix; - public SdkVersionReadListener(Action pCallback, string sdkPrefix) : base("com.adjust.sdk.OnSdkVersionReadListener") + public SdkVersionReadListener(Action pCallback, string sdkPrefix) + : base("com.adjust.sdk.OnSdkVersionReadListener") { this.callback = pCallback; this.sdkPrefix = sdkPrefix; @@ -1216,7 +1302,13 @@ public void onSdkVersionRead(string sdkVersion) return; } - this.callback(this.sdkPrefix + "@" + sdkVersion); + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (callback != null) + { + callback.Invoke(this.sdkPrefix + "@" + sdkVersion); + } + }); } } @@ -1224,7 +1316,8 @@ private class IsEnabledListener : AndroidJavaProxy { private Action callback; - public IsEnabledListener(Action pCallback) : base("com.adjust.sdk.OnIsEnabledListener") + public IsEnabledListener(Action pCallback) + : base("com.adjust.sdk.OnIsEnabledListener") { this.callback = pCallback; } @@ -1238,7 +1331,13 @@ public void onIsEnabledRead(bool isEnabled) return; } - this.callback(isEnabled); + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (callback != null) + { + callback.Invoke(isEnabled); + } + }); } } @@ -1246,7 +1345,8 @@ private class LastDeeplinkListener : AndroidJavaProxy { private Action callback; - public LastDeeplinkListener(Action pCallback) : base("com.adjust.sdk.OnLastDeeplinkReadListener") + public LastDeeplinkListener(Action pCallback) + : base("com.adjust.sdk.OnLastDeeplinkReadListener") { this.callback = pCallback; } @@ -1260,14 +1360,14 @@ public void onLastDeeplinkRead(AndroidJavaObject ajoLastDeeplink) return; } - if (ajoLastDeeplink == null) - { - this.callback(null); - } - else + AdjustThreadDispatcher.RunOnMainThread(() => { - this.callback(ajoLastDeeplink.Call("toString")); - } + string deeplink = ajoLastDeeplink != null ? ajoLastDeeplink.Call("toString") : null; + if (callback != null) + { + callback.Invoke(deeplink); + } + }); } } } diff --git a/Assets/Adjust/Scripts/AdjustAttribution.cs b/Assets/Adjust/Scripts/AdjustAttribution.cs index dad2d92f..261f2ad9 100644 --- a/Assets/Adjust/Scripts/AdjustAttribution.cs +++ b/Assets/Adjust/Scripts/AdjustAttribution.cs @@ -15,6 +15,7 @@ public class AdjustAttribution public string CostType { get; set; } public double? CostAmount { get; set; } public string CostCurrency { get; set; } + public Dictionary JsonResponse { get; set; } // Android only public string FbInstallReferrer { get; set; } @@ -49,6 +50,14 @@ public AdjustAttribution(string jsonString) } this.CostCurrency = AdjustUtils.GetJsonString(jsonNode, AdjustUtils.KeyCostCurrency); this.FbInstallReferrer = AdjustUtils.GetJsonString(jsonNode, AdjustUtils.KeyFbInstallReferrer); + + string jsonResponseString = AdjustUtils.GetJsonString(jsonNode, AdjustUtils.KeyJsonResponse); + var jsonResponseNode = JSON.Parse(jsonResponseString); + if (jsonResponseNode != null && jsonResponseNode.AsObject != null) + { + this.JsonResponse = new Dictionary(); + AdjustUtils.WriteJsonResponseDictionary(jsonResponseNode.AsObject, this.JsonResponse); + } } public AdjustAttribution(Dictionary dicAttributionData) diff --git a/Assets/Adjust/Scripts/AdjustThreadDispatcher.cs b/Assets/Adjust/Scripts/AdjustThreadDispatcher.cs new file mode 100644 index 00000000..26157f36 --- /dev/null +++ b/Assets/Adjust/Scripts/AdjustThreadDispatcher.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public class AdjustThreadDispatcher : MonoBehaviour +{ + private static readonly Queue executionQueue = new Queue(); + private static AdjustThreadDispatcher instance; + + public static void RunOnMainThread(Action action) + { + if (action == null) + { + return; + } + + lock (executionQueue) + { + executionQueue.Enqueue(action); + } + } + + private void Update() + { + while (executionQueue.Count > 0) + { + Action action; + lock (executionQueue) + { + action = executionQueue.Dequeue(); + } + if (action != null) + { + action.Invoke(); + } + } + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + private static void Initialize() + { + if (instance == null) + { + GameObject obj = new GameObject("AdjustThreadDispatcher"); + instance = obj.AddComponent(); + DontDestroyOnLoad(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Adjust/Scripts/AdjustThreadDispatcher.cs.meta b/Assets/Adjust/Scripts/AdjustThreadDispatcher.cs.meta new file mode 100644 index 00000000..fe68f179 --- /dev/null +++ b/Assets/Adjust/Scripts/AdjustThreadDispatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 068759bba95d0411895637c9165b2f99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Adjust/Scripts/AdjustUtils.cs b/Assets/Adjust/Scripts/AdjustUtils.cs index 0925de4a..6793be98 100644 --- a/Assets/Adjust/Scripts/AdjustUtils.cs +++ b/Assets/Adjust/Scripts/AdjustUtils.cs @@ -350,6 +350,11 @@ public static Dictionary GetSkanUpdateDataDictionary(string skan return skanUpdateDataDictionary; } + public static string GetValueOrEmptyToNull(string value) + { + return string.IsNullOrEmpty(value) ? null : value; + } + #if UNITY_ANDROID public static AndroidJavaObject TestOptionsMap2AndroidJavaObject(Dictionary testOptionsMap, AndroidJavaObject ajoCurrentActivity) { diff --git a/Assets/Adjust/Scripts/AdjustiOS.cs b/Assets/Adjust/Scripts/AdjustiOS.cs index 05065b9a..1b4c398c 100644 --- a/Assets/Adjust/Scripts/AdjustiOS.cs +++ b/Assets/Adjust/Scripts/AdjustiOS.cs @@ -8,7 +8,7 @@ namespace AdjustSdk #if UNITY_IOS public class AdjustiOS { - private const string sdkPrefix = "unity5.0.7"; + private const string sdkPrefix = "unity5.1.0"; // app callbacks as method parameters private static List> appIsEnabledGetterCallbacks; @@ -694,192 +694,345 @@ public static void TrackSubsessionEnd(string testingArgument = null) // MonoPInvokeCallback methods as method parameters [AOT.MonoPInvokeCallback(typeof(AdjustDelegateIsEnabledGetter))] - private static void IsEnabledGetterMonoPInvoke(bool isEnabled) { - if (appIsEnabledGetterCallbacks != null) + private static void IsEnabledGetterMonoPInvoke(bool isEnabled) + { + if (appIsEnabledGetterCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appIsEnabledGetterCallbacks) { - callback(isEnabled); + if (callback != null) + { + callback.Invoke(isEnabled); + } } appIsEnabledGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateAttributionGetter))] - private static void AttributionGetterMonoPInvoke(string attribution) { - if (appAttributionGetterCallbacks != null) + private static void AttributionGetterMonoPInvoke(string attribution) + { + if (appAttributionGetterCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appAttributionGetterCallbacks) { - callback(new AdjustAttribution(attribution)); + if (callback != null) + { + callback.Invoke(new AdjustAttribution(attribution)); + } } appAttributionGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateAdidGetter))] - private static void AdidGetterMonoPInvoke(string adid) { - if (appAdidGetterCallbacks != null) + private static void AdidGetterMonoPInvoke(string adid) + { + if (appAdidGetterCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appAdidGetterCallbacks) { - callback(adid); + if (callback != null) + { + callback.Invoke(adid); + } } appAdidGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateIdfaGetter))] - private static void IdfaGetterMonoPInvoke(string idfa) { - if (appIdfaGetterCallbacks != null) + private static void IdfaGetterMonoPInvoke(string idfa) + { + if (appIdfaGetterCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appIdfaGetterCallbacks) { - callback(idfa); + if (callback != null) + { + callback.Invoke(idfa); + } } appIdfaGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateIdfvGetter))] - private static void IdfvGetterMonoPInvoke(string idfv) { - if (appIdfvGetterCallbacks != null) + private static void IdfvGetterMonoPInvoke(string idfv) + { + if (appIdfvGetterCallbacks == null) { - foreach (Action callback in appIdfaGetterCallbacks) + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + foreach (Action callback in appIdfvGetterCallbacks) { - callback(idfv); + if (callback != null) + { + callback.Invoke(idfv); + } } appIdfvGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateLastDeeplinkGetter))] - private static void LastDeeplinkGetterMonoPInvoke(string lastDeeplink) { - if (appLastDeeplinkGetterCallbacks != null) + private static void LastDeeplinkGetterMonoPInvoke(string lastDeeplink) + { + if (appLastDeeplinkGetterCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appLastDeeplinkGetterCallbacks) { - callback(lastDeeplink); + if (callback != null) + { + callback.Invoke(lastDeeplink); + } } appLastDeeplinkGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateSdkVersionGetter))] - private static void SdkVersionGetterMonoPInvoke(string sdkVersion) { - if (appSdkVersionGetterCallbacks != null) + private static void SdkVersionGetterMonoPInvoke(string sdkVersion) + { + if (appSdkVersionGetterCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appSdkVersionGetterCallbacks) { - callback(sdkPrefix + "@" + sdkVersion); + if (callback != null) + { + callback.Invoke(sdkPrefix + "@" + sdkVersion); + } } appSdkVersionGetterCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateAttCallback))] - private static void AttCallbackMonoPInvoke(int status) { - if (appAttCallbacks != null) + private static void AttCallbackMonoPInvoke(int status) + { + if (appAttCallbacks == null) + { + return; + } + + AdjustThreadDispatcher.RunOnMainThread(() => { foreach (Action callback in appAttCallbacks) { - callback(status); + if (callback != null) + { + callback.Invoke(status); + } } appAttCallbacks.Clear(); - } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegatePurchaseVerificationCallback))] - private static void PurchaseVerificationCallbackMonoPInvoke(string verificationResult) { - if (appPurchaseVerificationCallback != null) + private static void PurchaseVerificationCallbackMonoPInvoke(string verificationResult) + { + if (appPurchaseVerificationCallback == null) { - appPurchaseVerificationCallback(new AdjustPurchaseVerificationResult(verificationResult)); - appPurchaseVerificationCallback = null; + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (appPurchaseVerificationCallback != null) + { + appPurchaseVerificationCallback.Invoke(new AdjustPurchaseVerificationResult(verificationResult)); + appPurchaseVerificationCallback = null; + } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateVerifyAndTrackCallback))] - private static void VerifyAndTrackCallbackMonoPInvoke(string verificationResult) { - if (appVerifyAndTrackCallback != null) + private static void VerifyAndTrackCallbackMonoPInvoke(string verificationResult) + { + if (appVerifyAndTrackCallback == null) { - appVerifyAndTrackCallback(new AdjustPurchaseVerificationResult(verificationResult)); - appVerifyAndTrackCallback = null; + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (appVerifyAndTrackCallback != null) + { + appVerifyAndTrackCallback.Invoke(new AdjustPurchaseVerificationResult(verificationResult)); + appVerifyAndTrackCallback = null; + } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateResolvedDeeplinkCallback))] - private static void ResolvedDeeplinkCallbackMonoPInvoke(string deeplink) { - if (appResolvedDeeplinkCallback != null) + private static void ResolvedDeeplinkCallbackMonoPInvoke(string deeplink) + { + if (appResolvedDeeplinkCallback == null) { - appResolvedDeeplinkCallback(deeplink); - appResolvedDeeplinkCallback = null; + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (appResolvedDeeplinkCallback != null) + { + appResolvedDeeplinkCallback.Invoke(deeplink); + appResolvedDeeplinkCallback = null; + } + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateSkanErrorCallback))] - private static void SkanErrorCallbackMonoPInvoke(string error) { - if (appSkanErrorCallback != null) + private static void SkanErrorCallbackMonoPInvoke(string error) + { + if (appSkanErrorCallback == null) { - appSkanErrorCallback(error); - appSkanErrorCallback = null; + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (appSkanErrorCallback != null) + { + appSkanErrorCallback.Invoke(error); + appSkanErrorCallback = null; + } + }); } // MonoPInvokeCallback methods as subscriptions [AOT.MonoPInvokeCallback(typeof(AdjustDelegateAttributionCallback))] - private static void AttributionCallbackMonoPInvoke(string attribution) { - if (appAttributionCallback != null) + private static void AttributionCallbackMonoPInvoke(string attribution) + { + if (appAttributionCallback == null) { - appAttributionCallback(new AdjustAttribution(attribution)); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + appAttributionCallback(new AdjustAttribution(attribution)); + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateSessionSuccessCallback))] - private static void SessionSuccessCallbackMonoPInvoke(string sessionSuccess) { - if (appSessionSuccessCallback != null) + private static void SessionSuccessCallbackMonoPInvoke(string sessionSuccess) + { + if (appSessionSuccessCallback == null) { - appSessionSuccessCallback(new AdjustSessionSuccess(sessionSuccess)); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + appSessionSuccessCallback(new AdjustSessionSuccess(sessionSuccess)); + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateSessionFailureCallback))] - private static void SessionFailureCallbackMonoPInvoke(string sessionFailure) { - if (appSessionFailureCallback != null) + private static void SessionFailureCallbackMonoPInvoke(string sessionFailure) + { + if (appSessionFailureCallback == null) { - appSessionFailureCallback(new AdjustSessionFailure(sessionFailure)); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + appSessionFailureCallback(new AdjustSessionFailure(sessionFailure)); + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateEventSuccessCallback))] - private static void EventSuccessCallbackMonoPInvoke(string eventSuccess) { - if (appEventSuccessCallback != null) + private static void EventSuccessCallbackMonoPInvoke(string eventSuccess) + { + if (appEventSuccessCallback == null) { - appEventSuccessCallback(new AdjustEventSuccess(eventSuccess)); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + appEventSuccessCallback(new AdjustEventSuccess(eventSuccess)); + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateEventFailureCallback))] - private static void EventFailureCallbackMonoPInvoke(string eventFailure) { - if (appEventFailureCallback != null) + private static void EventFailureCallbackMonoPInvoke(string eventFailure) + { + if (appEventFailureCallback == null) { - appEventFailureCallback(new AdjustEventFailure(eventFailure)); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + appEventFailureCallback(new AdjustEventFailure(eventFailure)); + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateDeferredDeeplinkCallback))] - private static void DeferredDeeplinkCallbackMonoPInvoke(string deeplink) { - if (appDeferredDeeplinkCallback != null) + private static void DeferredDeeplinkCallbackMonoPInvoke(string deeplink) + { + if (appDeferredDeeplinkCallback == null) { - appDeferredDeeplinkCallback(deeplink); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + appDeferredDeeplinkCallback(deeplink); + }); } [AOT.MonoPInvokeCallback(typeof(AdjustDelegateSkanUpdatedCallback))] - private static void SkanUpdatedCallbackMonoPInvoke(string skanData) { - if (appSkanUpdatedCallback != null) + private static void SkanUpdatedCallbackMonoPInvoke(string skanData) + { + if (appSkanUpdatedCallback == null) { - appSkanUpdatedCallback(AdjustUtils.GetSkanUpdateDataDictionary(skanData)); + return; } + + AdjustThreadDispatcher.RunOnMainThread(() => + { + if (appSkanUpdatedCallback != null) + { + appSkanUpdatedCallback.Invoke(AdjustUtils.GetSkanUpdateDataDictionary(skanData)); + } + }); } } #endif diff --git a/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs b/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs index 7d39e3c2..753630f4 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs @@ -11,11 +11,11 @@ namespace AdjustSdk { - #if UNITY_2018_1_OR_NEWER +#if UNITY_2018_1_OR_NEWER public class AdjustEditorPreprocessor : IPreprocessBuildWithReport - #else +#else public class AdjustEditorPreprocessor : IPreprocessBuild - #endif +#endif { public int callbackOrder { @@ -24,24 +24,24 @@ public int callbackOrder return 0; } } - #if UNITY_2018_1_OR_NEWER +#if UNITY_2018_1_OR_NEWER public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) { OnPreprocessBuild(report.summary.platform, string.Empty); } - #endif +#endif public void OnPreprocessBuild(BuildTarget target, string path) { if (target == BuildTarget.Android) { - #if UNITY_ANDROID +#if UNITY_ANDROID RunPostProcessTasksAndroid(); - #endif +#endif } } - #if UNITY_ANDROID +#if UNITY_ANDROID private static void RunPostProcessTasksAndroid() { var isAdjustManifestUsed = false; @@ -117,9 +117,16 @@ private static bool AddURISchemes(XmlDocument manifest) } Debug.Log("[Adjust]: Start addition of URI schemes"); - var intentRoot = manifest.DocumentElement.SelectSingleNode("/manifest/application/activity[@android:name='com.unity3d.player.UnityPlayerActivity']", GetNamespaceManager(manifest)); + // Check if user has defined a custom Android activity name. + string androidActivityName = "com.unity3d.player.UnityPlayerActivity"; + if (AdjustSettings.AndroidCustomActivityName.Length != 0) + { + androidActivityName = AdjustSettings.AndroidCustomActivityName; + } + + var intentRoot = manifest.DocumentElement.SelectSingleNode("/manifest/application/activity[@android:name='" + + androidActivityName + "']", GetNamespaceManager(manifest)); var usedIntentFiltersChanged = false; - var usedIntentFilters = GetIntentFilter(manifest); foreach (var uriScheme in AdjustSettings.AndroidUriSchemes) { Uri uri; @@ -141,54 +148,46 @@ private static bool AddURISchemes(XmlDocument manifest) continue; } - if (!IsIntentFilterAlreadyExist(manifest, uri)) + if (!DoesIntentFilterAlreadyExist(manifest, uri)) { Debug.Log("[Adjust]: Adding new URI with scheme: " + uri.Scheme + ", and host: " + uri.Host); + var newIntentFilter = GetNewIntentFilter(manifest); var androidSchemeNode = manifest.CreateElement("data"); AddAndroidNamespaceAttribute(manifest, "scheme", uri.Scheme, androidSchemeNode); AddAndroidNamespaceAttribute(manifest, "host", uri.Host, androidSchemeNode); - usedIntentFilters.AppendChild(androidSchemeNode); - usedIntentFiltersChanged = true; - + newIntentFilter.AppendChild(androidSchemeNode); + intentRoot.AppendChild(newIntentFilter); Debug.Log(string.Format("[Adjust]: Android deeplink URI scheme \"{0}\" successfully added to your app's AndroidManifest.xml file.", uriScheme)); + usedIntentFiltersChanged = true; } } - if (usedIntentFiltersChanged && usedIntentFilters.ParentNode == null) - { - intentRoot.AppendChild(usedIntentFilters); - } - return usedIntentFiltersChanged; } - private static XmlElement GetIntentFilter(XmlDocument manifest) + private static XmlElement GetNewIntentFilter(XmlDocument manifest) { - var xpath = "/manifest/application/activity/intent-filter[data/@android:scheme and data/@android:host]"; - var intentFilter = manifest.DocumentElement.SelectSingleNode(xpath, GetNamespaceManager(manifest)) as XmlElement; - if (intentFilter == null) - { - const string androidName = "name"; - const string category = "category"; + const string androidName = "name"; + const string category = "category"; - intentFilter = manifest.CreateElement("intent-filter"); + var intentFilter = manifest.CreateElement("intent-filter"); - var actionElement = manifest.CreateElement("action"); - AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.action.VIEW", actionElement); - intentFilter.AppendChild(actionElement); + var actionElement = manifest.CreateElement("action"); + AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.action.VIEW", actionElement); + intentFilter.AppendChild(actionElement); - var defaultCategory = manifest.CreateElement(category); - AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.category.DEFAULT", defaultCategory); - intentFilter.AppendChild(defaultCategory); + var defaultCategory = manifest.CreateElement(category); + AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.category.DEFAULT", defaultCategory); + intentFilter.AppendChild(defaultCategory); + + var browsableCategory = manifest.CreateElement(category); + AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.category.BROWSABLE", browsableCategory); + intentFilter.AppendChild(browsableCategory); - var browsableCategory = manifest.CreateElement(category); - AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.category.BROWSABLE", browsableCategory); - intentFilter.AppendChild(browsableCategory); - } return intentFilter; } - private static bool IsIntentFilterAlreadyExist(XmlDocument manifest, Uri link) + private static bool DoesIntentFilterAlreadyExist(XmlDocument manifest, Uri link) { var xpath = string.Format("/manifest/application/activity/intent-filter/data[@android:scheme='{0}' and @android:host='{1}']", link.Scheme, link.Host); return manifest.DocumentElement.SelectSingleNode(xpath, GetNamespaceManager(manifest)) != null; @@ -363,6 +362,6 @@ private static XmlNamespaceManager GetNamespaceManager(XmlDocument manifest) namespaceManager.AddNamespace("android", "http://schemas.android.com/apk/res/android"); return namespaceManager; } - #endif -} +#endif + } } diff --git a/Assets/Adjust/Scripts/Editor/AdjustSettings.cs b/Assets/Adjust/Scripts/Editor/AdjustSettings.cs index 6953ce24..b4d620b7 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustSettings.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustSettings.cs @@ -38,6 +38,8 @@ public class AdjustSettings : ScriptableObject private string[] _iOSUniversalLinksDomains = new string[0]; [SerializeField] private string[] androidUriSchemes = new string[0]; + [SerializeField] + private string _androidCustomActivityName; public static AdjustSettings Instance { @@ -182,5 +184,11 @@ public static string[] AndroidUriSchemes get { return Instance.androidUriSchemes; } set { Instance.androidUriSchemes = value; } } + + public static string AndroidCustomActivityName + { + get { return Instance._androidCustomActivityName; } + set { Instance._androidCustomActivityName = value; } + } } } diff --git a/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs b/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs index bde2addd..0bafe024 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs @@ -20,6 +20,7 @@ public class AdjustSettingsEditor : Editor SerializedProperty iOSUrlSchemes; SerializedProperty iOSUniversalLinksDomains; SerializedProperty androidUriSchemes; + SerializedProperty androidCustomActivityName; void OnEnable() { @@ -36,6 +37,7 @@ void OnEnable() iOSUrlSchemes = serializedObject.FindProperty("_iOSUrlSchemes"); iOSUniversalLinksDomains = serializedObject.FindProperty("_iOSUniversalLinksDomains"); androidUriSchemes = serializedObject.FindProperty("androidUriSchemes"); + androidCustomActivityName = serializedObject.FindProperty("_androidCustomActivityName"); } public override void OnInspectorGUI() { @@ -92,6 +94,15 @@ public override void OnInspectorGUI() true); EditorGUI.indentLevel -= 1; EditorGUILayout.Space(); + EditorGUILayout.LabelField("ANDROID ACTIVITY NAME:", darkerCyanTextFieldStyles); + EditorGUI.indentLevel += 1; + EditorGUILayout.PropertyField(androidCustomActivityName, + new GUIContent("Custom Android Activity Name", + "In case you are using custom activity instead of the default Unity activity " + + "(com.unity3d.player.UnityPlayerActivity), please specify it's full name."), + true); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); EditorGUILayout.LabelField("DEEP LINKING:", darkerCyanTextFieldStyles); EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(iOSUrlIdentifier, diff --git a/Assets/Adjust/package.json b/Assets/Adjust/package.json index e5d96d98..a4fdff35 100644 --- a/Assets/Adjust/package.json +++ b/Assets/Adjust/package.json @@ -1,6 +1,6 @@ { "name": "com.adjust.sdk", - "version": "5.0.7", + "version": "5.1.0", "unity": "2019.4", "displayName": "Adjust", "license": "MIT", diff --git a/Assets/Test/Scripts/CommandExecutor.cs b/Assets/Test/Scripts/CommandExecutor.cs index a51dd732..308ec989 100644 --- a/Assets/Test/Scripts/CommandExecutor.cs +++ b/Assets/Test/Scripts/CommandExecutor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using Newtonsoft.Json; namespace AdjustSdk.Test { @@ -368,6 +369,15 @@ private void Config() _testLibrary.AddInfoToSend("cost_amount", attribution.CostAmount.ToString()); _testLibrary.AddInfoToSend("cost_currency", attribution.CostCurrency); _testLibrary.AddInfoToSend("fb_install_referrer", attribution.FbInstallReferrer); + var updatedJsonResponse = new Dictionary(attribution.JsonResponse); +#if UNITY_IOS + updatedJsonResponse.Remove("fb_install_referrer"); + if (updatedJsonResponse.TryGetValue("cost_amount", out var costAmount) && costAmount is IConvertible) + { + updatedJsonResponse["cost_amount"] = string.Format("{0:0.00}", System.Convert.ToDouble(costAmount)); + } +#endif + _testLibrary.AddInfoToSend("json_response", JsonConvert.SerializeObject(updatedJsonResponse)); _testLibrary.SendInfoToServer(localExtraPath); }); } @@ -959,6 +969,15 @@ private void AttributionGetter() _testLibrary.AddInfoToSend("cost_amount", attribution.CostAmount.ToString()); _testLibrary.AddInfoToSend("cost_currency", attribution.CostCurrency); _testLibrary.AddInfoToSend("fb_install_referrer", attribution.FbInstallReferrer); + var updatedJsonResponse = new Dictionary(attribution.JsonResponse); +#if UNITY_IOS + updatedJsonResponse.Remove("fb_install_referrer"); + if (updatedJsonResponse.TryGetValue("cost_amount", out var costAmount) && costAmount is IConvertible) + { + updatedJsonResponse["cost_amount"] = string.Format("{0:0.00}", System.Convert.ToDouble(costAmount)); + } +#endif + _testLibrary.AddInfoToSend("json_response", JsonConvert.SerializeObject(updatedJsonResponse)); _testLibrary.SendInfoToServer(localExtraPath); }); } diff --git a/Assets/Test/TestApp/TestApp.cs b/Assets/Test/TestApp/TestApp.cs index 38595621..d832c737 100644 --- a/Assets/Test/TestApp/TestApp.cs +++ b/Assets/Test/TestApp/TestApp.cs @@ -11,11 +11,11 @@ public class TestApp : MonoBehaviour #if UNITY_ANDROID private const string PORT = ":8443"; private const string PROTOCOL = "https://"; - private const string IP = "192.168.86.99"; + private const string IP = "192.168.8.207"; #elif UNITY_IOS private const string PORT = ":8080"; private const string PROTOCOL = "http://"; - private const string IP = "192.168.86.99"; + private const string IP = "192.168.8.207"; private TestLibraryiOS _testLibraryiOS; #else private const string PORT = ":8080"; diff --git a/CHANGELOG.md b/CHANGELOG.md index 73e5c4ea..9672bd96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +### Version 5.1.0 (28th February 2025) +#### Added +- Added `JsonResponse` to `AdjustAttribution` where every key-value pair sent by the backend as part of the attribution response can be found. +- Added the ability to specify the name of custom Android activity which you might be using instead of the default `com.unity3d.player.UnityPlayerActivity` (https://github.com/adjust/unity_sdk/issues/273). + +#### Changed +- Switched to adding `` per specified Android URI scheme instead of adding them all as `` entries to the same intent filter (https://github.com/adjust/unity_sdk/issues/266). +- Moved execution of all the C# callbacks into the main Unity thread (https://github.com/adjust/unity_sdk/issues/277, https://github.com/adjust/unity_sdk/issues/310). + +#### Native SDKs +- [iOS@v5.1.1][ios_sdk_v5.1.1] +- [Android@v5.1.0][android_sdk_v5.1.0] + +--- + ### Version 5.0.7 (4th February 2025) #### Added - Added sending of the additional parameter to improve troubleshooting of `SKAdNetwork` related issues. @@ -1369,6 +1384,7 @@ Kudos to [Ivan](https://github.com/MatkovIvan) and [Evgeny](https://github.com/e [ios_sdk_v5.0.0]: https://github.com/adjust/ios_sdk/tree/v5.0.0 [ios_sdk_v5.0.1]: https://github.com/adjust/ios_sdk/tree/v5.0.1 [ios_sdk_v5.1.0]: https://github.com/adjust/ios_sdk/tree/v5.1.0 +[ios_sdk_v5.1.1]: https://github.com/adjust/ios_sdk/tree/v5.1.1 [android_sdk_v3.5.0]: https://github.com/adjust/android_sdk/tree/v3.5.0 [android_sdk_v4.1.0]: https://github.com/adjust/android_sdk/tree/v4.1.0 diff --git a/VERSION b/VERSION index 00433367..831446cb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.7 +5.1.0