diff --git a/Assets/Adjust/Native/Editor/Dependencies.xml b/Assets/Adjust/Native/Editor/Dependencies.xml index e3451106..ac320039 100644 --- a/Assets/Adjust/Native/Editor/Dependencies.xml +++ b/Assets/Adjust/Native/Editor/Dependencies.xml @@ -1,7 +1,7 @@ - + diff --git a/Assets/Adjust/Scripts/Adjust.cs b/Assets/Adjust/Scripts/Adjust.cs index 77f47167..7a8b1c5f 100644 --- a/Assets/Adjust/Scripts/Adjust.cs +++ b/Assets/Adjust/Scripts/Adjust.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace AdjustSdk @@ -33,7 +34,23 @@ public class Adjust : MonoBehaviour [HideInInspector] public bool linkMe = false; [HideInInspector] + public bool deviceIdsReadingOnce = false; + [HideInInspector] + public int eventDeduplicationIdsMaxSize = 0; + [HideInInspector] + public bool firstSessionDelay = false; + [HideInInspector] public string defaultTracker; + [HideInInspector] + public string storeName; + [HideInInspector] + public string storeAppId; + [HideInInspector] + public List urlStrategyDomains = new List(); + [HideInInspector] + public bool shouldUseSubdomains = false; + [HideInInspector] + public bool isDataResidency = false; // [Header("ANDROID SPECIFIC FEATURES:")] // [Space(5)] @@ -41,6 +58,8 @@ public class Adjust : MonoBehaviour public bool preinstallTracking = false; [HideInInspector] public string preinstallFilePath; + [HideInInspector] + public string fbAppId; // [Header("iOS SPECIFIC FEATURES:")] // [Space(5)] @@ -49,7 +68,13 @@ public class Adjust : MonoBehaviour [HideInInspector] public bool idfaReading = true; [HideInInspector] + public bool idfvReading = true; + [HideInInspector] public bool skanAttribution = true; + [HideInInspector] + public bool appTrackingTransparencyUsage = true; + [HideInInspector] + public int attConsentWaitingInterval = 0; void Awake() { @@ -83,15 +108,45 @@ void Awake() adjustConfig.IsSendingInBackgroundEnabled = this.sendInBackground; adjustConfig.IsDeferredDeeplinkOpeningEnabled = this.launchDeferredDeeplink; adjustConfig.DefaultTracker = this.defaultTracker; - // TODO: URL strategy adjustConfig.IsCoppaComplianceEnabled = this.coppaCompliance; adjustConfig.IsCostDataInAttributionEnabled = this.costDataInAttribution; + adjustConfig.IsDeviceIdsReadingOnceEnabled = this.deviceIdsReadingOnce; + if (this.eventDeduplicationIdsMaxSize > 0) + { + adjustConfig.EventDeduplicationIdsMaxSize = this.eventDeduplicationIdsMaxSize; + } + adjustConfig.IsFirstSessionDelayEnabled = this.firstSessionDelay; + if (!string.IsNullOrEmpty(this.storeName)) + { + AdjustStoreInfo storeInfo = new AdjustStoreInfo(this.storeName); + if (!string.IsNullOrEmpty(this.storeAppId)) + { + storeInfo.StoreAppId = this.storeAppId; + } + adjustConfig.StoreInfo = storeInfo; + } + if (this.urlStrategyDomains != null && this.urlStrategyDomains.Count > 0) + { + // Filter out empty strings + List validDomains = this.urlStrategyDomains.Where(domain => !string.IsNullOrEmpty(domain)).ToList(); + if (validDomains.Count > 0) + { + adjustConfig.SetUrlStrategy(validDomains, this.shouldUseSubdomains, this.isDataResidency); + } + } adjustConfig.IsPreinstallTrackingEnabled = this.preinstallTracking; adjustConfig.PreinstallFilePath = this.preinstallFilePath; + adjustConfig.FbAppId = this.fbAppId; adjustConfig.IsAdServicesEnabled = this.adServices; adjustConfig.IsIdfaReadingEnabled = this.idfaReading; + adjustConfig.IsIdfvReadingEnabled = this.idfvReading; adjustConfig.IsLinkMeEnabled = this.linkMe; adjustConfig.IsSkanAttributionEnabled = this.skanAttribution; + adjustConfig.IsAppTrackingTransparencyUsageEnabled = this.appTrackingTransparencyUsage; + if (this.attConsentWaitingInterval > 0) + { + adjustConfig.AttConsentWaitingInterval = this.attConsentWaitingInterval; + } Adjust.InitSdk(adjustConfig); } } diff --git a/Assets/Adjust/Scripts/AdjustAndroid.cs b/Assets/Adjust/Scripts/AdjustAndroid.cs index c33a6f1d..3d5a0724 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.4.4"; + private const string sdkPrefix = "unity5.4.5"; 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"); diff --git a/Assets/Adjust/Scripts/AdjustiOS.cs b/Assets/Adjust/Scripts/AdjustiOS.cs index a99bd7fd..d17c7f9c 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.4.4"; + private const string sdkPrefix = "unity5.4.5"; // app callbacks as method parameters private static List> appIsEnabledGetterCallbacks; diff --git a/Assets/Adjust/Scripts/Editor/AdjustCustomEditor.cs b/Assets/Adjust/Scripts/Editor/AdjustCustomEditor.cs index 193b05ac..b173892a 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustCustomEditor.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustCustomEditor.cs @@ -31,28 +31,69 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); EditorGUILayout.LabelField("MULTIPLATFORM SETTINGS:", darkerCyanTextFieldStyles); EditorGUI.indentLevel += 1; + EditorGUILayout.Space(); adjust.appToken = EditorGUILayout.TextField("App Token", adjust.appToken); adjust.environment = (AdjustEnvironment)EditorGUILayout.EnumPopup("Environment", adjust.environment); adjust.logLevel = (AdjustLogLevel)EditorGUILayout.EnumPopup("Log Level", adjust.logLevel); - // TODO: URL strategy missing + adjust.firstSessionDelay = EditorGUILayout.Toggle("First Session Delay", adjust.firstSessionDelay); adjust.sendInBackground = EditorGUILayout.Toggle("Send In Background", adjust.sendInBackground); adjust.launchDeferredDeeplink = EditorGUILayout.Toggle("Launch Deferred Deep Link", adjust.launchDeferredDeeplink); adjust.costDataInAttribution = EditorGUILayout.Toggle("Cost Data In Attribution Callback", adjust.costDataInAttribution); - adjust.linkMe = EditorGUILayout.Toggle("LinkMe", adjust.linkMe); + adjust.deviceIdsReadingOnce = EditorGUILayout.Toggle("Device IDs Reading Once", adjust.deviceIdsReadingOnce); + adjust.eventDeduplicationIdsMaxSize = EditorGUILayout.IntField("Event Deduplication IDs Count", adjust.eventDeduplicationIdsMaxSize); adjust.defaultTracker = EditorGUILayout.TextField("Default Tracker", adjust.defaultTracker); - EditorGUI.indentLevel -= 1; + + // Store Info section - visually grouped EditorGUILayout.Space(); - EditorGUILayout.LabelField("ANDROID SETTINGS:", darkerCyanTextFieldStyles); + EditorGUILayout.LabelField("Store Info:", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; - adjust.preinstallTracking = EditorGUILayout.Toggle("Preinstall Tracking", adjust.preinstallTracking); - adjust.preinstallFilePath = EditorGUILayout.TextField("Preinstall File Path", adjust.preinstallFilePath); + adjust.storeName = EditorGUILayout.TextField("Store Name", adjust.storeName); + adjust.storeAppId = EditorGUILayout.TextField("Store App ID", adjust.storeAppId); EditorGUI.indentLevel -= 1; + + // URL Strategy and Data Residency section - visually grouped EditorGUILayout.Space(); - EditorGUILayout.LabelField("IOS SETTINGS:", darkerCyanTextFieldStyles); + EditorGUILayout.LabelField("URL Strategy And Data Residency:", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + + // URL Strategy Domains list + if (adjust.urlStrategyDomains == null) + { + adjust.urlStrategyDomains = new System.Collections.Generic.List(); + } + + EditorGUILayout.LabelField("URL Strategy Domains", EditorStyles.label); EditorGUI.indentLevel += 1; - adjust.adServices = EditorGUILayout.Toggle("AdServices Info Reading", adjust.adServices); - adjust.idfaReading = EditorGUILayout.Toggle("IDFA Info Reading", adjust.idfaReading); - adjust.skanAttribution = EditorGUILayout.Toggle("SKAdNetwork Handling", adjust.skanAttribution); + int domainCount = adjust.urlStrategyDomains.Count; + int newDomainCount = EditorGUILayout.IntField("Size", domainCount); + if (newDomainCount != domainCount) + { + while (adjust.urlStrategyDomains.Count < newDomainCount) + { + adjust.urlStrategyDomains.Add(""); + } + while (adjust.urlStrategyDomains.Count > newDomainCount) + { + adjust.urlStrategyDomains.RemoveAt(adjust.urlStrategyDomains.Count - 1); + } + } + + for (int i = 0; i < adjust.urlStrategyDomains.Count; i++) + { + EditorGUILayout.BeginHorizontal(); + adjust.urlStrategyDomains[i] = EditorGUILayout.TextField("Element " + i, adjust.urlStrategyDomains[i]); + if (GUILayout.Button("Remove", GUILayout.Width(60))) + { + adjust.urlStrategyDomains.RemoveAt(i); + break; + } + EditorGUILayout.EndHorizontal(); + } + EditorGUI.indentLevel -= 1; + + adjust.shouldUseSubdomains = EditorGUILayout.Toggle("Should Use Subdomains", adjust.shouldUseSubdomains); + adjust.isDataResidency = EditorGUILayout.Toggle("Is Data Residency", adjust.isDataResidency); + EditorGUI.indentLevel -= 1; EditorGUI.indentLevel -= 1; } diff --git a/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs b/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs index 753630f4..3e1b69bd 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustEditorPreprocessor.cs @@ -86,13 +86,27 @@ private static void RunPostProcessTasksAndroid() // Add needed permissions if they are missing. manifestHasChanged |= AddPermissions(manifestFile); - // Add intent filter to main activity if it is missing. - manifestHasChanged |= AddBroadcastReceiver(manifestFile); + // Add intent filter to main activity if it is missing and user wants to use Adjust broadcast receiver. + if (AdjustSettings.AndroidUseAdjustBroadcastReceiver) + { + manifestHasChanged |= AddBroadcastReceiver(manifestFile); + } + } + else + { + // Adjust manifest is used - check if we need to remove the broadcast receiver + if (!AdjustSettings.AndroidUseAdjustBroadcastReceiver) + { + manifestHasChanged |= RemoveBroadcastReceiver(manifestFile); + } } // Add intent filter to URL schemes for deeplinking manifestHasChanged |= AddURISchemes(manifestFile); + // Add intent filter to App Links for deeplinking + manifestHasChanged |= AddAppLinks(manifestFile); + if (manifestHasChanged) { // Save the changes. @@ -165,6 +179,150 @@ private static bool AddURISchemes(XmlDocument manifest) return usedIntentFiltersChanged; } + private static bool AddAppLinks(XmlDocument manifest) + { + if (AdjustSettings.AndroidAppLinksDomains.Length == 0) + { + return false; + } + Debug.Log("[Adjust]: Start addition of Android App Links"); + + // 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)); + if (intentRoot == null) + { + Debug.LogError("[Adjust]: Could not find activity with name: " + androidActivityName); + Debug.LogError("[Adjust]: Unable to add Android App Links to AndroidManifest.xml."); + return false; + } + + var usedIntentFiltersChanged = false; + foreach (var domain in AdjustSettings.AndroidAppLinksDomains) + { + // Remove any leading/trailing whitespace + var trimmedDomain = domain.Trim(); + if (string.IsNullOrEmpty(trimmedDomain)) + { + continue; + } + + // Remove https:// or http:// prefix if present + if (trimmedDomain.StartsWith("https://")) + { + trimmedDomain = trimmedDomain.Substring(8); + } + else if (trimmedDomain.StartsWith("http://")) + { + trimmedDomain = trimmedDomain.Substring(7); + } + + // Remove leading slash if present + if (trimmedDomain.StartsWith("/")) + { + trimmedDomain = trimmedDomain.Substring(1); + } + + if (string.IsNullOrEmpty(trimmedDomain)) + { + Debug.LogError(string.Format("[Adjust]: Android App Link domain \"{0}\" is invalid and will be ignored.", domain)); + continue; + } + + // Parse host and path from the domain + // e.g., "adj.st/blah" -> host="adj.st", path="/blah" + // e.g., "adj.st" -> host="adj.st", path=null + string host; + string pathPrefix = null; + + int firstSlashIndex = trimmedDomain.IndexOf('/'); + if (firstSlashIndex >= 0) + { + host = trimmedDomain.Substring(0, firstSlashIndex); + pathPrefix = trimmedDomain.Substring(firstSlashIndex); + // Ensure pathPrefix starts with / + if (!pathPrefix.StartsWith("/")) + { + pathPrefix = "/" + pathPrefix; + } + } + else + { + host = trimmedDomain; + } + + if (string.IsNullOrEmpty(host)) + { + Debug.LogError(string.Format("[Adjust]: Android App Link domain \"{0}\" has invalid host and will be ignored.", domain)); + continue; + } + + if (!DoesAppLinkAlreadyExist(manifest, host, pathPrefix)) + { + Debug.Log(string.Format("[Adjust]: Adding new Android App Link with host: {0}, pathPrefix: {1}", host, pathPrefix ?? "(none)")); + var newIntentFilter = GetNewAppLinkIntentFilter(manifest); + var androidDataNode = manifest.CreateElement("data"); + AddAndroidNamespaceAttribute(manifest, "scheme", "https", androidDataNode); + AddAndroidNamespaceAttribute(manifest, "host", host, androidDataNode); + if (pathPrefix != null) + { + AddAndroidNamespaceAttribute(manifest, "pathPrefix", pathPrefix, androidDataNode); + } + newIntentFilter.AppendChild(androidDataNode); + intentRoot.AppendChild(newIntentFilter); + Debug.Log(string.Format("[Adjust]: Android App Link domain \"{0}\" successfully added to your app's AndroidManifest.xml file.", domain)); + usedIntentFiltersChanged = true; + } + } + + return usedIntentFiltersChanged; + } + + private static XmlElement GetNewAppLinkIntentFilter(XmlDocument manifest) + { + const string androidName = "name"; + const string category = "category"; + + var intentFilter = manifest.CreateElement("intent-filter"); + // Add android:autoVerify="true" attribute for App Links verification + AddAndroidNamespaceAttribute(manifest, "autoVerify", "true", intentFilter); + + 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 browsableCategory = manifest.CreateElement(category); + AddAndroidNamespaceAttribute(manifest, androidName, "android.intent.category.BROWSABLE", browsableCategory); + intentFilter.AppendChild(browsableCategory); + + return intentFilter; + } + + private static bool DoesAppLinkAlreadyExist(XmlDocument manifest, string host, string pathPrefix) + { + // Build XPath query to check if an App Link with the same host and pathPrefix already exists + string xpath; + if (pathPrefix != null) + { + xpath = string.Format("/manifest/application/activity/intent-filter[@android:autoVerify='true']/data[@android:scheme='https' and @android:host='{0}' and @android:pathPrefix='{1}']", host, pathPrefix); + } + else + { + xpath = string.Format("/manifest/application/activity/intent-filter[@android:autoVerify='true']/data[@android:scheme='https' and @android:host='{0}' and not(@android:pathPrefix)]", host); + } + return manifest.DocumentElement.SelectSingleNode(xpath, GetNamespaceManager(manifest)) != null; + } + private static XmlElement GetNewIntentFilter(XmlDocument manifest) { const string androidName = "name"; @@ -349,6 +507,33 @@ private static List GetCustomRecieverNodes(XmlDocument manifest) return new List(manifest.DocumentElement.SelectNodes(xpath, GetNamespaceManager(manifest)).OfType()); } + private static bool RemoveBroadcastReceiver(XmlDocument manifest) + { + Debug.Log("[Adjust]: Removing AdjustBroadcastReceiver from AndroidManifest.xml as per user settings."); + + // Find the application node + var applicationNodeXpath = "/manifest/application"; + var applicationNode = manifest.DocumentElement.SelectSingleNode(applicationNodeXpath); + + if (applicationNode == null) + { + return false; + } + + // Find and remove Adjust broadcast receiver + var xpath = "/manifest/application/receiver[@android:name='com.adjust.sdk.AdjustReferrerReceiver']"; + var receiverNode = manifest.DocumentElement.SelectSingleNode(xpath, GetNamespaceManager(manifest)); + + if (receiverNode != null) + { + applicationNode.RemoveChild(receiverNode); + Debug.Log("[Adjust]: AdjustBroadcastReceiver successfully removed from AndroidManifest.xml."); + return true; + } + + return false; + } + private static void AddAndroidNamespaceAttribute(XmlDocument manifest, string key, string value, XmlElement node) { var androidSchemeAttribute = manifest.CreateAttribute("android", key, "http://schemas.android.com/apk/res/android"); diff --git a/Assets/Adjust/Scripts/Editor/AdjustSettings.cs b/Assets/Adjust/Scripts/Editor/AdjustSettings.cs index b4d620b7..3ac4d4ce 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustSettings.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustSettings.cs @@ -39,7 +39,11 @@ public class AdjustSettings : ScriptableObject [SerializeField] private string[] androidUriSchemes = new string[0]; [SerializeField] + private string[] _androidAppLinksDomains = new string[0]; + [SerializeField] private string _androidCustomActivityName; + [SerializeField] + private bool _androidUseAdjustBroadcastReceiver = true; public static AdjustSettings Instance { @@ -185,10 +189,22 @@ public static string[] AndroidUriSchemes set { Instance.androidUriSchemes = value; } } + public static string[] AndroidAppLinksDomains + { + get { return Instance._androidAppLinksDomains; } + set { Instance._androidAppLinksDomains = value; } + } + public static string AndroidCustomActivityName { get { return Instance._androidCustomActivityName; } set { Instance._androidCustomActivityName = value; } } + + public static bool AndroidUseAdjustBroadcastReceiver + { + get { return Instance._androidUseAdjustBroadcastReceiver; } + set { Instance._androidUseAdjustBroadcastReceiver = value; } + } } } diff --git a/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs b/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs index 0bafe024..4834bf7f 100644 --- a/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs +++ b/Assets/Adjust/Scripts/Editor/AdjustSettingsEditor.cs @@ -20,7 +20,9 @@ public class AdjustSettingsEditor : Editor SerializedProperty iOSUrlSchemes; SerializedProperty iOSUniversalLinksDomains; SerializedProperty androidUriSchemes; + SerializedProperty androidAppLinksDomains; SerializedProperty androidCustomActivityName; + SerializedProperty androidUseAdjustBroadcastReceiver; void OnEnable() { @@ -37,15 +39,61 @@ void OnEnable() iOSUrlSchemes = serializedObject.FindProperty("_iOSUrlSchemes"); iOSUniversalLinksDomains = serializedObject.FindProperty("_iOSUniversalLinksDomains"); androidUriSchemes = serializedObject.FindProperty("androidUriSchemes"); + androidAppLinksDomains = serializedObject.FindProperty("_androidAppLinksDomains"); androidCustomActivityName = serializedObject.FindProperty("_androidCustomActivityName"); + androidUseAdjustBroadcastReceiver = serializedObject.FindProperty("_androidUseAdjustBroadcastReceiver"); } public override void OnInspectorGUI() { GUIStyle darkerCyanTextFieldStyles = new GUIStyle(EditorStyles.boldLabel); darkerCyanTextFieldStyles.normal.textColor = new Color(0f/255f, 190f/255f, 190f/255f); + var adjust = FindObjectOfType(); + bool isStartManually = adjust != null && adjust.startManually; + EditorGUILayout.Space(); - EditorGUILayout.LabelField("LINK IOS FRAMEWORKS:", darkerCyanTextFieldStyles); + EditorGUILayout.LabelField("IOS SETTINGS:", darkerCyanTextFieldStyles); + EditorGUI.indentLevel += 1; + EditorGUILayout.Space(); + + // Fields that should be disabled when startManually is checked + using (new EditorGUI.DisabledScope(isStartManually)) + { + if (adjust != null) + { + EditorGUI.BeginChangeCheck(); + adjust.linkMe = EditorGUILayout.Toggle("LinkMe", adjust.linkMe); + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(adjust); + } + } + + if (adjust != null) + { + EditorGUI.BeginChangeCheck(); + adjust.idfaReading = EditorGUILayout.Toggle("IDFA Info Reading", adjust.idfaReading); + adjust.idfvReading = EditorGUILayout.Toggle("IDFV Info Reading", adjust.idfvReading); + adjust.adServices = EditorGUILayout.Toggle("AdServices Info Reading", adjust.adServices); + adjust.skanAttribution = EditorGUILayout.Toggle("SKAdNetwork Handling", adjust.skanAttribution); + adjust.appTrackingTransparencyUsage = EditorGUILayout.Toggle("App Tracking Transparency Usage", adjust.appTrackingTransparencyUsage); + adjust.attConsentWaitingInterval = EditorGUILayout.IntField("ATT Consent Waiting Interval", adjust.attConsentWaitingInterval); + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(adjust); + } + } + + EditorGUILayout.PropertyField(iOSUserTrackingUsageDescription, + new GUIContent("User Tracking Description", + "String you would like to display to your users describing the reason " + + "behind asking for tracking permission."), + true); + } + + // Link iOS Frameworks - NOT disabled + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Link iOS Frameworks", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(iOSFrameworkAdSupport, new GUIContent("AdSupport.framework", @@ -64,8 +112,68 @@ public override void OnInspectorGUI() "iOS framework needed to use SKAdNetwork capabilities"), true); EditorGUI.indentLevel -= 1; + + // Deep linking - NOT disabled, moved to end + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Deep linking", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + EditorGUILayout.PropertyField(iOSUrlIdentifier, + new GUIContent("iOS URL Identifier", + "Value of CFBundleURLName property of the root CFBundleURLTypes element. " + + "If not needed otherwise, value should be your bundle ID."), + true); + EditorGUILayout.PropertyField(iOSUrlSchemes, + new GUIContent("iOS URL Schemes", + "URL schemes handled by your app. " + + "Make sure to enter just the scheme name without :// part at the end."), + true); + EditorGUILayout.PropertyField(iOSUniversalLinksDomains, + new GUIContent("iOS Universal Links Domains", + "Associated domains handled by your app. State just the domain part without applinks: part in front."), + true); + EditorGUI.indentLevel -= 1; + + EditorGUI.indentLevel -= 1; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("ANDROID SETTINGS:", darkerCyanTextFieldStyles); + EditorGUI.indentLevel += 1; + EditorGUILayout.Space(); + + // Preinstall Tracking, Preinstall File Path, Facebook App ID - at top, disabled when startManually + using (new EditorGUI.DisabledScope(isStartManually)) + { + if (adjust != null) + { + EditorGUI.BeginChangeCheck(); + adjust.preinstallTracking = EditorGUILayout.Toggle("Preinstall Tracking", adjust.preinstallTracking); + adjust.preinstallFilePath = EditorGUILayout.TextField("Preinstall File Path", adjust.preinstallFilePath); + adjust.fbAppId = EditorGUILayout.TextField("Facebook App ID", adjust.fbAppId); + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(adjust); + } + } + } + + // Custom Android Activity Name - NOT disabled + 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); + + // Use Adjust Broadcast Receiver - NOT disabled + EditorGUILayout.PropertyField(androidUseAdjustBroadcastReceiver, + new GUIContent("Use Adjust Broadcast Receiver", + "When enabled, AdjustBroadcastReceiver will be added as a listener to INSTALL_REFERRER intent. " + + "If you have no use case for AdjustBroadcastReceiver in your app, you can disable this option. " + + "Note: SDK 5.x uses the modern Install Referrer Library, so this receiver may not be needed."), + true); + + // Add Android Permissions - NOT disabled EditorGUILayout.Space(); - EditorGUILayout.LabelField("ADD ANDROID PERMISSIONS:", darkerCyanTextFieldStyles); + EditorGUILayout.LabelField("Add Android Permissions", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(androidPermissionInternet, new GUIContent("android.permission.INTERNET", @@ -84,53 +192,33 @@ public override void OnInspectorGUI() "Android permission needed to determine type of network device is connected to"), true); EditorGUI.indentLevel -= 1; + + // Deep linking - NOT disabled EditorGUILayout.Space(); - EditorGUILayout.LabelField("IOS PRIVACY:", darkerCyanTextFieldStyles); - EditorGUI.indentLevel += 1; - EditorGUILayout.PropertyField(iOSUserTrackingUsageDescription, - new GUIContent("User Tracking Description", - "String you would like to display to your users describing the reason " + - "behind asking for tracking permission."), - true); - EditorGUI.indentLevel -= 1; - EditorGUILayout.Space(); - EditorGUILayout.LabelField("ANDROID ACTIVITY NAME:", darkerCyanTextFieldStyles); + EditorGUILayout.LabelField("Deep linking", EditorStyles.boldLabel); 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, - new GUIContent("iOS URL Identifier", - "Value of CFBundleURLName property of the root CFBundleURLTypes element. " + - "If not needed otherwise, value should be your bundle ID."), - true); - EditorGUILayout.PropertyField(iOSUrlSchemes, - new GUIContent("iOS URL Schemes", - "URL schemes handled by your app. " + - "Make sure to enter just the scheme name without :// part at the end."), - true); - EditorGUILayout.PropertyField(iOSUniversalLinksDomains, - new GUIContent("iOS Universal Links Domains", - "Associated domains handled by your app. State just the domain part without applinks: part in front."), - true); EditorGUILayout.PropertyField(androidUriSchemes, new GUIContent("Android URI Schemes", "URI schemes handled by your app. " + "Make sure to enter just the scheme name with :// part at the end."), true); + EditorGUILayout.PropertyField(androidAppLinksDomains, + new GUIContent("Android App Links Domains", + "App Links domains handled by your app. " + + "Enter the domain (e.g., example.com or example.go.link). " + + "If you need to specify a path, use format: domain/path (e.g., adj.st/blah). " + + "The SDK will automatically add android:autoVerify=\"true\" and parse host/pathPrefix correctly."), + true); EditorGUILayout.HelpBox( - "Please note that Adjust SDK doesn't remove existing URI Schemes, " + + "Please note that Adjust SDK doesn't remove existing URI Schemes or App Links, " + "so if you need to clean previously added entries, " + "you need to do it manually from \"Assets/Plugins/Android/AndroidManifest.xml\"", MessageType.Info, true); EditorGUI.indentLevel -= 1; + + EditorGUI.indentLevel -= 1; + serializedObject.ApplyModifiedProperties(); } } diff --git a/Assets/Adjust/package.json b/Assets/Adjust/package.json index 96e2a4c0..21317ef0 100644 --- a/Assets/Adjust/package.json +++ b/Assets/Adjust/package.json @@ -1,6 +1,6 @@ { "name": "com.adjust.sdk", - "version": "5.4.4", + "version": "5.4.5", "unity": "2019.4", "displayName": "Adjust", "license": "MIT", diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e73697..83feb810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +### Version 5.4.5 (19th November 2025) +#### Added +- Added support for declaring Android App Links through the Adjust prefab. +- Added an option to prevent Adjust scripts from adding the broadcast receiver for the `INSTALL_REFERRER` intent on Android. +- Added all missing `AdjustConfig` fields to the Adjust prefab that can be configured without initializing the SDK manually in code. + +#### Native SDKs +- [iOS@v5.4.6][ios_sdk_v5.4.6] +- [Android@v5.4.6][android_sdk_v5.4.6] + +--- + ### Version 5.4.4 (23th October 2025) #### Changed - Updated the Adjust Signature library version to 3.61.0. @@ -1554,6 +1566,7 @@ Kudos to [Ivan](https://github.com/MatkovIvan) and [Evgeny](https://github.com/e [android_sdk_v5.4.2]: https://github.com/adjust/android_sdk/tree/v5.4.2 [android_sdk_v5.4.4]: https://github.com/adjust/android_sdk/tree/v5.4.4 [android_sdk_v5.4.5]: https://github.com/adjust/android_sdk/tree/v5.4.5 +[android_sdk_v5.4.6]: https://github.com/adjust/android_sdk/tree/v5.4.6 [windows_sdk_v4.12.0]: https://github.com/adjust/windows_sdk/tree/v4.12.0 [windows_sdk_v4.13.0]: https://github.com/adjust/windows_sdk/tree/v4.13.0 diff --git a/VERSION b/VERSION index 426c1c17..8ce222e9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.4.4 +5.4.5 diff --git a/ext/android/sdk b/ext/android/sdk index f94bb09a..b0c927b5 160000 --- a/ext/android/sdk +++ b/ext/android/sdk @@ -1 +1 @@ -Subproject commit f94bb09a41d4e07e8e3f2d7bad83e5e9dee5a14b +Subproject commit b0c927b58502db322823c0797ac24833a7367546