更新max
This commit is contained in:
@@ -16,7 +16,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// <summary>
|
||||
/// Handles auto updates for AppLovin MAX plugin.
|
||||
/// </summary>
|
||||
public class AppLovinAutoUpdater
|
||||
public static class AppLovinAutoUpdater
|
||||
{
|
||||
public const string KeyAutoUpdateEnabled = "com.applovin.auto_update_enabled";
|
||||
private const string KeyLastUpdateCheckTime = "com.applovin.last_update_check_time_v2"; // Updated to v2 to force adapter version checks in plugin version 3.1.10.
|
||||
@@ -39,7 +39,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{"MINTEGRAL_NETWORK", "android_16.8.51.1_ios_7.7.2.0.1"},
|
||||
{"MOBILEFUSE_NETWORK", "android_1.7.6.1_ios_1.7.6.1"},
|
||||
{"MOLOCO_NETWORK", "android_3.1.0.1_ios_3.1.3.1"},
|
||||
{ "MYTARGET_NETWORK", "android_5.22.1.1_ios_5.21.7.1"},
|
||||
{"MYTARGET_NETWORK", "android_5.22.1.1_ios_5.21.7.1"},
|
||||
{"PUBMATIC_NETWORK", "android_3.9.0.2_ios_3.9.0.2"},
|
||||
{"SMAATO_NETWORK", "android_22.7.0.1_ios_22.8.4.1"},
|
||||
{"TIKTOK_NETWORK", "android_6.2.0.5.2_ios_6.2.0.7.2"},
|
||||
@@ -97,7 +97,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
if (option == 0) // Download
|
||||
{
|
||||
MaxSdkLogger.UserDebug("Downloading plugin...");
|
||||
AppLovinIntegrationManager.downloadPluginProgressCallback = AppLovinIntegrationManagerWindow.OnDownloadPluginProgress;
|
||||
AppLovinEditorCoroutine.StartCoroutine(AppLovinIntegrationManager.Instance.DownloadPlugin(data.AppLovinMax));
|
||||
}
|
||||
else if (option == 1) // Not Now
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
///
|
||||
/// TODO: Currently only supports shell (Linux). Add support for Windows machines.
|
||||
/// </summary>
|
||||
public class AppLovinCommandLine
|
||||
public static class AppLovinCommandLine
|
||||
{
|
||||
/// <summary>
|
||||
/// Result obtained by running a command line command.
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
// Copyright © 2019 AppLovin. All rights reserved.
|
||||
//
|
||||
|
||||
using AppLovinMax.Scripts.IntegrationManager.Editor;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
@@ -21,6 +19,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
"AdColony",
|
||||
"Criteo",
|
||||
"LinkedIn",
|
||||
"Nend",
|
||||
"Snap",
|
||||
"Tapjoy",
|
||||
@@ -70,11 +69,26 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
"MaxSdk/Scripts/MaxVariableServiceUnityEditor.cs",
|
||||
"MaxSdk/Scripts/MaxVariableServiceUnityEditor.cs.meta",
|
||||
|
||||
// TODO: Add MaxTargetingData and MaxUserSegment when the plugin has enough traction.
|
||||
// The `MaxSdk/Scripts/Editor` folder contents have been moved into `MaxSdk/Scripts/IntegrationManager/Editor`.
|
||||
"MaxSdk/Version.md",
|
||||
"MaxSdk/Version.md.meta",
|
||||
|
||||
// The alert_icon.png has been renamed to error_icon.png.
|
||||
"MaxSdk/Resources/Images/alert_icon.png",
|
||||
"MaxSdk/Resources/Images/alert_icon.png.meta",
|
||||
|
||||
// `TargetingData` has been removed and we no longer set `UserSegment` through the Unity Plugin.
|
||||
"MaxSdk/Scripts/MaxUserSegment.cs",
|
||||
"MaxSdk/Scripts/MaxUserSegment.cs.meta",
|
||||
"MaxSdk/Scripts/MaxTargetingData.cs",
|
||||
"MaxSdk/Scripts/MaxTargetingData.cs.meta"
|
||||
};
|
||||
|
||||
static AppLovinInitialize()
|
||||
{
|
||||
// Don't run obsolete file cleanup logic when entering play mode.
|
||||
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
|
||||
|
||||
#if UNITY_IOS
|
||||
// Check that the publisher is targeting iOS 9.0+
|
||||
if (!PlayerSettings.iOS.targetOSVersionString.StartsWith("9.") && !PlayerSettings.iOS.targetOSVersionString.StartsWith("1"))
|
||||
@@ -83,51 +97,43 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}
|
||||
#endif
|
||||
|
||||
var pluginParentDir = AppLovinIntegrationManager.PluginParentDirectory;
|
||||
var isPluginOutsideAssetsDir = AppLovinIntegrationManager.IsPluginOutsideAssetsDirectory;
|
||||
var changesMade = AppLovinIntegrationManager.MovePluginFilesIfNeeded(pluginParentDir, isPluginOutsideAssetsDir);
|
||||
if (isPluginOutsideAssetsDir)
|
||||
var isPluginInPackageManager = AppLovinIntegrationManager.IsPluginInPackageManager;
|
||||
if (!isPluginInPackageManager)
|
||||
{
|
||||
// If the plugin is not under the assets folder, delete the MaxSdk/Mediation folder in the plugin, so that the adapters are not imported at that location and imported to the default location.
|
||||
var mediationDir = Path.Combine(pluginParentDir, "MaxSdk/Mediation");
|
||||
if (Directory.Exists(mediationDir))
|
||||
var changesMade = false;
|
||||
foreach (var obsoleteFileExportPathToDelete in ObsoleteFileExportPathsToDelete)
|
||||
{
|
||||
FileUtil.DeleteFileOrDirectory(mediationDir);
|
||||
FileUtil.DeleteFileOrDirectory(mediationDir + ".meta");
|
||||
changesMade = true;
|
||||
var pathToDelete = MaxSdkUtils.GetAssetPathForExportPath(obsoleteFileExportPathToDelete);
|
||||
if (CheckExistence(pathToDelete))
|
||||
{
|
||||
MaxSdkLogger.UserDebug("Deleting obsolete file '" + pathToDelete + "' that is no longer needed.");
|
||||
FileUtil.DeleteFileOrDirectory(pathToDelete);
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var obsoleteFileExportPathToDelete in ObsoleteFileExportPathsToDelete)
|
||||
{
|
||||
var pathToDelete = MaxSdkUtils.GetAssetPathForExportPath(obsoleteFileExportPathToDelete);
|
||||
if (CheckExistence(pathToDelete))
|
||||
var pluginParentDir = AppLovinIntegrationManager.PluginParentDirectory;
|
||||
// Check if any obsolete networks are installed
|
||||
foreach (var obsoleteNetwork in ObsoleteNetworks)
|
||||
{
|
||||
MaxSdkLogger.UserDebug("Deleting obsolete file '" + pathToDelete + "' that are no longer needed.");
|
||||
FileUtil.DeleteFileOrDirectory(pathToDelete);
|
||||
changesMade = true;
|
||||
var networkDir = Path.Combine(pluginParentDir, "MaxSdk/Mediation/" + obsoleteNetwork);
|
||||
if (CheckExistence(networkDir))
|
||||
{
|
||||
MaxSdkLogger.UserDebug("Deleting obsolete network " + obsoleteNetwork + " from path " + networkDir + "...");
|
||||
FileUtil.DeleteFileOrDirectory(networkDir);
|
||||
FileUtil.DeleteFileOrDirectory(networkDir + ".meta");
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any obsolete networks are installed
|
||||
foreach (var obsoleteNetwork in ObsoleteNetworks)
|
||||
{
|
||||
var networkDir = Path.Combine(pluginParentDir, "MaxSdk/Mediation/" + obsoleteNetwork);
|
||||
if (CheckExistence(networkDir))
|
||||
// Refresh UI
|
||||
if (changesMade)
|
||||
{
|
||||
MaxSdkLogger.UserDebug("Deleting obsolete network " + obsoleteNetwork + " from path " + networkDir + "...");
|
||||
FileUtil.DeleteFileOrDirectory(networkDir);
|
||||
changesMade = true;
|
||||
AssetDatabase.Refresh();
|
||||
MaxSdkLogger.UserDebug("Obsolete networks and files removed.");
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh UI
|
||||
if (changesMade)
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
MaxSdkLogger.UserDebug("AppLovin MAX Migration completed");
|
||||
}
|
||||
|
||||
AppLovinAutoUpdater.Update();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,24 +8,23 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using AppLovinMax.Internal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using VersionComparisonResult = MaxSdkUtils.VersionComparisonResult;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
[Serializable]
|
||||
public class PluginData
|
||||
{
|
||||
// ReSharper disable InconsistentNaming - Consistent with JSON data.
|
||||
public Network AppLovinMax;
|
||||
public Network[] MediatedNetworks;
|
||||
public Network[] PartnerMicroSdks;
|
||||
public DynamicLibraryToEmbed[] ThirdPartyDynamicLibrariesToEmbed;
|
||||
public Alert[] Alerts;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -48,21 +47,26 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
// }
|
||||
//
|
||||
|
||||
// ReSharper disable InconsistentNaming - Consistent with JSON data.
|
||||
public string Name;
|
||||
public string DisplayName;
|
||||
public string DownloadUrl;
|
||||
public string DependenciesFilePath;
|
||||
public PackageInfo[] Packages;
|
||||
public string[] PluginFilePaths;
|
||||
public Versions LatestVersions;
|
||||
[NonSerialized] public Versions CurrentVersions;
|
||||
[NonSerialized] public VersionComparisonResult CurrentToLatestVersionComparisonResult = VersionComparisonResult.Lesser;
|
||||
[NonSerialized] public bool RequiresUpdate;
|
||||
public DynamicLibraryToEmbed[] DynamicLibrariesToEmbed;
|
||||
|
||||
[NonSerialized] public Versions CurrentVersions;
|
||||
[NonSerialized] public MaxSdkUtils.VersionComparisonResult CurrentToLatestVersionComparisonResult = MaxSdkUtils.VersionComparisonResult.Lesser;
|
||||
[NonSerialized] public bool RequiresUpdate;
|
||||
[NonSerialized] public bool IsCurrentlyInstalling;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DynamicLibraryToEmbed
|
||||
{
|
||||
// ReSharper disable InconsistentNaming - Consistent with JSON data.
|
||||
public string PodName;
|
||||
public string[] FrameworkNames;
|
||||
|
||||
@@ -79,12 +83,62 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}
|
||||
}
|
||||
|
||||
public enum Severity
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Alert
|
||||
{
|
||||
public string SeverityType;
|
||||
public string Title;
|
||||
public string Message;
|
||||
public string Url;
|
||||
public string MinimumPluginVersion;
|
||||
public string MaximumPluginVersion;
|
||||
public string MinimumUnityVersion;
|
||||
public string MaximumUnityVersion;
|
||||
|
||||
public Severity Severity;
|
||||
|
||||
public void InitializeSeverityEnum()
|
||||
{
|
||||
switch (SeverityType)
|
||||
{
|
||||
case "INFO":
|
||||
Severity = Severity.Info;
|
||||
break;
|
||||
case "WARNING":
|
||||
Severity = Severity.Warning;
|
||||
break;
|
||||
case "ERROR":
|
||||
Severity = Severity.Error;
|
||||
break;
|
||||
default:
|
||||
MaxSdkLogger.E(string.Format("Alert <{0}> has unsupported severity type <{1}>.", Title, SeverityType));
|
||||
Severity = Severity.Info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldShowAlert()
|
||||
{
|
||||
var pluginVersionValid = MaxSdkUtils.IsVersionInRange(MaxSdk.Version, MinimumPluginVersion, MaximumPluginVersion);
|
||||
var unityVersionValid = MaxSdkUtils.IsVersionInRange(Application.unityVersion, MinimumUnityVersion, MaximumUnityVersion);
|
||||
return pluginVersionValid && unityVersionValid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A helper data class used to get current versions from Dependency.xml files.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Versions
|
||||
{
|
||||
// ReSharper disable InconsistentNaming - Consistent with JSON data.
|
||||
public string Unity;
|
||||
public string Android;
|
||||
public string Ios;
|
||||
@@ -108,66 +162,48 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return new {Unity, Android, Ios}.GetHashCode();
|
||||
return new {unity = Unity, android = Android, ios = Ios}.GetHashCode();
|
||||
}
|
||||
|
||||
private static string AdapterSdkVersion(string adapterVersion)
|
||||
{
|
||||
var index = adapterVersion.LastIndexOf(".");
|
||||
if (string.IsNullOrEmpty(adapterVersion)) return "";
|
||||
|
||||
var index = adapterVersion.LastIndexOf(".", StringComparison.Ordinal);
|
||||
return index > 0 ? adapterVersion.Substring(0, index) : adapterVersion;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A manager class for MAX integration manager window.
|
||||
///
|
||||
/// TODO: Decide if we should namespace these classes.
|
||||
/// </summary>
|
||||
public class AppLovinIntegrationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate to be called when downloading a plugin with the progress percentage.
|
||||
/// Delegate to be called when a plugin package's import is started.
|
||||
/// </summary>
|
||||
/// <param name="pluginName">The name of the plugin being downloaded.</param>
|
||||
/// <param name="progress">Percentage downloaded.</param>
|
||||
/// <param name="done">Whether or not the download is complete.</param>
|
||||
public delegate void DownloadPluginProgressCallback(string pluginName, float progress, bool done);
|
||||
internal delegate void ImportPackageStartedCallback(Network network);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to be called when a plugin package is imported.
|
||||
/// Delegate to be called when a plugin package is finished importing.
|
||||
/// </summary>
|
||||
/// <param name="network">The network data for which the package is imported.</param>
|
||||
public delegate void ImportPackageCompletedCallback(Network network);
|
||||
internal delegate void ImportPackageCompletedCallback(Network network);
|
||||
|
||||
private static readonly AppLovinIntegrationManager instance = new AppLovinIntegrationManager();
|
||||
|
||||
public static readonly string GradleTemplatePath = Path.Combine("Assets/Plugins/Android", "mainTemplate.gradle");
|
||||
public static readonly string DefaultPluginExportPath = Path.Combine("Assets", "MaxSdk");
|
||||
internal static readonly string GradleTemplatePath = Path.Combine("Assets/Plugins/Android", "mainTemplate.gradle");
|
||||
private const string MaxSdkAssetExportPath = "MaxSdk/Scripts/MaxSdk.cs";
|
||||
private const string MaxSdkMediationExportPath = "MaxSdk/Mediation";
|
||||
|
||||
internal static readonly string PluginDataEndpoint = "https://unity.applovin.com/max/1.0/integration_manager_info?plugin_version={0}";
|
||||
|
||||
/// <summary>
|
||||
/// Some publishers might re-export our plugin via Unity Package Manager and the plugin will not be under the Assets folder. This means that the mediation adapters, settings files should not be moved to the packages folder,
|
||||
/// since they get overridden when the package is updated. These are the files that should not be moved, if the plugin is not under the Assets/ folder.
|
||||
///
|
||||
/// Note: When we distribute the plugin via Unity Package Manager, we need to distribute the adapters as separate packages, and the adapters won't be in the MaxSdk folder. So we need to take that into account.
|
||||
/// </summary>
|
||||
private static readonly List<string> PluginPathsToIgnoreMoveWhenPluginOutsideAssetsDirectory = new List<string>
|
||||
{
|
||||
"MaxSdk/Mediation",
|
||||
"MaxSdk/Mediation.meta",
|
||||
"MaxSdk/Resources.meta",
|
||||
AppLovinSettings.SettingsExportPath,
|
||||
AppLovinSettings.SettingsExportPath + ".meta"
|
||||
};
|
||||
private const string PluginDataEndpoint = "https://unity.applovin.com/max/1.0/integration_manager_info?plugin_version={0}";
|
||||
|
||||
private static string externalDependencyManagerVersion;
|
||||
|
||||
public static DownloadPluginProgressCallback downloadPluginProgressCallback;
|
||||
public static ImportPackageCompletedCallback importPackageCompletedCallback;
|
||||
internal static ImportPackageStartedCallback OnImportPackageStartedCallback;
|
||||
internal static ImportPackageCompletedCallback OnImportPackageCompletedCallback;
|
||||
|
||||
private UnityWebRequest webRequest;
|
||||
private MaxWebRequest maxWebRequest;
|
||||
private Network importingNetwork;
|
||||
|
||||
/// <summary>
|
||||
@@ -185,8 +221,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
get
|
||||
{
|
||||
// Search for the asset with the default exported path first, In most cases, we should be able to find the asset.
|
||||
// In some cases where we don't, use the platform specific export path to search for the asset (in case of migrating a project from Windows to Mac or vice versa).
|
||||
// Search for the asset with the export path label.
|
||||
// Paths are normalized using AltDirectorySeparatorChar (/) to ensure compatibility across platforms (in case of migrating a project from Windows to Mac or vice versa).
|
||||
var maxSdkScriptAssetPath = MaxSdkUtils.GetAssetPathForExportPath(MaxSdkAssetExportPath);
|
||||
|
||||
// maxSdkScriptAssetPath will always have AltDirectorySeparatorChar (/) as the path separator. Convert to platform specific path.
|
||||
@@ -195,21 +231,21 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the base plugin is outside the <c>Assets/</c> directory, the mediation plugin files are still imported to the default location under <c>Assets/</c>.
|
||||
/// Returns the parent directory where the mediation adapter plugins are imported.
|
||||
/// </summary>
|
||||
public static string MediationSpecificPluginParentDirectory
|
||||
public static string MediationDirectory
|
||||
{
|
||||
get { return IsPluginOutsideAssetsDirectory ? "Assets" : PluginParentDirectory; }
|
||||
get
|
||||
{
|
||||
var mediationAssetPath = MaxSdkUtils.GetAssetPathForExportPath(MaxSdkMediationExportPath);
|
||||
return mediationAssetPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the plugin is under the Assets/ folder.
|
||||
/// Whether or not the plugin is in the Unity Package Manager.
|
||||
/// </summary>
|
||||
public static bool IsPluginOutsideAssetsDirectory
|
||||
public static bool IsPluginInPackageManager
|
||||
{
|
||||
get { return !PluginParentDirectory.StartsWith("Assets"); }
|
||||
get { return PluginParentDirectory.StartsWith("Packages"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -243,7 +279,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(externalDependencyManagerVersion)) return externalDependencyManagerVersion;
|
||||
if (MaxSdkUtils.IsValidString(externalDependencyManagerVersion)) return externalDependencyManagerVersion;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -263,14 +299,18 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private AppLovinIntegrationManager()
|
||||
{
|
||||
AssetDatabase.importPackageStarted += packageName =>
|
||||
{
|
||||
if (!IsImportingNetwork(packageName)) return;
|
||||
|
||||
CallImportPackageStartedCallback(importingNetwork);
|
||||
};
|
||||
|
||||
// Add asset import callbacks.
|
||||
AssetDatabase.importPackageCompleted += packageName =>
|
||||
{
|
||||
if (!IsImportingNetwork(packageName)) return;
|
||||
|
||||
var pluginParentDir = PluginParentDirectory;
|
||||
var isPluginOutsideAssetsDir = IsPluginOutsideAssetsDirectory;
|
||||
MovePluginFilesIfNeeded(pluginParentDir, isPluginOutsideAssetsDir);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
CallImportPackageCompletedCallback(importingNetwork);
|
||||
@@ -281,7 +321,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
if (!IsImportingNetwork(packageName)) return;
|
||||
|
||||
MaxSdkLogger.UserDebug("Package import cancelled.");
|
||||
importingNetwork = null;
|
||||
};
|
||||
|
||||
@@ -299,15 +338,15 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
public static PluginData LoadPluginDataSync()
|
||||
{
|
||||
var url = string.Format(PluginDataEndpoint, MaxSdk.Version);
|
||||
using (var unityWebRequest = UnityWebRequest.Get(url))
|
||||
var webRequestConfig = new WebRequestConfig()
|
||||
{
|
||||
var operation = unityWebRequest.SendWebRequest();
|
||||
EndPoint = url,
|
||||
};
|
||||
|
||||
// Just wait till www is done
|
||||
while (!operation.isDone) { }
|
||||
var maxWebRequest = new MaxWebRequest(webRequestConfig);
|
||||
var webResponse = maxWebRequest.SendSync();
|
||||
|
||||
return CreatePluginDataFromWebResponse(unityWebRequest);
|
||||
}
|
||||
return CreatePluginDataFromWebResponse(webResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -317,25 +356,22 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
public IEnumerator LoadPluginData(Action<PluginData> callback)
|
||||
{
|
||||
var url = string.Format(PluginDataEndpoint, MaxSdk.Version);
|
||||
using (var unityWebRequest = UnityWebRequest.Get(url))
|
||||
var webRequestConfig = new WebRequestConfig()
|
||||
{
|
||||
var operation = unityWebRequest.SendWebRequest();
|
||||
|
||||
while (!operation.isDone) yield return new WaitForSeconds(0.1f); // Just wait till www is done. Our coroutine is pretty rudimentary.
|
||||
|
||||
var pluginData = CreatePluginDataFromWebResponse(unityWebRequest);
|
||||
EndPoint = url,
|
||||
};
|
||||
|
||||
maxWebRequest = new MaxWebRequest(webRequestConfig);
|
||||
yield return maxWebRequest.Send(webResponse =>
|
||||
{
|
||||
var pluginData = CreatePluginDataFromWebResponse(webResponse);
|
||||
callback(pluginData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static PluginData CreatePluginDataFromWebResponse(UnityWebRequest unityWebRequest)
|
||||
private static PluginData CreatePluginDataFromWebResponse(WebResponse webResponse)
|
||||
{
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (unityWebRequest.result != UnityWebRequest.Result.Success)
|
||||
#else
|
||||
if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
|
||||
#endif
|
||||
if (!webResponse.IsSuccess)
|
||||
{
|
||||
MaxSdkLogger.E("Failed to load plugin data. Please check your internet connection.");
|
||||
return null;
|
||||
@@ -344,7 +380,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
PluginData pluginData;
|
||||
try
|
||||
{
|
||||
pluginData = JsonUtility.FromJson<PluginData>(unityWebRequest.downloadHandler.text);
|
||||
pluginData = JsonUtility.FromJson<PluginData>(webResponse.ResponseMessage);
|
||||
AppLovinPackageManager.PluginData = pluginData;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -356,87 +393,33 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
// Get current version of the plugin
|
||||
var appLovinMax = pluginData.AppLovinMax;
|
||||
UpdateCurrentVersions(appLovinMax, PluginParentDirectory);
|
||||
AppLovinPackageManager.UpdateCurrentVersions(appLovinMax);
|
||||
|
||||
// Get current versions for all the mediation networks.
|
||||
var mediationPluginParentDirectory = MediationSpecificPluginParentDirectory;
|
||||
foreach (var network in pluginData.MediatedNetworks)
|
||||
{
|
||||
UpdateCurrentVersions(network, mediationPluginParentDirectory);
|
||||
AppLovinPackageManager.UpdateCurrentVersions(network);
|
||||
}
|
||||
|
||||
foreach (var partnerMicroSdk in pluginData.PartnerMicroSdks)
|
||||
if (pluginData.PartnerMicroSdks != null)
|
||||
{
|
||||
UpdateCurrentVersions(partnerMicroSdk, mediationPluginParentDirectory);
|
||||
foreach (var partnerMicroSdk in pluginData.PartnerMicroSdks)
|
||||
{
|
||||
AppLovinPackageManager.UpdateCurrentVersions(partnerMicroSdk);
|
||||
}
|
||||
}
|
||||
|
||||
if (pluginData.Alerts == null) return pluginData;
|
||||
|
||||
// Initiate Severity enums from the raw strings in the response
|
||||
foreach (var alert in pluginData.Alerts)
|
||||
{
|
||||
alert.InitializeSeverityEnum();
|
||||
}
|
||||
|
||||
return pluginData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the CurrentVersion fields for a given network data object.
|
||||
/// </summary>
|
||||
/// <param name="network">Network for which to update the current versions.</param>
|
||||
/// <param name="mediationPluginParentDirectory">The parent directory of where the mediation adapter plugins are imported to.</param>
|
||||
public static void UpdateCurrentVersions(Network network, string mediationPluginParentDirectory)
|
||||
{
|
||||
var currentVersions = GetCurrentVersions(MaxSdkUtils.GetAssetPathForExportPath(network.DependenciesFilePath));
|
||||
|
||||
network.CurrentVersions = currentVersions;
|
||||
|
||||
// If AppLovin mediation plugin, get the version from MaxSdk and the latest and current version comparison.
|
||||
if (network.Name.Equals("APPLOVIN_NETWORK"))
|
||||
{
|
||||
network.CurrentVersions.Unity = MaxSdk.Version;
|
||||
|
||||
var unityVersionComparison = MaxSdkUtils.CompareVersions(network.CurrentVersions.Unity, network.LatestVersions.Unity);
|
||||
var androidVersionComparison = MaxSdkUtils.CompareVersions(network.CurrentVersions.Android, network.LatestVersions.Android);
|
||||
var iosVersionComparison = MaxSdkUtils.CompareVersions(network.CurrentVersions.Ios, network.LatestVersions.Ios);
|
||||
|
||||
// Overall version is same if all the current and latest (from db) versions are same.
|
||||
if (unityVersionComparison == VersionComparisonResult.Equal &&
|
||||
androidVersionComparison == VersionComparisonResult.Equal &&
|
||||
iosVersionComparison == VersionComparisonResult.Equal)
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = VersionComparisonResult.Equal;
|
||||
}
|
||||
// One of the installed versions is newer than the latest versions which means that the publisher is on a beta version.
|
||||
else if (unityVersionComparison == VersionComparisonResult.Greater ||
|
||||
androidVersionComparison == VersionComparisonResult.Greater ||
|
||||
iosVersionComparison == VersionComparisonResult.Greater)
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = VersionComparisonResult.Greater;
|
||||
}
|
||||
// We have a new version available if all Android, iOS and Unity has a newer version available in db.
|
||||
else
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = VersionComparisonResult.Lesser;
|
||||
}
|
||||
}
|
||||
// For all other mediation adapters, get the version comparison using their Unity versions.
|
||||
else
|
||||
{
|
||||
// If adapter is indeed installed, compare the current (installed) and the latest (from db) versions, so that we can determine if the publisher is on an older, current or a newer version of the adapter.
|
||||
// If the publisher is on a newer version of the adapter than the db version, that means they are on a beta version.
|
||||
if (!string.IsNullOrEmpty(currentVersions.Unity))
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = MaxSdkUtils.CompareUnityMediationVersions(currentVersions.Unity, network.LatestVersions.Unity);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(network.CurrentVersions.Unity) && AppLovinAutoUpdater.MinAdapterVersions.ContainsKey(network.Name))
|
||||
{
|
||||
var comparisonResult = MaxSdkUtils.CompareUnityMediationVersions(network.CurrentVersions.Unity, AppLovinAutoUpdater.MinAdapterVersions[network.Name]);
|
||||
// Requires update if current version is lower than the min required version.
|
||||
network.RequiresUpdate = comparisonResult < 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset value so that the Integration manager can hide the alert icon once adapter is updated.
|
||||
network.RequiresUpdate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the plugin file for a given network.
|
||||
/// </summary>
|
||||
@@ -446,36 +429,25 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
public IEnumerator DownloadPlugin(Network network, bool showImport = true)
|
||||
{
|
||||
var path = Path.Combine(Application.temporaryCachePath, GetPluginFileName(network)); // TODO: Maybe delete plugin file after finishing import.
|
||||
var downloadHandler = new DownloadHandlerFile(path);
|
||||
webRequest = new UnityWebRequest(network.DownloadUrl)
|
||||
var webRequestConfig = new WebRequestConfig()
|
||||
{
|
||||
method = UnityWebRequest.kHttpVerbGET,
|
||||
downloadHandler = downloadHandler
|
||||
DownloadHandler = new DownloadHandlerFile(path),
|
||||
EndPoint = network.DownloadUrl
|
||||
};
|
||||
|
||||
var operation = webRequest.SendWebRequest();
|
||||
while (!operation.isDone)
|
||||
maxWebRequest = new MaxWebRequest(webRequestConfig);
|
||||
yield return maxWebRequest.Send(webResponse =>
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f); // Just wait till webRequest is completed. Our coroutine is pretty rudimentary.
|
||||
CallDownloadPluginProgressCallback(network.DisplayName, operation.progress, operation.isDone);
|
||||
}
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (webRequest.result != UnityWebRequest.Result.Success)
|
||||
#else
|
||||
if (webRequest.isNetworkError || webRequest.isHttpError)
|
||||
#endif
|
||||
{
|
||||
MaxSdkLogger.UserError(webRequest.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
importingNetwork = network;
|
||||
AssetDatabase.ImportPackage(path, showImport);
|
||||
}
|
||||
|
||||
webRequest.Dispose();
|
||||
webRequest = null;
|
||||
if (webResponse.IsSuccess)
|
||||
{
|
||||
importingNetwork = network;
|
||||
AssetDatabase.ImportPackage(path, showImport);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to download plugin package: " + webResponse.ErrorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -483,9 +455,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
public void CancelDownload()
|
||||
{
|
||||
if (webRequest == null) return;
|
||||
if (maxWebRequest == null) return;
|
||||
|
||||
webRequest.Abort();
|
||||
maxWebRequest.Abort();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -503,111 +475,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
MaxSdkLogger.UserError(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not an adapter with the given version or newer exists.
|
||||
/// </summary>
|
||||
/// <param name="adapterName">The name of the network (the root adapter folder name in "MaxSdk/Mediation/" folder.</param>
|
||||
/// <param name="iosVersion">The min adapter version to check for. Can be <c>null</c> if we want to check for any version.</param>
|
||||
/// <returns><c>true</c> if an adapter with the min version is installed.</returns>
|
||||
public static bool IsAdapterInstalled(string adapterName, string iosVersion = null) // TODO: Add Android version check.
|
||||
{
|
||||
var dependencyFilePath = MaxSdkUtils.GetAssetPathForExportPath("MaxSdk/Mediation/" + adapterName + "/Editor/Dependencies.xml");
|
||||
if (!File.Exists(dependencyFilePath)) return false;
|
||||
|
||||
// If version is null, we just need the adapter installed. We don't have to check for a specific version.
|
||||
if (iosVersion == null) return true;
|
||||
|
||||
var currentVersion = GetCurrentVersions(dependencyFilePath);
|
||||
var iosVersionComparison = MaxSdkUtils.CompareVersions(currentVersion.Ios, iosVersion);
|
||||
return iosVersionComparison != VersionComparisonResult.Lesser;
|
||||
}
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current versions for a given network's dependency file path.
|
||||
/// </summary>
|
||||
/// <param name="dependencyPath">A dependency file path that from which to extract current versions.</param>
|
||||
/// <returns>Current versions of a given network's dependency file.</returns>
|
||||
public static Versions GetCurrentVersions(string dependencyPath)
|
||||
{
|
||||
XDocument dependency;
|
||||
try
|
||||
{
|
||||
dependency = XDocument.Load(dependencyPath);
|
||||
}
|
||||
#pragma warning disable 0168
|
||||
catch (IOException exception)
|
||||
#pragma warning restore 0168
|
||||
{
|
||||
// Couldn't find the dependencies file. The plugin is not installed.
|
||||
return new Versions();
|
||||
}
|
||||
|
||||
// <dependencies>
|
||||
// <androidPackages>
|
||||
// <androidPackage spec="com.applovin.mediation:network_name-adapter:1.2.3.4" />
|
||||
// </androidPackages>
|
||||
// <iosPods>
|
||||
// <iosPod name="AppLovinMediationNetworkNameAdapter" version="2.3.4.5" />
|
||||
// </iosPods>
|
||||
// </dependencies>
|
||||
string androidVersion = null;
|
||||
string iosVersion = null;
|
||||
var dependenciesElement = dependency.Element("dependencies");
|
||||
if (dependenciesElement != null)
|
||||
{
|
||||
var androidPackages = dependenciesElement.Element("androidPackages");
|
||||
if (androidPackages != null)
|
||||
{
|
||||
var adapterPackage = androidPackages.Descendants().FirstOrDefault(element => element.Name.LocalName.Equals("androidPackage")
|
||||
&& element.FirstAttribute.Name.LocalName.Equals("spec")
|
||||
&& element.FirstAttribute.Value.StartsWith("com.applovin"));
|
||||
if (adapterPackage != null)
|
||||
{
|
||||
androidVersion = adapterPackage.FirstAttribute.Value.Split(':').Last();
|
||||
// Hack alert: Some Android versions might have square brackets to force a specific version. Remove them if they are detected.
|
||||
if (androidVersion.StartsWith("["))
|
||||
{
|
||||
androidVersion = androidVersion.Trim('[', ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var iosPods = dependenciesElement.Element("iosPods");
|
||||
if (iosPods != null)
|
||||
{
|
||||
var adapterPod = iosPods.Descendants().FirstOrDefault(element => element.Name.LocalName.Equals("iosPod")
|
||||
&& element.FirstAttribute.Name.LocalName.Equals("name")
|
||||
&& element.FirstAttribute.Value.StartsWith("AppLovin"));
|
||||
if (adapterPod != null)
|
||||
{
|
||||
iosVersion = adapterPod.Attributes().First(attribute => attribute.Name.LocalName.Equals("version")).Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var currentVersions = new Versions();
|
||||
if (androidVersion != null && iosVersion != null)
|
||||
{
|
||||
currentVersions.Unity = string.Format("android_{0}_ios_{1}", androidVersion, iosVersion);
|
||||
currentVersions.Android = androidVersion;
|
||||
currentVersions.Ios = iosVersion;
|
||||
}
|
||||
else if (androidVersion != null)
|
||||
{
|
||||
currentVersions.Unity = string.Format("android_{0}", androidVersion);
|
||||
currentVersions.Android = androidVersion;
|
||||
}
|
||||
else if (iosVersion != null)
|
||||
{
|
||||
currentVersions.Unity = string.Format("ios_{0}", iosVersion);
|
||||
currentVersions.Ios = iosVersion;
|
||||
}
|
||||
|
||||
return currentVersions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the given package name is the currently importing package.
|
||||
/// </summary>
|
||||
@@ -615,120 +484,22 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// <returns>true if the importing package matches the given package name.</returns>
|
||||
private bool IsImportingNetwork(string packageName)
|
||||
{
|
||||
// Note: The pluginName doesn't have the '.unitypacakge' extension included in its name but the pluginFileName does. So using Contains instead of Equals.
|
||||
// Note: The pluginName doesn't have the '.unitypackage' extension included in its name but the pluginFileName does. So using Contains instead of Equals.
|
||||
return importingNetwork != null && GetPluginFileName(importingNetwork).Contains(packageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the imported plugin files to the MaxSdk directory if the publisher has moved the plugin to a different directory. This is a failsafe for when some plugin files are not imported to the new location.
|
||||
/// </summary>
|
||||
/// <returns>True if the adapters have been moved.</returns>
|
||||
public static bool MovePluginFilesIfNeeded(string pluginParentDirectory, bool isPluginOutsideAssetsDirectory)
|
||||
private static void CallImportPackageStartedCallback(Network network)
|
||||
{
|
||||
var pluginDir = Path.Combine(pluginParentDirectory, "MaxSdk");
|
||||
if (OnImportPackageStartedCallback == null) return;
|
||||
|
||||
// Check if the user has moved the Plugin and if new assets have been imported to the default directory.
|
||||
if (DefaultPluginExportPath.Equals(pluginDir) || !Directory.Exists(DefaultPluginExportPath)) return false;
|
||||
|
||||
MovePluginFiles(DefaultPluginExportPath, pluginDir, isPluginOutsideAssetsDirectory);
|
||||
if (!isPluginOutsideAssetsDirectory)
|
||||
{
|
||||
FileUtil.DeleteFileOrDirectory(DefaultPluginExportPath + ".meta");
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A helper function to move all the files recursively from the default plugin dir to a custom location the publisher moved the plugin to.
|
||||
/// </summary>
|
||||
private static void MovePluginFiles(string fromDirectory, string pluginRoot, bool isPluginOutsideAssetsDirectory)
|
||||
{
|
||||
var files = Directory.GetFiles(fromDirectory);
|
||||
foreach (var file in files)
|
||||
{
|
||||
// We have to ignore some files, if the plugin is outside the Assets/ directory.
|
||||
if (isPluginOutsideAssetsDirectory && PluginPathsToIgnoreMoveWhenPluginOutsideAssetsDirectory.Any(pluginPathsToIgnore => file.Contains(pluginPathsToIgnore))) continue;
|
||||
|
||||
// Check if the destination folder exists and create it if it doesn't exist
|
||||
var parentDirectory = Path.GetDirectoryName(file);
|
||||
var destinationDirectoryPath = parentDirectory.Replace(DefaultPluginExportPath, pluginRoot);
|
||||
if (!Directory.Exists(destinationDirectoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDirectoryPath);
|
||||
}
|
||||
|
||||
// If the meta file is of a folder asset and doesn't have labels (it is auto generated by Unity), just delete it.
|
||||
if (IsAutoGeneratedFolderMetaFile(file))
|
||||
{
|
||||
FileUtil.DeleteFileOrDirectory(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
var destinationPath = file.Replace(DefaultPluginExportPath, pluginRoot);
|
||||
|
||||
// Check if the file is already present at the destination path and delete it.
|
||||
if (File.Exists(destinationPath))
|
||||
{
|
||||
FileUtil.DeleteFileOrDirectory(destinationPath);
|
||||
}
|
||||
|
||||
FileUtil.MoveFileOrDirectory(file, destinationPath);
|
||||
}
|
||||
|
||||
var directories = Directory.GetDirectories(fromDirectory);
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
// We might have to ignore some directories, if the plugin is outside the Assets/ directory.
|
||||
if (isPluginOutsideAssetsDirectory && PluginPathsToIgnoreMoveWhenPluginOutsideAssetsDirectory.Any(pluginPathsToIgnore => directory.Contains(pluginPathsToIgnore))) continue;
|
||||
|
||||
MovePluginFiles(directory, pluginRoot, isPluginOutsideAssetsDirectory);
|
||||
}
|
||||
|
||||
if (!isPluginOutsideAssetsDirectory)
|
||||
{
|
||||
FileUtil.DeleteFileOrDirectory(fromDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAutoGeneratedFolderMetaFile(string assetPath)
|
||||
{
|
||||
// Check if it is a meta file.
|
||||
if (!assetPath.EndsWith(".meta")) return false;
|
||||
|
||||
var lines = File.ReadAllLines(assetPath);
|
||||
var isFolderAsset = false;
|
||||
var hasLabels = false;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.Contains("folderAsset: yes"))
|
||||
{
|
||||
isFolderAsset = true;
|
||||
}
|
||||
|
||||
if (line.Contains("labels:"))
|
||||
{
|
||||
hasLabels = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If it is a folder asset and doesn't have a label, the meta file is auto generated by
|
||||
return isFolderAsset && !hasLabels;
|
||||
}
|
||||
|
||||
private static void CallDownloadPluginProgressCallback(string pluginName, float progress, bool isDone)
|
||||
{
|
||||
if (downloadPluginProgressCallback == null) return;
|
||||
|
||||
downloadPluginProgressCallback(pluginName, progress, isDone);
|
||||
OnImportPackageStartedCallback(network);
|
||||
}
|
||||
|
||||
private static void CallImportPackageCompletedCallback(Network network)
|
||||
{
|
||||
if (importPackageCompletedCallback == null) return;
|
||||
if (OnImportPackageCompletedCallback == null) return;
|
||||
|
||||
importPackageCompletedCallback(network);
|
||||
OnImportPackageCompletedCallback(network);
|
||||
}
|
||||
|
||||
private static object GetEditorUserBuildSetting(string name, object defaultValue)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
public static class AppLovinIntegrationManagerUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Compares AppLovin MAX Unity mediation adapter plugin versions. Returns <see cref="MaxSdkUtils.VersionComparisonResult.Lesser"/>, <see cref="MaxSdkUtils.VersionComparisonResult.Equal"/>,
|
||||
/// or <see cref="MaxSdkUtils.VersionComparisonResult.Greater"/> as the first version is less than, equal to, or greater than the second.
|
||||
///
|
||||
/// If a version for a specific platform is only present in one of the provided versions, the one that contains it is considered newer.
|
||||
/// </summary>
|
||||
/// <param name="versionA">The first version to be compared.</param>
|
||||
/// <param name="versionB">The second version to be compared.</param>
|
||||
/// <returns>
|
||||
/// <see cref="MaxSdkUtils.VersionComparisonResult.Lesser"/> if versionA is less than versionB.
|
||||
/// <see cref="MaxSdkUtils.VersionComparisonResult.Equal"/> if versionA and versionB are equal.
|
||||
/// <see cref="MaxSdkUtils.VersionComparisonResult.Greater"/> if versionA is greater than versionB.
|
||||
/// </returns>
|
||||
internal static MaxSdkUtils.VersionComparisonResult CompareUnityMediationVersions(string versionA, string versionB)
|
||||
{
|
||||
if (versionA.Equals(versionB)) return MaxSdkUtils.VersionComparisonResult.Equal;
|
||||
|
||||
// Unity version would be of format: android_w.x.y.z_ios_a.b.c.d
|
||||
// For Android only versions it would be: android_w.x.y.z
|
||||
// For iOS only version it would be: ios_a.b.c.d
|
||||
|
||||
// After splitting into their respective components, the versions would be at the odd indices.
|
||||
var versionAComponents = versionA.Split('_').ToList();
|
||||
var versionBComponents = versionB.Split('_').ToList();
|
||||
|
||||
var androidComparison = MaxSdkUtils.VersionComparisonResult.Equal;
|
||||
if (versionA.Contains("android") && versionB.Contains("android"))
|
||||
{
|
||||
var androidVersionA = versionAComponents[1];
|
||||
var androidVersionB = versionBComponents[1];
|
||||
androidComparison = MaxSdkUtils.CompareVersions(androidVersionA, androidVersionB);
|
||||
|
||||
// Remove the Android version component so that iOS versions can be processed.
|
||||
versionAComponents.RemoveRange(0, 2);
|
||||
versionBComponents.RemoveRange(0, 2);
|
||||
}
|
||||
else if (versionA.Contains("android"))
|
||||
{
|
||||
androidComparison = MaxSdkUtils.VersionComparisonResult.Greater;
|
||||
|
||||
// Remove the Android version component so that iOS versions can be processed.
|
||||
versionAComponents.RemoveRange(0, 2);
|
||||
}
|
||||
else if (versionB.Contains("android"))
|
||||
{
|
||||
androidComparison = MaxSdkUtils.VersionComparisonResult.Lesser;
|
||||
|
||||
// Remove the Android version component so that iOS version can be processed.
|
||||
versionBComponents.RemoveRange(0, 2);
|
||||
}
|
||||
|
||||
var iosComparison = MaxSdkUtils.VersionComparisonResult.Equal;
|
||||
if (versionA.Contains("ios") && versionB.Contains("ios"))
|
||||
{
|
||||
var iosVersionA = versionAComponents[1];
|
||||
var iosVersionB = versionBComponents[1];
|
||||
iosComparison = MaxSdkUtils.CompareVersions(iosVersionA, iosVersionB);
|
||||
}
|
||||
else if (versionA.Contains("ios"))
|
||||
{
|
||||
iosComparison = MaxSdkUtils.VersionComparisonResult.Greater;
|
||||
}
|
||||
else if (versionB.Contains("ios"))
|
||||
{
|
||||
iosComparison = MaxSdkUtils.VersionComparisonResult.Lesser;
|
||||
}
|
||||
|
||||
// If either one of the Android or iOS version is greater, the entire version should be greater.
|
||||
return (androidComparison == MaxSdkUtils.VersionComparisonResult.Greater || iosComparison == MaxSdkUtils.VersionComparisonResult.Greater) ? MaxSdkUtils.VersionComparisonResult.Greater : MaxSdkUtils.VersionComparisonResult.Lesser;
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96efb4dba39eb48d2a60afab69786e6a
|
||||
labels:
|
||||
- al_max
|
||||
- al_max_export_path-MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManagerUtils.cs
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+318
-250
@@ -8,65 +8,68 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VersionComparisonResult = MaxSdkUtils.VersionComparisonResult;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
public class AppLovinIntegrationManagerWindow : EditorWindow
|
||||
{
|
||||
private const string windowTitle = "AppLovin Integration Manager";
|
||||
private const string WindowTitle = "AppLovin Integration Manager";
|
||||
|
||||
private const string appLovinSdkKeyLink = "https://dash.applovin.com/o/account#keys";
|
||||
private const string AppLovinSdkKeyLink = "https://dash.applovin.com/o/account#keys";
|
||||
|
||||
private const string userTrackingUsageDescriptionDocsLink = "https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription";
|
||||
private const string documentationTermsAndPrivacyPolicyFlow = "https://developers.applovin.com/en/unity/overview/terms-and-privacy-policy-flow";
|
||||
private const string documentationAdaptersLink = "https://developers.applovin.com/en/unity/preparing-mediated-networks";
|
||||
private const string documentationNote = "Please ensure that integration instructions (e.g. permissions, ATS settings, etc) specific to each network are implemented as well. Click the link below for more info:";
|
||||
private const string uninstallIconExportPath = "MaxSdk/Resources/Images/uninstall_icon.png";
|
||||
private const string alertIconExportPath = "MaxSdk/Resources/Images/alert_icon.png";
|
||||
private const string warningIconExportPath = "MaxSdk/Resources/Images/warning_icon.png";
|
||||
private const string UserTrackingUsageDescriptionDocsLink = "https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription";
|
||||
private const string DocumentationTermsAndPrivacyPolicyFlow = "https://support.axon.ai/en/max/unity/overview/terms-and-privacy-policy-flow";
|
||||
private const string DocumentationAdaptersLink = "https://support.axon.ai/en/max/unity/preparing-mediated-networks";
|
||||
private const string DocumentationNote = "Please ensure that integration instructions (e.g. permissions, ATS settings, etc) specific to each network are implemented as well. Click the link below for more info:";
|
||||
private const string UninstallIconExportPath = "MaxSdk/Resources/Images/uninstall_icon.png";
|
||||
private const string InfoIconExportPath = "MaxSdk/Resources/Images/info_icon.png";
|
||||
private const string WarningIconExportPath = "MaxSdk/Resources/Images/warning_icon.png";
|
||||
private const string ErrorIconExportPath = "MaxSdk/Resources/Images/error_icon.png";
|
||||
|
||||
private const string qualityServiceRequiresGradleBuildErrorMsg = "AppLovin Quality Service integration via AppLovin Integration Manager requires Custom Gradle Template enabled or Unity 2018.2 or higher.\n" +
|
||||
private const string QualityServiceRequiresGradleBuildErrorMsg = "AppLovin Quality Service integration via AppLovin Integration Manager requires Custom Gradle Template enabled or Unity 2018.2 or higher.\n" +
|
||||
"If you would like to continue using your existing setup, please add Quality Service Plugin to your build.gradle manually.";
|
||||
|
||||
private const string customGradleVersionTooltip = "To set the version to 6.9.3, set the field to: https://services.gradle.org/distributions/gradle-6.9.3-bin.zip";
|
||||
private const string customGradleToolsVersionTooltip = "To set the version to 4.2.0, set the field to: 4.2.0";
|
||||
private const string CustomGradleVersionTooltip = "To set the version to 6.9.3, set the field to: https://services.gradle.org/distributions/gradle-6.9.3-bin.zip";
|
||||
private const string CustomGradleToolsVersionTooltip = "To set the version to 4.2.0, set the field to: 4.2.0";
|
||||
|
||||
private const string keyShowMicroSdkPartners = "com.applovin.show_micro_sdk_partners";
|
||||
private const string keyShowMediatedNetworks = "com.applovin.show_mediated_networks";
|
||||
private const string keyShowSdkSettings = "com.applovin.show_sdk_settings";
|
||||
private const string keyShowPrivacySettings = "com.applovin.show_privacy_settings";
|
||||
private const string keyShowOtherSettings = "com.applovin.show_other_settings";
|
||||
private const string KeyShowAlerts = "com.applovin.show_alerts";
|
||||
private const string KeyShowMicroSdkPartners = "com.applovin.show_micro_sdk_partners";
|
||||
private const string KeyShowMediatedNetworks = "com.applovin.show_mediated_networks";
|
||||
private const string KeyShowSdkSettings = "com.applovin.show_sdk_settings";
|
||||
private const string KeyShowPrivacySettings = "com.applovin.show_privacy_settings";
|
||||
private const string KeyShowOtherSettings = "com.applovin.show_other_settings";
|
||||
|
||||
private const string expandButtonText = "+";
|
||||
private const string collapseButtonText = "-";
|
||||
private const string ExpandButtonText = "+";
|
||||
private const string CollapseButtonText = "-";
|
||||
|
||||
private const string ExternalDependencyManagerPath = "Assets/ExternalDependencyManager";
|
||||
|
||||
private readonly string[] termsFlowPlatforms = new string[3] {"Both", "Android", "iOS"};
|
||||
private readonly string[] debugUserGeographies = new string[2] {"Not Set", "GDPR"};
|
||||
|
||||
private Vector2 scrollPosition;
|
||||
private static readonly Vector2 windowMinSize = new Vector2(750, 750);
|
||||
private const float actionFieldWidth = 60f;
|
||||
private const float upgradeAllButtonWidth = 80f;
|
||||
private const float networkFieldMinWidth = 100f;
|
||||
private const float versionFieldMinWidth = 190f;
|
||||
private const float privacySettingLabelWidth = 250f;
|
||||
private const float networkFieldWidthPercentage = 0.22f;
|
||||
private const float versionFieldWidthPercentage = 0.36f; // There are two version fields. Each take 40% of the width, network field takes the remaining 20%.
|
||||
private static float previousWindowWidth = windowMinSize.x;
|
||||
private static GUILayoutOption networkWidthOption = GUILayout.Width(networkFieldMinWidth);
|
||||
private static GUILayoutOption versionWidthOption = GUILayout.Width(versionFieldMinWidth);
|
||||
private static readonly Vector2 WindowMinSize = new Vector2(750, 750);
|
||||
private const float ActionFieldWidth = 70f;
|
||||
private const float UpgradeAllButtonWidth = 80f;
|
||||
private const float NetworkFieldMinWidth = 100f;
|
||||
private const float VersionFieldMinWidth = 190f;
|
||||
private const float PrivacySettingLabelWidth = 250f;
|
||||
private const float NetworkFieldWidthPercentage = 0.22f;
|
||||
private const float VersionFieldWidthPercentage = 0.36f; // There are two version fields. Each take 40% of the width, network field takes the remaining 20%.
|
||||
private static float previousWindowWidth = WindowMinSize.x;
|
||||
private static GUILayoutOption networkWidthOption = GUILayout.Width(NetworkFieldMinWidth);
|
||||
private static GUILayoutOption versionWidthOption = GUILayout.Width(VersionFieldMinWidth);
|
||||
|
||||
private static GUILayoutOption privacySettingFieldWidthOption = GUILayout.Width(400);
|
||||
private static readonly GUILayoutOption fieldWidth = GUILayout.Width(actionFieldWidth);
|
||||
private static readonly GUILayoutOption upgradeAllButtonFieldWidth = GUILayout.Width(upgradeAllButtonWidth);
|
||||
private static readonly GUILayoutOption collapseButtonWidthOption = GUILayout.Width(20f);
|
||||
private static readonly GUILayoutOption FieldWidth = GUILayout.Width(ActionFieldWidth);
|
||||
private static readonly GUILayoutOption UpgradeAllButtonFieldWidth = GUILayout.Width(UpgradeAllButtonWidth);
|
||||
private static readonly GUILayoutOption CollapseButtonWidthOption = GUILayout.Width(20f);
|
||||
|
||||
private static readonly Color darkModeTextColor = new Color(0.29f, 0.6f, 0.8f);
|
||||
private static readonly Color DarkModeTextColor = new Color(0.29f, 0.6f, 0.8f);
|
||||
|
||||
private GUIStyle titleLabelStyle;
|
||||
private GUIStyle headerLabelStyle;
|
||||
@@ -77,19 +80,19 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private PluginData pluginData;
|
||||
private bool pluginDataLoadFailed;
|
||||
private bool isPluginMoved;
|
||||
private bool shouldShowGoogleWarning;
|
||||
private bool networkButtonsEnabled = true;
|
||||
|
||||
private AppLovinEditorCoroutine loadDataCoroutine;
|
||||
private Texture2D uninstallIcon;
|
||||
private Texture2D alertIcon;
|
||||
private Texture2D infoIcon;
|
||||
private Texture2D warningIcon;
|
||||
private Texture2D errorIcon;
|
||||
|
||||
public static void ShowManager()
|
||||
{
|
||||
var manager = GetWindow<AppLovinIntegrationManagerWindow>(utility: true, title: windowTitle, focus: true);
|
||||
manager.minSize = windowMinSize;
|
||||
var manager = GetWindow<AppLovinIntegrationManagerWindow>(utility: true, title: WindowTitle, focus: true);
|
||||
manager.minSize = WindowMinSize;
|
||||
}
|
||||
|
||||
#region Editor Window Lifecyle Methods
|
||||
@@ -118,7 +121,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
linkLabelStyle = new GUIStyle(EditorStyles.label)
|
||||
{
|
||||
wordWrap = true,
|
||||
normal = {textColor = EditorGUIUtility.isProSkin ? darkModeTextColor : Color.blue}
|
||||
normal = {textColor = EditorGUIUtility.isProSkin ? DarkModeTextColor : Color.blue}
|
||||
};
|
||||
|
||||
wrapTextLabelStyle = new GUIStyle(EditorStyles.label)
|
||||
@@ -134,22 +137,27 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
};
|
||||
|
||||
// Load uninstall icon texture.
|
||||
var uninstallIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(uninstallIconExportPath));
|
||||
uninstallIcon = new Texture2D(0, 0, TextureFormat.RGBA32, false); // 1. Initial size doesn't matter here, will be automatically resized once the image asset is loaded. 2. Set mipChain to false, else the texture has a weird blurry effect.
|
||||
var uninstallIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(UninstallIconExportPath));
|
||||
// 1. Set the initial size to 1, as Unity 6000 no longer supports a width or height of 0.
|
||||
// 2. The image will be automatically resized once the image asset is loaded.
|
||||
// 3. Set mipChain to false, else the texture has a weird blurry effect.
|
||||
uninstallIcon = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||
uninstallIcon.LoadImage(uninstallIconData);
|
||||
|
||||
// Load alert icon texture.
|
||||
var alertIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(alertIconExportPath));
|
||||
alertIcon = new Texture2D(0, 0, TextureFormat.RGBA32, false);
|
||||
alertIcon.LoadImage(alertIconData);
|
||||
// Load info icon texture.
|
||||
var infoIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(InfoIconExportPath));
|
||||
infoIcon = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||
infoIcon.LoadImage(infoIconData);
|
||||
|
||||
// Load warning icon texture.
|
||||
var warningIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(warningIconExportPath));
|
||||
warningIcon = new Texture2D(0, 0, TextureFormat.RGBA32, false);
|
||||
var warningIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(WarningIconExportPath));
|
||||
warningIcon = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||
warningIcon.LoadImage(warningIconData);
|
||||
|
||||
var pluginPath = Path.Combine(AppLovinIntegrationManager.PluginParentDirectory, "MaxSdk");
|
||||
isPluginMoved = !AppLovinIntegrationManager.DefaultPluginExportPath.Equals(pluginPath);
|
||||
// Load error icon texture.
|
||||
var errorIconData = File.ReadAllBytes(MaxSdkUtils.GetAssetPathForExportPath(ErrorIconExportPath));
|
||||
errorIcon = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||
errorIcon.LoadImage(errorIconData);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
@@ -174,17 +182,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private void OnWindowEnabled()
|
||||
{
|
||||
AppLovinIntegrationManager.downloadPluginProgressCallback = OnDownloadPluginProgress;
|
||||
|
||||
// Plugin downloaded and imported. Update current versions for the imported package.
|
||||
AppLovinIntegrationManager.importPackageCompletedCallback = OnImportPackageCompleted;
|
||||
|
||||
// Disable old consent flow if new flow is enabled.
|
||||
if (AppLovinInternalSettings.Instance.ConsentFlowEnabled)
|
||||
{
|
||||
AppLovinSettings.Instance.ConsentFlowEnabled = false;
|
||||
AppLovinSettings.Instance.SaveAsync();
|
||||
}
|
||||
AppLovinIntegrationManager.OnImportPackageStartedCallback = OnImportPackageStarted;
|
||||
AppLovinIntegrationManager.OnImportPackageCompletedCallback = OnImportPackageCompleted;
|
||||
|
||||
Load();
|
||||
}
|
||||
@@ -221,17 +221,36 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
// Draw AppLovin MAX plugin details
|
||||
EditorGUILayout.LabelField("AppLovin MAX Plugin Details", titleLabelStyle);
|
||||
|
||||
DrawPluginDetails();
|
||||
|
||||
if (pluginData != null && pluginData.PartnerMicroSdks != null)
|
||||
// Draw alerts
|
||||
if (pluginData != null && pluginData.Alerts != null)
|
||||
{
|
||||
DrawCollapsableSection(keyShowMicroSdkPartners, "AppLovin Micro SDK Partners", DrawPartnerMicroSdks);
|
||||
var alertsToShow = pluginData.Alerts.Where(alert => alert.ShouldShowAlert()).ToList();
|
||||
if (alertsToShow.Count > 0)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
var showAlertDetails = DrawExpandCollapseButton(KeyShowAlerts);
|
||||
EditorGUILayout.LabelField("Alerts", titleLabelStyle, GUILayout.Width(45));
|
||||
DrawAlertCount(alertsToShow);
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
if (showAlertDetails)
|
||||
{
|
||||
DrawAlerts(alertsToShow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Micro SDK Partners
|
||||
if (pluginData != null && !MaxSdkUtils.IsNullOrEmpty(pluginData.PartnerMicroSdks))
|
||||
{
|
||||
DrawCollapsibleSection(KeyShowMicroSdkPartners, "AppLovin Micro SDK Partners", DrawPartnerMicroSdks);
|
||||
}
|
||||
|
||||
// Draw mediated networks);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
var showDetails = DrawExpandCollapseButton(keyShowMediatedNetworks);
|
||||
var showDetails = DrawExpandCollapseButton(KeyShowMediatedNetworks);
|
||||
EditorGUILayout.LabelField("Mediated Networks", titleLabelStyle);
|
||||
GUILayout.FlexibleSpace();
|
||||
DrawUpgradeAllButton();
|
||||
@@ -241,22 +260,28 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
DrawMediatedNetworks();
|
||||
}
|
||||
|
||||
if (!AppLovinIntegrationManager.IsPluginInPackageManager)
|
||||
{
|
||||
EditorGUILayout.LabelField("Unity Package Manager Migration", titleLabelStyle);
|
||||
DrawPluginMigrationHelper();
|
||||
}
|
||||
|
||||
// Draw AppLovin Quality Service settings
|
||||
DrawCollapsableSection(keyShowSdkSettings, "SDK Settings", DrawQualityServiceSettings);
|
||||
DrawCollapsibleSection(KeyShowSdkSettings, "SDK Settings", DrawQualityServiceSettings);
|
||||
|
||||
DrawCollapsableSection(keyShowPrivacySettings, "Privacy Settings", DrawPrivacySettings);
|
||||
DrawCollapsibleSection(KeyShowPrivacySettings, "Privacy Settings", DrawPrivacySettings);
|
||||
|
||||
DrawCollapsableSection(keyShowOtherSettings, "Other Settings", DrawOtherSettings);
|
||||
DrawCollapsibleSection(KeyShowOtherSettings, "Other Settings", DrawOtherSettings);
|
||||
|
||||
// Draw Unity environment details
|
||||
EditorGUILayout.LabelField("Unity Environment Details", titleLabelStyle);
|
||||
DrawUnityEnvironmentDetails();
|
||||
|
||||
// Draw documentation notes
|
||||
EditorGUILayout.LabelField(new GUIContent(documentationNote), wrapTextLabelStyle);
|
||||
if (GUILayout.Button(new GUIContent(documentationAdaptersLink), linkLabelStyle))
|
||||
EditorGUILayout.LabelField(new GUIContent(DocumentationNote), wrapTextLabelStyle);
|
||||
if (GUILayout.Button(new GUIContent(DocumentationAdaptersLink), linkLabelStyle))
|
||||
{
|
||||
Application.OpenURL(documentationAdaptersLink);
|
||||
Application.OpenURL(DocumentationAdaptersLink);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +310,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Failed to load plugin data. Please click retry or restart the integration manager.", titleLabelStyle);
|
||||
if (GUILayout.Button("Retry", fieldWidth))
|
||||
if (GUILayout.Button("Retry", FieldWidth))
|
||||
{
|
||||
pluginDataLoadFailed = false;
|
||||
Load();
|
||||
@@ -331,7 +356,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
var appLovinMax = pluginData.AppLovinMax;
|
||||
// Check if a newer version is available to enable the upgrade button.
|
||||
var upgradeButtonEnabled = appLovinMax.CurrentToLatestVersionComparisonResult == VersionComparisonResult.Lesser;
|
||||
var upgradeButtonEnabled = appLovinMax.CurrentToLatestVersionComparisonResult == MaxSdkUtils.VersionComparisonResult.Lesser;
|
||||
DrawPluginDetailRow("Unity 3D", appLovinMax.CurrentVersions.Unity, appLovinMax.LatestVersions.Unity);
|
||||
DrawPluginDetailRow("Android", appLovinMax.CurrentVersions.Android, appLovinMax.LatestVersions.Android);
|
||||
DrawPluginDetailRow("iOS", appLovinMax.CurrentVersions.Ios, appLovinMax.LatestVersions.Ios);
|
||||
@@ -340,10 +365,15 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUI.enabled = upgradeButtonEnabled;
|
||||
if (GUILayout.Button(new GUIContent("Upgrade"), fieldWidth))
|
||||
var action = appLovinMax.IsCurrentlyInstalling ? "Installing..." : "Upgrade";
|
||||
|
||||
GUI.enabled = upgradeButtonEnabled && !appLovinMax.IsCurrentlyInstalling;
|
||||
if (GUILayout.Button(new GUIContent(action), FieldWidth))
|
||||
{
|
||||
AppLovinEditorCoroutine.StartCoroutine(AppLovinIntegrationManager.Instance.DownloadPlugin(appLovinMax));
|
||||
// Only show "Installing..." if the plugin is in the Assets folder
|
||||
// Manifest edits don't trigger import callbacks, and UPM resolution locks the UI anyway.
|
||||
appLovinMax.IsCurrentlyInstalling = !AppLovinIntegrationManager.IsPluginInPackageManager;
|
||||
AppLovinEditorCoroutine.StartCoroutine(AppLovinPackageManager.AddNetwork(pluginData.AppLovinMax, true));
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
@@ -358,6 +388,84 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the number of each alert type next to the alert section header.
|
||||
/// </summary>
|
||||
private void DrawAlertCount(List<Alert> alerts)
|
||||
{
|
||||
if (pluginData == null) return;
|
||||
|
||||
var infoAlertsCount = alerts.Count(alert => alert.Severity == Severity.Info);
|
||||
var warningAlertsCount = alerts.Count(alert => alert.Severity == Severity.Warning);
|
||||
var errorAlertsCount = alerts.Count(alert => alert.Severity == Severity.Error);
|
||||
|
||||
GUILayout.Label(infoIcon, GUILayout.Width(20), GUILayout.Height(20));
|
||||
EditorGUILayout.LabelField(AlertCountToString(infoAlertsCount), GUILayout.Width(20));
|
||||
GUILayout.Label(warningIcon, GUILayout.Width(20), GUILayout.Height(20));
|
||||
EditorGUILayout.LabelField(AlertCountToString(warningAlertsCount), GUILayout.Width(20));
|
||||
GUILayout.Label(errorIcon, GUILayout.Width(20), GUILayout.Height(20));
|
||||
EditorGUILayout.LabelField(AlertCountToString(errorAlertsCount), GUILayout.Width(20));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the list of alerts grouped by severity.
|
||||
/// </summary>
|
||||
private void DrawAlerts(List<Alert> alerts)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(10);
|
||||
using (new EditorGUILayout.VerticalScope("box"))
|
||||
{
|
||||
DrawAlertsOfType(alerts, Severity.Error);
|
||||
DrawAlertsOfType(alerts, Severity.Warning);
|
||||
DrawAlertsOfType(alerts, Severity.Info);
|
||||
}
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawAlertsOfType(List<Alert> alerts, Severity severity)
|
||||
{
|
||||
var alertsOfType = alerts.Where(alert => alert.Severity == severity).ToList();
|
||||
foreach (var alert in alertsOfType)
|
||||
{
|
||||
DrawAlert(alert);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw a single alert.
|
||||
/// </summary>
|
||||
private void DrawAlert(Alert alert)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
using (new EditorGUILayout.VerticalScope(GUILayout.Width(20)))
|
||||
{
|
||||
GUILayout.Space(2);
|
||||
GUILayout.Label(GetSeverityIcon(alert.Severity), GUILayout.Width(20), GUILayout.Height(20));
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
GUILayout.Label(alert.Title, headerLabelStyle);
|
||||
EditorGUILayout.LabelField(alert.Message, wrapTextLabelStyle);
|
||||
if (MaxSdkUtils.IsValidString(alert.Url))
|
||||
{
|
||||
if (GUILayout.Button(new GUIContent(alert.Url), linkLabelStyle))
|
||||
{
|
||||
Application.OpenURL(alert.Url);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Space(2);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the headers for a table.
|
||||
/// </summary>
|
||||
@@ -374,7 +482,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
if (drawAction)
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Button("Actions", headerLabelStyle, fieldWidth);
|
||||
GUILayout.Button("Actions", headerLabelStyle, FieldWidth);
|
||||
GUILayout.Space(5);
|
||||
}
|
||||
}
|
||||
@@ -478,13 +586,13 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
var comparison = network.CurrentToLatestVersionComparisonResult;
|
||||
// A newer version is available
|
||||
if (comparison == VersionComparisonResult.Lesser)
|
||||
if (comparison == MaxSdkUtils.VersionComparisonResult.Lesser)
|
||||
{
|
||||
action = "Upgrade";
|
||||
isActionEnabled = true;
|
||||
}
|
||||
// Current installed version is newer than latest version from DB (beta version)
|
||||
else if (comparison == VersionComparisonResult.Greater)
|
||||
else if (comparison == MaxSdkUtils.VersionComparisonResult.Greater)
|
||||
{
|
||||
action = "Installed";
|
||||
isActionEnabled = false;
|
||||
@@ -510,18 +618,25 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
if (network.RequiresUpdate)
|
||||
{
|
||||
GUILayout.Label(new GUIContent {image = alertIcon, tooltip = "Adapter not compatible, please update to the latest version."}, iconStyle);
|
||||
GUILayout.Label(new GUIContent {image = errorIcon, tooltip = "Adapter not compatible, please update to the latest version."}, iconStyle);
|
||||
}
|
||||
else if ((network.Name.Equals("ADMOB_NETWORK") || network.Name.Equals("GOOGLE_AD_MANAGER_NETWORK")) && shouldShowGoogleWarning)
|
||||
{
|
||||
GUILayout.Label(new GUIContent {image = warningIcon, tooltip = "You may see unexpected errors if you use different versions of the AdMob and Google Ad Manager adapter SDKs."}, iconStyle);
|
||||
}
|
||||
|
||||
GUI.enabled = networkButtonsEnabled && isActionEnabled;
|
||||
if (GUILayout.Button(new GUIContent(action), fieldWidth))
|
||||
if (network.IsCurrentlyInstalling)
|
||||
{
|
||||
// Download the plugin.
|
||||
AppLovinEditorCoroutine.StartCoroutine(AppLovinIntegrationManager.Instance.DownloadPlugin(network));
|
||||
action = "Installing...";
|
||||
}
|
||||
|
||||
GUI.enabled = networkButtonsEnabled && isActionEnabled && !network.IsCurrentlyInstalling;
|
||||
if (GUILayout.Button(new GUIContent(action), FieldWidth))
|
||||
{
|
||||
// Only show "Installing..." if the plugin is in the Assets folder
|
||||
// Manifest edits don't trigger import callbacks, and UPM resolution locks the UI anyway.
|
||||
network.IsCurrentlyInstalling = !AppLovinIntegrationManager.IsPluginInPackageManager;
|
||||
AppLovinEditorCoroutine.StartCoroutine(AppLovinPackageManager.AddNetwork(network, true));
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
@@ -530,20 +645,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUI.enabled = networkButtonsEnabled && isInstalled;
|
||||
if (GUILayout.Button(new GUIContent {image = uninstallIcon, tooltip = "Uninstall"}, iconStyle))
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Integration Manager", "Deleting " + network.Name + "...", 0.5f);
|
||||
var pluginRoot = AppLovinIntegrationManager.MediationSpecificPluginParentDirectory;
|
||||
foreach (var pluginFilePath in network.PluginFilePaths)
|
||||
{
|
||||
var filePath = Path.Combine(pluginRoot, pluginFilePath);
|
||||
FileUtil.DeleteFileOrDirectory(filePath);
|
||||
FileUtil.DeleteFileOrDirectory(filePath + ".meta");
|
||||
}
|
||||
|
||||
AppLovinIntegrationManager.UpdateCurrentVersions(network, pluginRoot);
|
||||
|
||||
// Refresh UI
|
||||
AssetDatabase.Refresh();
|
||||
EditorUtility.ClearProgressBar();
|
||||
AppLovinPackageManager.RemoveNetwork(network);
|
||||
AppLovinPackageManager.UpdateCurrentVersions(network);
|
||||
UpdateShouldShowGoogleWarningIfNeeded();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
@@ -562,11 +666,10 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
if (network.Name.Equals("ADMOB_NETWORK"))
|
||||
{
|
||||
// Show only one set of text boxes if both ADMOB and GAM are installed
|
||||
if (AppLovinIntegrationManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
if (AppLovinPackageManager.IsAdapterInstalled(pluginData, "GOOGLE_AD_MANAGER_NETWORK")) return;
|
||||
|
||||
DrawGoogleAppIdTextBox();
|
||||
}
|
||||
|
||||
// Custom integration for GAM where the user can enter the Android and iOS App IDs.
|
||||
else if (network.Name.Equals("GOOGLE_AD_MANAGER_NETWORK"))
|
||||
{
|
||||
@@ -597,7 +700,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
private void DrawUpgradeAllButton()
|
||||
{
|
||||
GUI.enabled = NetworksRequireUpgrade();
|
||||
if (GUILayout.Button(new GUIContent("Upgrade All"), upgradeAllButtonFieldWidth))
|
||||
if (GUILayout.Button(new GUIContent("Upgrade All"), UpgradeAllButtonFieldWidth))
|
||||
{
|
||||
AppLovinEditorCoroutine.StartCoroutine(UpgradeAllNetworks());
|
||||
}
|
||||
@@ -606,6 +709,53 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.Space(10);
|
||||
}
|
||||
|
||||
private void DrawPluginMigrationHelper()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(10);
|
||||
using (new EditorGUILayout.VerticalScope("box"))
|
||||
{
|
||||
GUILayout.Space(5);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
EditorGUILayout.LabelField(new GUIContent("This will migrate the AppLovin MAX Unity Plugin and adapters to the Unity Package Manager."), wrapTextLabelStyle);
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUI.enabled = true;
|
||||
GUILayout.Space(3);
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(10);
|
||||
var migrationText = "Upgrade All Adapters and Migrate to UPM";
|
||||
if (GUILayout.Button(new GUIContent(migrationText)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Migrate to UPM?",
|
||||
"Are you sure you want to migrate the SDK and adapters to UPM? This action will move both the MAX SDK and its adapters.", "Yes", "No"))
|
||||
{
|
||||
var deleteExternalDependencyManager = false;
|
||||
if (Directory.Exists(ExternalDependencyManagerPath))
|
||||
{
|
||||
deleteExternalDependencyManager = EditorUtility.DisplayDialog("External Dependency Manager Detected",
|
||||
"Our plugin includes the External Dependency Manager via the Unity Package Manager. Would you like us to automatically remove the existing External Dependency Manager folder, or would you prefer to manage it manually?", "Remove Automatically", "Manage Manually");
|
||||
}
|
||||
|
||||
AppLovinPluginMigrationHelper.MigrateToUnityPackageManager(pluginData, deleteExternalDependencyManager);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(5);
|
||||
EditorGUILayout.HelpBox("Ensure all changes are committed before migration.", MessageType.Warning);
|
||||
}
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawQualityServiceSettings()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
@@ -618,20 +768,20 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
EditorGUILayout.HelpBox(qualityServiceRequiresGradleBuildErrorMsg, MessageType.Warning);
|
||||
EditorGUILayout.HelpBox(QualityServiceRequiresGradleBuildErrorMsg, MessageType.Warning);
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(4);
|
||||
}
|
||||
|
||||
AppLovinSettings.Instance.SdkKey = DrawTextField("AppLovin SDK Key", AppLovinSettings.Instance.SdkKey, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.SdkKey = DrawTextField("AppLovin SDK Key", AppLovinSettings.Instance.SdkKey, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
GUILayout.Button("You can find your SDK key here: ", wrapTextLabelStyle, GUILayout.Width(185)); // Setting a fixed width since Unity adds arbitrary padding at the end leaving a space between link and text.
|
||||
if (GUILayout.Button(new GUIContent(appLovinSdkKeyLink), linkLabelStyle))
|
||||
if (GUILayout.Button(new GUIContent(AppLovinSdkKeyLink), linkLabelStyle))
|
||||
{
|
||||
Application.OpenURL(appLovinSdkKeyLink);
|
||||
Application.OpenURL(AppLovinSdkKeyLink);
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
@@ -687,106 +837,13 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.Space(10);
|
||||
using (new EditorGUILayout.VerticalScope("box"))
|
||||
{
|
||||
if (AppLovinSettings.Instance.ConsentFlowEnabled)
|
||||
{
|
||||
DrawTermsFlowSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawConsentFlowSettings();
|
||||
}
|
||||
DrawConsentFlowSettings();
|
||||
}
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawTermsFlowSettings()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
EditorGUILayout.HelpBox("The Terms Flow has been deprecated; switch to the MAX Terms and Privacy Policy Flow instead.", MessageType.Warning); // TODO Refine
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Switch to MAX Terms and Privacy Policy Flow"))
|
||||
{
|
||||
AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl = AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl;
|
||||
AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl = AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl;
|
||||
AppLovinInternalSettings.Instance.ConsentFlowEnabled = true;
|
||||
AppLovinSettings.Instance.ConsentFlowEnabled = false;
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(4);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
AppLovinSettings.Instance.ConsentFlowEnabled = GUILayout.Toggle(AppLovinSettings.Instance.ConsentFlowEnabled, " Enable Terms Flow");
|
||||
GUILayout.FlexibleSpace();
|
||||
GUI.enabled = AppLovinSettings.Instance.ConsentFlowEnabled;
|
||||
AppLovinSettings.Instance.ConsentFlowPlatform = (Platform) EditorGUILayout.Popup((int) AppLovinSettings.Instance.ConsentFlowPlatform, termsFlowPlatforms);
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(4);
|
||||
|
||||
AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl = DrawTextField("Privacy Policy URL", AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl = DrawTextField("Terms of Service URL (optional)", AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionEn = DrawTextField("User Tracking Usage Description (iOS only)", AppLovinSettings.Instance.UserTrackingUsageDescriptionEn, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
AppLovinSettings.Instance.UserTrackingUsageLocalizationEnabled = GUILayout.Toggle(AppLovinSettings.Instance.UserTrackingUsageLocalizationEnabled, " Localize User Tracking Usage Description (iOS only)");
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(4);
|
||||
|
||||
if (AppLovinSettings.Instance.UserTrackingUsageLocalizationEnabled)
|
||||
{
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionZhHans = DrawTextField("Chinese, Simplified (zh-Hans)", AppLovinSettings.Instance.UserTrackingUsageDescriptionZhHans, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionZhHant = DrawTextField("Chinese, Traditional (zh-Hant)", AppLovinSettings.Instance.UserTrackingUsageDescriptionZhHant, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption); // TODO: Remove new mark for next release.
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionFr = DrawTextField("French (fr)", AppLovinSettings.Instance.UserTrackingUsageDescriptionFr, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionDe = DrawTextField("German (de)", AppLovinSettings.Instance.UserTrackingUsageDescriptionDe, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionJa = DrawTextField("Japanese (ja)", AppLovinSettings.Instance.UserTrackingUsageDescriptionJa, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionKo = DrawTextField("Korean (ko)", AppLovinSettings.Instance.UserTrackingUsageDescriptionKo, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinSettings.Instance.UserTrackingUsageDescriptionEs = DrawTextField("Spanish (es)", AppLovinSettings.Instance.UserTrackingUsageDescriptionEs, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
EditorGUILayout.HelpBox("MAX may add more localized strings to this list in the future, which will set the default value of the User Tracking Usage Description string for more locales. If you are overriding these with your own custom translations, you may want to review this list whenever you upgrade the plugin to see if there are new entries you may want to customize.", MessageType.Info);
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
EditorGUILayout.HelpBox("If you have your own implementation of InfoPlist.strings localization implementation, please use that instead. Using both at the same time may cause conflicts.", MessageType.Info);
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
GUILayout.Button("Click the link below for more information about User Tracking Usage Description: ", wrapTextLabelStyle);
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
if (GUILayout.Button(new GUIContent(userTrackingUsageDescriptionDocsLink), linkLabelStyle))
|
||||
{
|
||||
Application.OpenURL(userTrackingUsageDescriptionDocsLink);
|
||||
}
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(4);
|
||||
}
|
||||
|
||||
private void DrawConsentFlowSettings()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
@@ -809,9 +866,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
if (GUILayout.Button(new GUIContent(documentationTermsAndPrivacyPolicyFlow), linkLabelStyle))
|
||||
if (GUILayout.Button(new GUIContent(DocumentationTermsAndPrivacyPolicyFlow), linkLabelStyle))
|
||||
{
|
||||
Application.OpenURL(documentationTermsAndPrivacyPolicyFlow);
|
||||
Application.OpenURL(DocumentationTermsAndPrivacyPolicyFlow);
|
||||
}
|
||||
|
||||
GUILayout.Space(4);
|
||||
@@ -819,8 +876,14 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
GUILayout.Space(8);
|
||||
|
||||
AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl = DrawTextField("Privacy Policy URL", AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl = DrawTextField("Terms of Service URL (optional)", AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl = DrawTextField("Privacy Policy URL", AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl = DrawTextField("Terms of Service URL (optional)", AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption);
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
AppLovinInternalSettings.Instance.ShouldShowTermsAndPrivacyPolicyAlertInGDPR = GUILayout.Toggle(AppLovinInternalSettings.Instance.ShouldShowTermsAndPrivacyPolicyAlertInGDPR, " Show Terms and Privacy Policy Flow when in GDPR Regions");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
@@ -837,7 +900,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.Space(4);
|
||||
|
||||
GUILayout.Space(4);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn = DrawTextField("User Tracking Usage Description", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn = DrawTextField("User Tracking Usage Description", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
@@ -847,13 +910,13 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
if (AppLovinInternalSettings.Instance.UserTrackingUsageLocalizationEnabled)
|
||||
{
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHans = DrawTextField("Chinese, Simplified (zh-Hans)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHans, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHant = DrawTextField("Chinese, Traditional (zh-Hant)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHant, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionFr = DrawTextField("French (fr)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionFr, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionDe = DrawTextField("German (de)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionDe, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionJa = DrawTextField("Japanese (ja)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionJa, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionKo = DrawTextField("Korean (ko)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionKo, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEs = DrawTextField("Spanish (es)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEs, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHans = DrawTextField("Chinese, Simplified (zh-Hans)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHans, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHant = DrawTextField("Chinese, Traditional (zh-Hant)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHant, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionFr = DrawTextField("French (fr)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionFr, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionDe = DrawTextField("German (de)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionDe, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionJa = DrawTextField("Japanese (ja)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionJa, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionKo = DrawTextField("Korean (ko)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionKo, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEs = DrawTextField("Spanish (es)", AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEs, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, isEditableTextField);
|
||||
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
@@ -871,9 +934,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
if (GUILayout.Button(new GUIContent(userTrackingUsageDescriptionDocsLink), linkLabelStyle))
|
||||
if (GUILayout.Button(new GUIContent(UserTrackingUsageDescriptionDocsLink), linkLabelStyle))
|
||||
{
|
||||
Application.OpenURL(userTrackingUsageDescriptionDocsLink);
|
||||
Application.OpenURL(UserTrackingUsageDescriptionDocsLink);
|
||||
}
|
||||
|
||||
GUILayout.Space(4);
|
||||
@@ -901,10 +964,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
GUILayout.Space(10);
|
||||
using (new EditorGUILayout.VerticalScope("box"))
|
||||
{
|
||||
GUILayout.Space(5);
|
||||
AppLovinSettings.Instance.SetAttributionReportEndpoint = DrawOtherSettingsToggle(AppLovinSettings.Instance.SetAttributionReportEndpoint, " Set Advertising Attribution Report Endpoint in Info.plist (iOS only)");
|
||||
GUILayout.Space(5);
|
||||
AppLovinSettings.Instance.AddApsSkAdNetworkIds = DrawOtherSettingsToggle(AppLovinSettings.Instance.AddApsSkAdNetworkIds, " Add Amazon Publisher Services SKAdNetworkID's");
|
||||
GUILayout.Space(5);
|
||||
var autoUpdateEnabled = DrawOtherSettingsToggle(EditorPrefs.GetBool(AppLovinAutoUpdater.KeyAutoUpdateEnabled, true), " Enable Auto Update", "Checks for AppLovin MAX plugin updates and notifies you when an update is available.");
|
||||
EditorPrefs.SetBool(AppLovinAutoUpdater.KeyAutoUpdateEnabled, autoUpdateEnabled);
|
||||
@@ -912,8 +971,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var verboseLoggingEnabled = DrawOtherSettingsToggle(EditorPrefs.GetBool(MaxSdkLogger.KeyVerboseLoggingEnabled, false), " Enable Verbose Logging");
|
||||
EditorPrefs.SetBool(MaxSdkLogger.KeyVerboseLoggingEnabled, verboseLoggingEnabled);
|
||||
GUILayout.Space(5);
|
||||
AppLovinSettings.Instance.CustomGradleVersionUrl = DrawTextField("Custom Gradle Version URL", AppLovinSettings.Instance.CustomGradleVersionUrl, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, tooltip: customGradleVersionTooltip);
|
||||
AppLovinSettings.Instance.CustomGradleToolsVersion = DrawTextField("Custom Gradle Tools Version", AppLovinSettings.Instance.CustomGradleToolsVersion, GUILayout.Width(privacySettingLabelWidth), privacySettingFieldWidthOption, tooltip: customGradleToolsVersionTooltip);
|
||||
AppLovinSettings.Instance.CustomGradleVersionUrl = DrawTextField("Custom Gradle Version URL", AppLovinSettings.Instance.CustomGradleVersionUrl, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, tooltip: CustomGradleVersionTooltip);
|
||||
AppLovinSettings.Instance.CustomGradleToolsVersion = DrawTextField("Custom Gradle Tools Version", AppLovinSettings.Instance.CustomGradleToolsVersion, GUILayout.Width(PrivacySettingLabelWidth), privacySettingFieldWidthOption, tooltip: CustomGradleToolsVersionTooltip);
|
||||
EditorGUILayout.HelpBox("This will overwrite the gradle build tools version in your base gradle template.", MessageType.Info);
|
||||
}
|
||||
|
||||
@@ -965,7 +1024,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCollapsableSection(string keyShowDetails, string label, Action drawContent)
|
||||
private void DrawCollapsibleSection(string keyShowDetails, string label, Action drawContent)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
var showDetails = DrawExpandCollapseButton(keyShowDetails);
|
||||
@@ -982,8 +1041,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
private bool DrawExpandCollapseButton(string keyShowDetails)
|
||||
{
|
||||
var showDetails = EditorPrefs.GetBool(keyShowDetails, true);
|
||||
var buttonText = showDetails ? collapseButtonText : expandButtonText;
|
||||
if (GUILayout.Button(buttonText, collapseButtonWidthOption))
|
||||
var buttonText = showDetails ? CollapseButtonText : ExpandButtonText;
|
||||
if (GUILayout.Button(buttonText, CollapseButtonWidthOption))
|
||||
{
|
||||
EditorPrefs.SetBool(keyShowDetails, !showDetails);
|
||||
}
|
||||
@@ -997,15 +1056,15 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
private void CalculateFieldWidth()
|
||||
{
|
||||
var currentWidth = position.width;
|
||||
var availableWidth = currentWidth - actionFieldWidth - 80; // NOTE: Magic number alert. This is the sum of all the spacing the fields and other UI elements.
|
||||
var networkLabelWidth = Math.Max(networkFieldMinWidth, availableWidth * networkFieldWidthPercentage);
|
||||
var availableWidth = currentWidth - ActionFieldWidth - 80; // NOTE: Magic number alert. This is the sum of all the spacing the fields and other UI elements.
|
||||
var networkLabelWidth = Math.Max(NetworkFieldMinWidth, availableWidth * NetworkFieldWidthPercentage);
|
||||
networkWidthOption = GUILayout.Width(networkLabelWidth);
|
||||
|
||||
var versionLabelWidth = Math.Max(versionFieldMinWidth, availableWidth * versionFieldWidthPercentage);
|
||||
var versionLabelWidth = Math.Max(VersionFieldMinWidth, availableWidth * VersionFieldWidthPercentage);
|
||||
versionWidthOption = GUILayout.Width(versionLabelWidth);
|
||||
|
||||
const int textFieldOtherUiElementsWidth = 55; // NOTE: Magic number alert. This is the sum of all the spacing the fields and other UI elements.
|
||||
var availableUserDescriptionTextFieldWidth = currentWidth - privacySettingLabelWidth - textFieldOtherUiElementsWidth;
|
||||
var availableUserDescriptionTextFieldWidth = currentWidth - PrivacySettingLabelWidth - textFieldOtherUiElementsWidth;
|
||||
privacySettingFieldWidthOption = GUILayout.Width(availableUserDescriptionTextFieldWidth);
|
||||
}
|
||||
|
||||
@@ -1037,31 +1096,14 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback method that will be called with progress updates when the plugin is being downloaded.
|
||||
/// </summary>
|
||||
public static void OnDownloadPluginProgress(string pluginName, float progress, bool done)
|
||||
private void OnImportPackageStarted(Network network)
|
||||
{
|
||||
// Download is complete. Clear progress bar.
|
||||
if (done)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
// Download is in progress, update progress bar.
|
||||
else
|
||||
{
|
||||
if (EditorUtility.DisplayCancelableProgressBar(windowTitle, string.Format("Downloading {0} plugin...", pluginName), progress))
|
||||
{
|
||||
AppLovinIntegrationManager.Instance.CancelDownload();
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
network.IsCurrentlyInstalling = false;
|
||||
}
|
||||
|
||||
private void OnImportPackageCompleted(Network network)
|
||||
{
|
||||
var parentDirectory = network.Name.Equals("APPLOVIN_NETWORK") ? AppLovinIntegrationManager.PluginParentDirectory : AppLovinIntegrationManager.MediationSpecificPluginParentDirectory;
|
||||
AppLovinIntegrationManager.UpdateCurrentVersions(network, parentDirectory);
|
||||
AppLovinPackageManager.UpdateCurrentVersions(network);
|
||||
|
||||
UpdateShouldShowGoogleWarningIfNeeded();
|
||||
}
|
||||
@@ -1079,7 +1121,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var googleAdManagerNetwork = networks.FirstOrDefault(foundNetwork => foundNetwork.Name.Equals("GOOGLE_AD_MANAGER_NETWORK"));
|
||||
|
||||
if (googleNetwork != null && googleAdManagerNetwork != null &&
|
||||
!string.IsNullOrEmpty(googleNetwork.CurrentVersions.Unity) && !string.IsNullOrEmpty(googleAdManagerNetwork.CurrentVersions.Unity) &&
|
||||
MaxSdkUtils.IsValidString(googleNetwork.CurrentVersions.Unity) && MaxSdkUtils.IsValidString(googleAdManagerNetwork.CurrentVersions.Unity) &&
|
||||
!googleNetwork.CurrentVersions.HasEqualSdkVersions(googleAdManagerNetwork.CurrentVersions))
|
||||
{
|
||||
shouldShowGoogleWarning = true;
|
||||
@@ -1102,9 +1144,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
var comparison = network.CurrentToLatestVersionComparisonResult;
|
||||
// A newer version is available
|
||||
if (!string.IsNullOrEmpty(network.CurrentVersions.Unity) && comparison == VersionComparisonResult.Lesser)
|
||||
if (MaxSdkUtils.IsValidString(network.CurrentVersions.Unity) && comparison == MaxSdkUtils.VersionComparisonResult.Lesser)
|
||||
{
|
||||
yield return AppLovinIntegrationManager.Instance.DownloadPlugin(network, false);
|
||||
yield return AppLovinPackageManager.AddNetwork(network, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1123,7 +1165,33 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
if (pluginData == null || pluginData.AppLovinMax.CurrentVersions == null) return false;
|
||||
|
||||
var networks = pluginData.MediatedNetworks;
|
||||
return networks.Any(network => !string.IsNullOrEmpty(network.CurrentVersions.Unity) && network.CurrentToLatestVersionComparisonResult == VersionComparisonResult.Lesser);
|
||||
return networks.Any(network => MaxSdkUtils.IsValidString(network.CurrentVersions.Unity) && network.CurrentToLatestVersionComparisonResult == MaxSdkUtils.VersionComparisonResult.Lesser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes in an int representing the count of an alert and returns it as a string or "9+" if greater than 9.
|
||||
/// </summary>
|
||||
private string AlertCountToString(int count)
|
||||
{
|
||||
return count > 9 ? "9+" : count.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the icon for the given severity type.
|
||||
/// </summary>
|
||||
private Texture2D GetSeverityIcon(Severity severity)
|
||||
{
|
||||
switch (severity)
|
||||
{
|
||||
case Severity.Info:
|
||||
return infoIcon;
|
||||
case Severity.Warning:
|
||||
return warningIcon;
|
||||
case Severity.Error:
|
||||
return errorIcon;
|
||||
default:
|
||||
return infoIcon;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// AppLovinInternalSettigns.cs
|
||||
// AppLovinInternalSettings.cs
|
||||
// AppLovin User Engagement Unity Plugin
|
||||
//
|
||||
// Created by Santosh Bagadi on 9/15/22.
|
||||
@@ -22,18 +22,19 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
private static AppLovinInternalSettings instance;
|
||||
|
||||
public const string DefaultUserTrackingDescriptionEn = "This uses device info for more personalized ads and content";
|
||||
public const string DefaultUserTrackingDescriptionDe = "Dies benutzt Gerätinformationen für relevantere Werbeinhalte";
|
||||
public const string DefaultUserTrackingDescriptionEs = "Esto utiliza la información del dispositivo para anuncios y contenido más personalizados";
|
||||
public const string DefaultUserTrackingDescriptionFr = "Cela permet d'utiliser les informations du téléphone pour afficher des contenus publicitaires plus pertinents.";
|
||||
public const string DefaultUserTrackingDescriptionJa = "これはユーザーデータをもとに、より関連性の高い広告コンテンツをお客様に提供します";
|
||||
public const string DefaultUserTrackingDescriptionKo = "보다 개인화된 광고 및 콘텐츠를 위해 기기 정보를 사용합니다.";
|
||||
public const string DefaultUserTrackingDescriptionZhHans = "我们使用设备信息来提供个性化的广告和内容。";
|
||||
public const string DefaultUserTrackingDescriptionZhHant = "我們使用設備信息來提供個性化的廣告和內容。";
|
||||
private const string DefaultUserTrackingDescriptionEn = "This uses device info for more personalized ads and content";
|
||||
private const string DefaultUserTrackingDescriptionDe = "Dies benutzt Gerätinformationen für relevantere Werbeinhalte";
|
||||
private const string DefaultUserTrackingDescriptionEs = "Esto utiliza la información del dispositivo para anuncios y contenido más personalizados";
|
||||
private const string DefaultUserTrackingDescriptionFr = "Cela permet d'utiliser les informations du téléphone pour afficher des contenus publicitaires plus pertinents.";
|
||||
private const string DefaultUserTrackingDescriptionJa = "これはユーザーデータをもとに、より関連性の高い広告コンテンツをお客様に提供します";
|
||||
private const string DefaultUserTrackingDescriptionKo = "보다 개인화된 광고 및 콘텐츠를 위해 기기 정보를 사용합니다.";
|
||||
private const string DefaultUserTrackingDescriptionZhHans = "我们使用设备信息来提供个性化的广告和内容。";
|
||||
private const string DefaultUserTrackingDescriptionZhHant = "我們使用設備信息來提供個性化的廣告和內容。";
|
||||
|
||||
[SerializeField] private bool consentFlowEnabled;
|
||||
[SerializeField] private string consentFlowPrivacyPolicyUrl = string.Empty;
|
||||
[SerializeField] private string consentFlowTermsOfServiceUrl = string.Empty;
|
||||
[SerializeField] private bool shouldShowTermsAndPrivacyPolicyAlertInGDPR;
|
||||
[SerializeField] private bool overrideDefaultUserTrackingUsageDescriptions;
|
||||
[SerializeField] private MaxSdkBase.ConsentFlowUserGeography debugUserGeography;
|
||||
[SerializeField] private string userTrackingUsageDescriptionEn = string.Empty;
|
||||
@@ -140,9 +141,18 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
set { consentFlowTermsOfServiceUrl = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to show the Terms and Privacy Policy alert in GDPR regions prior to presenting the CMP prompt.
|
||||
/// </summary>
|
||||
public bool ShouldShowTermsAndPrivacyPolicyAlertInGDPR
|
||||
{
|
||||
get { return shouldShowTermsAndPrivacyPolicyAlertInGDPR; }
|
||||
set { shouldShowTermsAndPrivacyPolicyAlertInGDPR = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in English to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see <see href="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionEn
|
||||
{
|
||||
@@ -185,7 +195,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to localize User Tracking Usage Description.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public bool UserTrackingUsageLocalizationEnabled
|
||||
{
|
||||
@@ -226,7 +236,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in German to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionDe
|
||||
{
|
||||
@@ -236,7 +246,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Spanish to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionEs
|
||||
{
|
||||
@@ -246,7 +256,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in French to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionFr
|
||||
{
|
||||
@@ -256,7 +266,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Japanese to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionJa
|
||||
{
|
||||
@@ -266,7 +276,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Korean to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionKo
|
||||
{
|
||||
@@ -276,7 +286,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Chinese (Simplified) to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionZhHans
|
||||
{
|
||||
@@ -286,7 +296,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Chinese (Traditional) to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// For more information see Apple's documentation: https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionZhHant
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ using UnityEngine;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
public class AppLovinMenuItems
|
||||
public static class AppLovinMenuItems
|
||||
{
|
||||
/**
|
||||
* The special characters at the end represent a shortcut for this action.
|
||||
@@ -31,7 +31,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
[MenuItem("AppLovin/Documentation")]
|
||||
private static void Documentation()
|
||||
{
|
||||
Application.OpenURL("https://developers.applovin.com/en/unity/overview/integration");
|
||||
Application.OpenURL("https://support.axon.ai/en/max/unity/overview/integration");
|
||||
}
|
||||
|
||||
[MenuItem("AppLovin/Contact Us")]
|
||||
|
||||
@@ -0,0 +1,614 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if !UNITY_2020_1_OR_NEWER
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using System.Xml.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.PackageManager;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
[Serializable]
|
||||
public class PackageInfo
|
||||
{
|
||||
// ReSharper disable InconsistentNaming - For JSON Deserialization
|
||||
public string Name;
|
||||
public string Version;
|
||||
}
|
||||
|
||||
public interface IPackageManagerClient
|
||||
{
|
||||
IEnumerator AddNetwork(Network network, bool showImport);
|
||||
void RemoveNetwork(Network network);
|
||||
}
|
||||
|
||||
public static class AppLovinPackageManager
|
||||
{
|
||||
private const string AppLovinMediationAmazonAdapterDependenciesPath = "Amazon/Scripts/Mediations/AppLovinMediation/Editor/Dependencies.xml";
|
||||
|
||||
private static readonly IPackageManagerClient _upmPackageManager = new AppLovinUpmPackageManager();
|
||||
private static readonly IPackageManagerClient _assetsPackageManager = new AppLovinAssetsPackageManager();
|
||||
|
||||
private static IPackageManagerClient PackageManagerClient
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppLovinIntegrationManager.IsPluginInPackageManager ? _upmPackageManager : _assetsPackageManager;
|
||||
}
|
||||
}
|
||||
|
||||
internal static PluginData PluginData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not an adapter with the given version or newer exists.
|
||||
/// </summary>
|
||||
/// <param name="adapterName">The name of the network (the root adapter folder name in "MaxSdk/Mediation/" folder.</param>
|
||||
/// <param name="iosVersion">The min iOS adapter version to check for. Can be <c>null</c> if we want to check for any version.</param>
|
||||
/// <param name="androidVersion">The min android adapter version to check for. Can be <c>null</c> if we want to check for any version.</param>
|
||||
/// <returns><c>true</c> if an adapter with the min version is installed.</returns>
|
||||
internal static bool IsAdapterInstalled(string adapterName, string iosVersion = null, string androidVersion = null)
|
||||
{
|
||||
var dependencyFilePathList = GetAssetPathListForExportPath("MaxSdk/Mediation/" + adapterName + "/Editor/Dependencies.xml");
|
||||
if (dependencyFilePathList.Count <= 0) return false;
|
||||
|
||||
var currentVersion = GetCurrentVersions(dependencyFilePathList);
|
||||
if (iosVersion != null)
|
||||
{
|
||||
var iosVersionComparison = MaxSdkUtils.CompareVersions(currentVersion.Ios, iosVersion);
|
||||
if (iosVersionComparison == MaxSdkUtils.VersionComparisonResult.Lesser)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (androidVersion != null)
|
||||
{
|
||||
var androidVersionComparison = MaxSdkUtils.CompareVersions(currentVersion.Android, androidVersion);
|
||||
if (androidVersionComparison == MaxSdkUtils.VersionComparisonResult.Lesser)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an adapter is installed using the plugin data.
|
||||
/// </summary>
|
||||
/// <param name="pluginData">The plugin data to check for the adapter</param>
|
||||
/// <param name="adapterName">The name of the network.</param>
|
||||
/// <returns>Whether an adapter is installed in the plugin data</returns>
|
||||
internal static bool IsAdapterInstalled(PluginData pluginData, string adapterName)
|
||||
{
|
||||
var network = pluginData.MediatedNetworks.Where(mediatedNetwork => mediatedNetwork.Name.Equals(adapterName)).ToList().FirstOrDefault();
|
||||
var networkVersion = network != null ? network.CurrentVersions : null;
|
||||
var currentVersion = networkVersion != null ? networkVersion.Unity : "";
|
||||
|
||||
return MaxSdkUtils.IsValidString(currentVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mediation networks that are currently installed in the project. If using UPM, checks
|
||||
/// for networks in Packages folder and Mediation folder in case a custom adapter was added to the project.
|
||||
/// </summary>
|
||||
/// <returns>A list of the installed mediation network names.</returns>
|
||||
internal static List<string> GetInstalledMediationNetworks()
|
||||
{
|
||||
var installedNetworks = new List<string>();
|
||||
var installedNetworksInAssets = AppLovinAssetsPackageManager.GetInstalledMediationNetworks();
|
||||
installedNetworks.AddRange(installedNetworksInAssets);
|
||||
|
||||
var installedNetworksInPackages = AppLovinUpmPackageManager.GetInstalledMediationNetworks();
|
||||
installedNetworks.AddRange(installedNetworksInPackages);
|
||||
|
||||
if (IsAmazonAppLovinAdapterInstalled())
|
||||
{
|
||||
installedNetworks.Add("AmazonAdMarketplace");
|
||||
}
|
||||
|
||||
return installedNetworks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a network to the project.
|
||||
/// </summary>
|
||||
/// <param name="network">The network to add.</param>
|
||||
/// <param name="showImport">Whether to show the import window (only for non UPM)</param>
|
||||
internal static IEnumerator AddNetwork(Network network, bool showImport)
|
||||
{
|
||||
yield return PackageManagerClient.AddNetwork(network, showImport);
|
||||
|
||||
AppLovinEditorCoroutine.StartCoroutine(RefreshAssetsAtEndOfFrame(network));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a network from the project.
|
||||
/// </summary>
|
||||
/// <param name="network">The network to remove.</param>
|
||||
internal static void RemoveNetwork(Network network)
|
||||
{
|
||||
PackageManagerClient.RemoveNetwork(network);
|
||||
|
||||
AppLovinEditorCoroutine.StartCoroutine(RefreshAssetsAtEndOfFrame(network));
|
||||
}
|
||||
|
||||
#region Utility
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all asset paths for a given MAX plugin export path.
|
||||
/// </summary>
|
||||
/// <param name="exportPath">The actual exported path of the asset.</param>
|
||||
/// <returns>The exported path of the MAX plugin asset or an empty list if the asset is not found.</returns>
|
||||
private static List<string> GetAssetPathListForExportPath(string exportPath)
|
||||
{
|
||||
var assetLabelToFind = "l:al_max_export_path-" + MaxSdkUtils.NormalizeToUnityPath(exportPath);
|
||||
var assetGuids = AssetDatabase.FindAssets(assetLabelToFind);
|
||||
|
||||
var assetPaths = new List<string>();
|
||||
foreach (var assetGuid in assetGuids)
|
||||
{
|
||||
assetPaths.Add(AssetDatabase.GUIDToAssetPath(assetGuid));
|
||||
}
|
||||
|
||||
return assetPaths.Count <= 0 ? new List<string>() : assetPaths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the CurrentVersion fields for a given network data object.
|
||||
/// </summary>
|
||||
/// <param name="network">Network for which to update the current versions.</param>
|
||||
internal static void UpdateCurrentVersions(Network network)
|
||||
{
|
||||
var assetPaths = GetAssetPathListForExportPath(network.DependenciesFilePath);
|
||||
if (HasDuplicateAdapters(assetPaths))
|
||||
{
|
||||
ShowDeleteDuplicateAdapterPrompt(network);
|
||||
}
|
||||
|
||||
var currentVersions = GetCurrentVersions(assetPaths);
|
||||
network.CurrentVersions = currentVersions;
|
||||
|
||||
// If AppLovin mediation plugin, get the version from MaxSdk and the latest and current version comparison.
|
||||
if (network.Name.Equals("APPLOVIN_NETWORK"))
|
||||
{
|
||||
network.CurrentVersions.Unity = MaxSdk.Version;
|
||||
|
||||
var unityVersionComparison = MaxSdkUtils.CompareVersions(network.CurrentVersions.Unity, network.LatestVersions.Unity);
|
||||
var androidVersionComparison = MaxSdkUtils.CompareVersions(network.CurrentVersions.Android, network.LatestVersions.Android);
|
||||
var iosVersionComparison = MaxSdkUtils.CompareVersions(network.CurrentVersions.Ios, network.LatestVersions.Ios);
|
||||
|
||||
// Overall version is same if all the current and latest (from db) versions are same.
|
||||
if (unityVersionComparison == MaxSdkUtils.VersionComparisonResult.Equal &&
|
||||
androidVersionComparison == MaxSdkUtils.VersionComparisonResult.Equal &&
|
||||
iosVersionComparison == MaxSdkUtils.VersionComparisonResult.Equal)
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = MaxSdkUtils.VersionComparisonResult.Equal;
|
||||
}
|
||||
// One of the installed versions is newer than the latest versions which means that the publisher is on a beta version.
|
||||
else if (unityVersionComparison == MaxSdkUtils.VersionComparisonResult.Greater ||
|
||||
androidVersionComparison == MaxSdkUtils.VersionComparisonResult.Greater ||
|
||||
iosVersionComparison == MaxSdkUtils.VersionComparisonResult.Greater)
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = MaxSdkUtils.VersionComparisonResult.Greater;
|
||||
}
|
||||
// We have a new version available if all Android, iOS and Unity has a newer version available in db.
|
||||
else
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = MaxSdkUtils.VersionComparisonResult.Lesser;
|
||||
}
|
||||
}
|
||||
// For all other mediation adapters, get the version comparison using their Unity versions.
|
||||
else
|
||||
{
|
||||
// If adapter is indeed installed, compare the current (installed) and the latest (from db) versions, so that we can determine if the publisher is on an older, current or a newer version of the adapter.
|
||||
// If the publisher is on a newer version of the adapter than the db version, that means they are on a beta version.
|
||||
if (MaxSdkUtils.IsValidString(currentVersions.Unity))
|
||||
{
|
||||
network.CurrentToLatestVersionComparisonResult = AppLovinIntegrationManagerUtils.CompareUnityMediationVersions(currentVersions.Unity, network.LatestVersions.Unity);
|
||||
}
|
||||
|
||||
if (MaxSdkUtils.IsValidString(network.CurrentVersions.Unity) && AppLovinAutoUpdater.MinAdapterVersions.ContainsKey(network.Name))
|
||||
{
|
||||
var comparisonResult = AppLovinIntegrationManagerUtils.CompareUnityMediationVersions(network.CurrentVersions.Unity, AppLovinAutoUpdater.MinAdapterVersions[network.Name]);
|
||||
// Requires update if current version is lower than the min required version.
|
||||
network.RequiresUpdate = comparisonResult < 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset value so that the Integration manager can hide the alert icon once adapter is updated.
|
||||
network.RequiresUpdate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a network has duplicate adapters installed in both the Assets folder and via UPM.
|
||||
/// </summary>
|
||||
/// <param name="dependencyPaths">The list of paths to the dependencies.xml files</param>
|
||||
/// <returns><c>True</c> if there are adapters in both the Assets folder and installed via UPM</returns>
|
||||
private static bool HasDuplicateAdapters(List<string> dependencyPaths)
|
||||
{
|
||||
var inPackagesFolder = dependencyPaths.Any(path => path.Contains("Packages"));
|
||||
var inAssetsFolder = dependencyPaths.Any(path => path.Contains("Assets"));
|
||||
|
||||
return inPackagesFolder && inAssetsFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt informing the user that duplicate adapters were detected
|
||||
/// and allows them to choose which version to keep.
|
||||
/// </summary>
|
||||
/// <param name="network">The network that has duplicate adapters installed.</param>
|
||||
private static void ShowDeleteDuplicateAdapterPrompt(Network network)
|
||||
{
|
||||
var keepAssetsAdapter = EditorUtility.DisplayDialog("Duplicate Adapters Detected",
|
||||
"The " + network.DisplayName + " adapter is installed in both the Assets folder and via UPM. Please choose which version to keep.",
|
||||
"Keep Assets Folder Version",
|
||||
"Keep UPM Version");
|
||||
DeleteDuplicateAdapter(network, keepAssetsAdapter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a duplicate adapter by either deleting it from the Assets folder
|
||||
/// or uninstalling it from the Unity Package Manager (UPM).
|
||||
/// </summary>
|
||||
/// <param name="network">The network for which the duplicate adapter is being removed.</param>
|
||||
/// <param name="keepAssetsAdapter">If <c>true</c>, retains the adapter in the Assets folder and removes the UPM version;
|
||||
/// otherwise, deletes the adapter from the Assets folder.</param>
|
||||
internal static void DeleteDuplicateAdapter(Network network, bool keepAssetsAdapter)
|
||||
{
|
||||
// Skip duplicate removal logic for our plugin.
|
||||
if (network.Name.Equals("APPLOVIN_NETWORK")) return;
|
||||
|
||||
if (keepAssetsAdapter)
|
||||
{
|
||||
var appLovinManifest = AppLovinUpmManifest.Load();
|
||||
AppLovinUpmPackageManager.RemovePackages(network, appLovinManifest);
|
||||
appLovinManifest.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var pluginFilePath in network.PluginFilePaths)
|
||||
{
|
||||
var filePath = Path.Combine(AppLovinIntegrationManager.MediationDirectory, pluginFilePath.Replace("MaxSdk/Mediation/", ""));
|
||||
FileUtil.DeleteFileOrDirectory(filePath);
|
||||
FileUtil.DeleteFileOrDirectory(filePath + ".meta");
|
||||
}
|
||||
}
|
||||
|
||||
AppLovinUpmPackageManager.ResolvePackageManager();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current versions for a given network's dependency file paths. UPM will have multiple paths
|
||||
/// for each network - one each for iOS and Android.
|
||||
/// </summary>
|
||||
/// <param name="dependencyPaths">A list of dependency file paths to extract current versions from.</param>
|
||||
/// <returns>Current versions of a given network's dependency files.</returns>
|
||||
private static Versions GetCurrentVersions(List<string> dependencyPaths)
|
||||
{
|
||||
var currentVersions = new Versions();
|
||||
foreach (var dependencyPath in dependencyPaths)
|
||||
{
|
||||
GetCurrentVersion(currentVersions, dependencyPath);
|
||||
}
|
||||
|
||||
if (currentVersions.Android != null && currentVersions.Ios != null)
|
||||
{
|
||||
currentVersions.Unity = "android_" + currentVersions.Android + "_ios_" + currentVersions.Ios;
|
||||
}
|
||||
else if (currentVersions.Android != null)
|
||||
{
|
||||
currentVersions.Unity = "android_" + currentVersions.Android;
|
||||
}
|
||||
else if (currentVersions.Ios != null)
|
||||
{
|
||||
currentVersions.Unity = "ios_" + currentVersions.Ios;
|
||||
}
|
||||
|
||||
return currentVersions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the current version of a network from its dependency.xml file.
|
||||
/// </summary>
|
||||
/// <param name="currentVersions">The Versions object we are using.</param>
|
||||
/// <param name="dependencyPath">The path to the dependency.xml file.</param>
|
||||
private static void GetCurrentVersion(Versions currentVersions, string dependencyPath)
|
||||
{
|
||||
XDocument dependency;
|
||||
try
|
||||
{
|
||||
dependency = XDocument.Load(dependencyPath);
|
||||
}
|
||||
#pragma warning disable 0168
|
||||
catch (IOException exception)
|
||||
#pragma warning restore 0168
|
||||
{
|
||||
// Couldn't find the dependencies file. The plugin is not installed.
|
||||
return;
|
||||
}
|
||||
|
||||
// <dependencies>
|
||||
// <androidPackages>
|
||||
// <androidPackage spec="com.applovin.mediation:network_name-adapter:1.2.3.4" />
|
||||
// </androidPackages>
|
||||
// <iosPods>
|
||||
// <iosPod name="AppLovinMediationNetworkNameAdapter" version="2.3.4.5" />
|
||||
// </iosPods>
|
||||
// </dependencies>
|
||||
string androidVersion = null;
|
||||
string iosVersion = null;
|
||||
var dependenciesElement = dependency.Element("dependencies");
|
||||
if (dependenciesElement != null)
|
||||
{
|
||||
var androidPackages = dependenciesElement.Element("androidPackages");
|
||||
if (androidPackages != null)
|
||||
{
|
||||
var adapterPackage = androidPackages.Descendants().FirstOrDefault(element => element.Name.LocalName.Equals("androidPackage")
|
||||
&& element.FirstAttribute.Name.LocalName.Equals("spec")
|
||||
&& element.FirstAttribute.Value.StartsWith("com.applovin"));
|
||||
if (adapterPackage != null)
|
||||
{
|
||||
androidVersion = adapterPackage.FirstAttribute.Value.Split(':').Last();
|
||||
// Hack alert: Some Android versions might have square brackets to force a specific version. Remove them if they are detected.
|
||||
if (androidVersion.StartsWith("["))
|
||||
{
|
||||
androidVersion = androidVersion.Trim('[', ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var iosPods = dependenciesElement.Element("iosPods");
|
||||
if (iosPods != null)
|
||||
{
|
||||
var adapterPod = iosPods.Descendants().FirstOrDefault(element => element.Name.LocalName.Equals("iosPod")
|
||||
&& element.FirstAttribute.Name.LocalName.Equals("name")
|
||||
&& element.FirstAttribute.Value.StartsWith("AppLovin"));
|
||||
if (adapterPod != null)
|
||||
{
|
||||
iosVersion = adapterPod.Attributes().First(attribute => attribute.Name.LocalName.Equals("version")).Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (androidVersion != null)
|
||||
{
|
||||
currentVersions.Android = androidVersion;
|
||||
}
|
||||
|
||||
if (iosVersion != null)
|
||||
{
|
||||
currentVersions.Ios = iosVersion;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for the Amazon AppLovin adapter in the project.
|
||||
/// </summary>
|
||||
/// <returns>Whether the AppLovin Adapter is installed through the Amazon SDK.</returns>
|
||||
private static bool IsAmazonAppLovinAdapterInstalled()
|
||||
{
|
||||
string[] dependenciesFiles = AssetDatabase.FindAssets("t:TextAsset Dependencies", new[] {"Assets"})
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.ToArray();
|
||||
|
||||
// Use regex to search for Amazon and then AppLovin in the file paths of the dependencies.xml files.
|
||||
return dependenciesFiles.Any(filePath => filePath.Contains(AppLovinMediationAmazonAdapterDependenciesPath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh assets and update current versions after a slight delay to allow for Client.Resolve to finish.
|
||||
/// </summary>
|
||||
/// <param name="network">The network that was just installed/removed.</param>
|
||||
private static IEnumerator RefreshAssetsAtEndOfFrame(Network network)
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
UpdateCurrentVersions(network);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class AppLovinUpmPackageManager : IPackageManagerClient
|
||||
{
|
||||
public const string PackageNamePrefixAppLovin = "com.applovin.mediation.ads";
|
||||
private const string PackageNamePrefixNetwork = "com.applovin.mediation.adapters";
|
||||
private const string PackageNamePrefixDsp = "com.applovin.mediation.dsp";
|
||||
|
||||
private const float TimeoutFetchPackageCollectionSeconds = 10f;
|
||||
|
||||
#if !UNITY_2020_1_OR_NEWER
|
||||
private static Type packageManagerClientType;
|
||||
private static MethodInfo packageManagerResolveMethod;
|
||||
#endif
|
||||
|
||||
public static List<string> GetInstalledMediationNetworks()
|
||||
{
|
||||
// Return empty list if we failed to get the package list
|
||||
var packageCollection = GetPackageCollectionSync(TimeoutFetchPackageCollectionSeconds);
|
||||
if (packageCollection == null)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
return packageCollection.Where(package => package.name.StartsWith(PackageNamePrefixNetwork) || package.name.StartsWith(PackageNamePrefixDsp))
|
||||
.SelectMany(package => package.keywords)
|
||||
.Where(keyword => keyword.StartsWith("dir:"))
|
||||
.Select(keyword => keyword.Replace("dir:", ""))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public IEnumerator AddNetwork(Network network, bool showImport)
|
||||
{
|
||||
var appLovinManifest = AppLovinUpmManifest.Load();
|
||||
AddPackages(network, appLovinManifest);
|
||||
appLovinManifest.Save();
|
||||
|
||||
// Remove any versions of the adapter in the Assets folder
|
||||
AppLovinPackageManager.DeleteDuplicateAdapter(network, false);
|
||||
ResolvePackageManager();
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
public void RemoveNetwork(Network network)
|
||||
{
|
||||
var appLovinManifest = AppLovinUpmManifest.Load();
|
||||
RemovePackages(network, appLovinManifest);
|
||||
appLovinManifest.Save();
|
||||
ResolvePackageManager();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a network's packages to the package manager removes any beta version that exists
|
||||
/// </summary>
|
||||
/// <param name="network">The network to add.</param>
|
||||
/// <param name="appLovinManifest">The AppLovinUpmManifest instance to edit</param>
|
||||
internal static void AddPackages(Network network, AppLovinUpmManifest appLovinManifest)
|
||||
{
|
||||
foreach (var packageInfo in network.Packages)
|
||||
{
|
||||
appLovinManifest.AddPackageDependency(packageInfo.Name, packageInfo.Version);
|
||||
RemoveBetaPackage(packageInfo.Name, appLovinManifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a network's packages from the package manager
|
||||
/// </summary>
|
||||
/// <param name="network">The network to add.</param>
|
||||
/// <param name="appLovinManifest">The AppLovinUpmManifest instance to edit</param>
|
||||
internal static void RemovePackages(Network network, AppLovinUpmManifest appLovinManifest)
|
||||
{
|
||||
foreach (var packageInfo in network.Packages)
|
||||
{
|
||||
appLovinManifest.RemovePackageDependency(packageInfo.Name);
|
||||
RemoveBetaPackage(packageInfo.Name, appLovinManifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the beta version of a package name
|
||||
/// </summary>
|
||||
/// <param name="packageName">The name of the package to remove a beta for</param>
|
||||
/// <param name="appLovinManifest">The AppLovinUpmManifest instance to edit</param>
|
||||
private static void RemoveBetaPackage(string packageName, AppLovinUpmManifest appLovinManifest)
|
||||
{
|
||||
var prefix = "";
|
||||
if (packageName.Contains(PackageNamePrefixNetwork))
|
||||
{
|
||||
prefix = PackageNamePrefixNetwork;
|
||||
}
|
||||
else if (packageName.Contains(PackageNamePrefixDsp))
|
||||
{
|
||||
prefix = PackageNamePrefixDsp;
|
||||
}
|
||||
else if (packageName.Contains(PackageNamePrefixAppLovin))
|
||||
{
|
||||
prefix = PackageNamePrefixAppLovin;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var betaPackageName = packageName.Replace(prefix, prefix + ".beta");
|
||||
appLovinManifest.RemovePackageDependency(betaPackageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the Unity Package Manager so any changes made to the manifest.json file are reflected in the Unity Editor.
|
||||
/// </summary>
|
||||
internal static void ResolvePackageManager()
|
||||
{
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
Client.Resolve();
|
||||
#else
|
||||
packageManagerClientType = packageManagerClientType ?? typeof(Client);
|
||||
if (packageManagerClientType != null)
|
||||
{
|
||||
packageManagerResolveMethod = packageManagerResolveMethod ?? packageManagerClientType.GetMethod("Resolve", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
}
|
||||
|
||||
if (packageManagerResolveMethod != null)
|
||||
{
|
||||
packageManagerResolveMethod.Invoke(null, null);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the PackageCollection from the Unity Package Manager synchronously.
|
||||
/// </summary>
|
||||
/// <param name="timeoutSeconds">How long to wait before exiting with a timeout error</param>
|
||||
/// <returns></returns>
|
||||
private static PackageCollection GetPackageCollectionSync(float timeoutSeconds = -1)
|
||||
{
|
||||
var request = Client.List();
|
||||
|
||||
// Just wait till the request is complete
|
||||
var now = DateTime.Now;
|
||||
while (!request.IsCompleted)
|
||||
{
|
||||
// Wait indefinitely if there is no timeout set.
|
||||
if (timeoutSeconds < 0) continue;
|
||||
|
||||
var delta = DateTime.Now - now;
|
||||
if (delta.TotalSeconds > timeoutSeconds)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to list UPM packages: Timeout");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!request.IsCompleted)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (request.Status >= StatusCode.Failure)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to list packages: " + request.Error.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (request.Status == StatusCode.Success) ? request.Result : null;
|
||||
}
|
||||
}
|
||||
|
||||
public class AppLovinAssetsPackageManager : IPackageManagerClient
|
||||
{
|
||||
public static List<string> GetInstalledMediationNetworks()
|
||||
{
|
||||
var maxMediationDirectory = AppLovinIntegrationManager.MediationDirectory;
|
||||
if (!Directory.Exists(maxMediationDirectory)) return new List<string>();
|
||||
|
||||
var mediationNetworkDirectories = Directory.GetDirectories(maxMediationDirectory);
|
||||
return mediationNetworkDirectories.Select(Path.GetFileName).ToList();
|
||||
}
|
||||
|
||||
public IEnumerator AddNetwork(Network network, bool showImport)
|
||||
{
|
||||
yield return AppLovinIntegrationManager.Instance.DownloadPlugin(network, showImport);
|
||||
}
|
||||
|
||||
public void RemoveNetwork(Network network)
|
||||
{
|
||||
foreach (var pluginFilePath in network.PluginFilePaths)
|
||||
{
|
||||
var filePath = Path.Combine(AppLovinIntegrationManager.PluginParentDirectory, pluginFilePath);
|
||||
FileUtil.DeleteFileOrDirectory(filePath);
|
||||
FileUtil.DeleteFileOrDirectory(filePath + ".meta");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69faa9dfd9aac483daa24261a3e11206
|
||||
labels:
|
||||
- al_max
|
||||
- al_max_export_path-MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPackageManager.cs
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,166 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Moves our SDK Unity Plugin from under the Assets folder to the Unity Package Manager.
|
||||
/// </summary>
|
||||
public static class AppLovinPluginMigrationHelper
|
||||
{
|
||||
private const string ApplovinRegistryName = "AppLovin MAX Unity";
|
||||
private const string ApplovinRegistryUrl = "https://unity.packages.applovin.com/";
|
||||
private static readonly List<string> AppLovinRegistryScopes = new List<string>() {"com.applovin.mediation.ads", "com.applovin.mediation.adapters", "com.applovin.mediation.dsp"};
|
||||
|
||||
private const string OpenUpmRegistryName = "package.openupm.com";
|
||||
private const string OpenUpmRegistryUrl = "https://package.openupm.com";
|
||||
private static readonly List<string> OpenUpmRegistryScopes = new List<string>() {"com.google.external-dependency-manager"};
|
||||
|
||||
private static List<string> betaNetworkPluginFilePaths = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move the Unity plugin to UPM by adding the AppLovin scoped registry and dependencies to the manifest.
|
||||
/// </summary>
|
||||
/// <param name="pluginData">The Unity Plugin data for our sdk and mediation adapters.</param>
|
||||
/// <param name="deleteExternalDependencyManager">Whether to delete the EDM folder under "Assets"</param>
|
||||
internal static void MigrateToUnityPackageManager(PluginData pluginData, bool deleteExternalDependencyManager)
|
||||
{
|
||||
MaxSdkLogger.UserDebug("Moving AppLovin Unity Plugin to package manager");
|
||||
|
||||
if (deleteExternalDependencyManager)
|
||||
{
|
||||
DeleteExternalDependencyManager();
|
||||
}
|
||||
|
||||
var appLovinManifest = AppLovinUpmManifest.Load();
|
||||
|
||||
MigrateAdapters(pluginData, appLovinManifest);
|
||||
MigratePlugin(pluginData, appLovinManifest);
|
||||
|
||||
appLovinManifest.Save();
|
||||
AppLovinUpmPackageManager.ResolvePackageManager();
|
||||
DeletePluginFiles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add all currently installed networks to the manifest.
|
||||
/// </summary>
|
||||
internal static void MigrateAdapters(PluginData pluginData, AppLovinUpmManifest appLovinManifest)
|
||||
{
|
||||
var allNetworks = pluginData.MediatedNetworks.Concat(pluginData.PartnerMicroSdks).ToArray();
|
||||
betaNetworkPluginFilePaths.Clear();
|
||||
|
||||
// Add every currently installed network and separate it by android and iOS.
|
||||
foreach (var network in allNetworks)
|
||||
{
|
||||
var currentVersion = network.CurrentVersions != null ? network.CurrentVersions.Unity : "";
|
||||
if (string.IsNullOrEmpty(currentVersion)) continue;
|
||||
|
||||
if (currentVersion.Contains("beta"))
|
||||
{
|
||||
betaNetworkPluginFilePaths.AddRange(network.PluginFilePaths);
|
||||
continue;
|
||||
}
|
||||
|
||||
AppLovinUpmPackageManager.AddPackages(network, appLovinManifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the AppLovin scoped registry to the manifest if it doesn't exist. Otherwise update it.
|
||||
/// </summary>
|
||||
private static void MigratePlugin(PluginData pluginData, AppLovinUpmManifest appLovinManifest)
|
||||
{
|
||||
appLovinManifest.AddOrUpdateRegistry(ApplovinRegistryName, ApplovinRegistryUrl, AppLovinRegistryScopes);
|
||||
appLovinManifest.AddOrUpdateRegistry(OpenUpmRegistryName, OpenUpmRegistryUrl, OpenUpmRegistryScopes);
|
||||
|
||||
var appLovinVersion = pluginData.AppLovinMax.LatestVersions.Unity;
|
||||
appLovinManifest.AddPackageDependency(AppLovinUpmPackageManager.PackageNamePrefixAppLovin, appLovinVersion);
|
||||
}
|
||||
|
||||
#region Utility
|
||||
|
||||
/// <summary>
|
||||
/// Delete the external dependency manager folder from the project.
|
||||
/// </summary>
|
||||
private static void DeleteExternalDependencyManager()
|
||||
{
|
||||
var externalDependencyManagerPath = Path.Combine(Application.dataPath, "ExternalDependencyManager");
|
||||
FileUtil.DeleteFileOrDirectory(externalDependencyManagerPath);
|
||||
FileUtil.DeleteFileOrDirectory(externalDependencyManagerPath + ".meta");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all the files in the plugin directory except the AppLovinSettings.asset file.
|
||||
/// </summary>
|
||||
private static void DeletePluginFiles()
|
||||
{
|
||||
if (AppLovinIntegrationManager.IsPluginInPackageManager) return;
|
||||
|
||||
var pluginPath = Path.Combine(AppLovinIntegrationManager.PluginParentDirectory, "MaxSdk");
|
||||
var appLovinSettingsPath = Path.Combine(pluginPath, "Resources/AppLovinSettings.asset");
|
||||
|
||||
var appLovinResourcesDirectory = Path.Combine(pluginPath, "Resources");
|
||||
var appLovinSettingsTempPath = Path.Combine(Path.GetTempPath(), "AppLovinSettings.asset");
|
||||
var appLovinMediationTempPath = Path.Combine(Path.GetTempPath(), "Mediation");
|
||||
|
||||
// Ensure there aren't any errors when moving the files due to the directories/files already existing.
|
||||
FileUtil.DeleteFileOrDirectory(appLovinSettingsTempPath);
|
||||
FileUtil.DeleteFileOrDirectory(appLovinMediationTempPath);
|
||||
|
||||
var mediationAssetsDir = Path.Combine(AppLovinIntegrationManager.PluginParentDirectory, "MaxSdk/Mediation");
|
||||
|
||||
// Move the AppLovinSettings.asset file and any beta adapters to a temporary directory.
|
||||
File.Move(appLovinSettingsPath, appLovinSettingsTempPath);
|
||||
var adapterSaved = MoveBetaAdaptersIfNeeded(mediationAssetsDir, appLovinMediationTempPath);
|
||||
|
||||
// Move the meta file if the adapter was saved to save the asset labels
|
||||
if (adapterSaved)
|
||||
{
|
||||
File.Move(mediationAssetsDir, appLovinMediationTempPath + ".meta");
|
||||
}
|
||||
|
||||
// Delete the plugin directory and then move the AppLovinSettings.asset and beta adapters back.
|
||||
FileUtil.DeleteFileOrDirectory(pluginPath);
|
||||
Directory.CreateDirectory(appLovinResourcesDirectory);
|
||||
File.Move(appLovinSettingsTempPath, appLovinSettingsPath);
|
||||
MoveBetaAdaptersIfNeeded(appLovinMediationTempPath, mediationAssetsDir);
|
||||
if (adapterSaved)
|
||||
{
|
||||
File.Move(appLovinMediationTempPath + ".meta", mediationAssetsDir);
|
||||
}
|
||||
|
||||
FileUtil.DeleteFileOrDirectory(appLovinMediationTempPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the beta adapters from a source mediation directory to a destination mediation directory.
|
||||
/// </summary>
|
||||
/// <param name="sourceMediationDirectory">The directory containing the beta adapters to be moved.</param>
|
||||
/// <param name="destinationMediationDirectory">The target directory where the beta adapters should be moved.</param>
|
||||
private static bool MoveBetaAdaptersIfNeeded(string sourceMediationDirectory, string destinationMediationDirectory)
|
||||
{
|
||||
if (betaNetworkPluginFilePaths.Count == 0 || !Directory.Exists(sourceMediationDirectory)) return false;
|
||||
|
||||
var movedAdapter = false;
|
||||
Directory.CreateDirectory(destinationMediationDirectory);
|
||||
foreach (var pluginFilePath in betaNetworkPluginFilePaths)
|
||||
{
|
||||
var sourceDirectory = Path.Combine(sourceMediationDirectory, Path.GetFileName(pluginFilePath));
|
||||
var destinationDirectory = Path.Combine(destinationMediationDirectory, Path.GetFileName(pluginFilePath));
|
||||
if (Directory.Exists(sourceDirectory))
|
||||
{
|
||||
Directory.Move(sourceDirectory, destinationDirectory);
|
||||
movedAdapter = true;
|
||||
}
|
||||
}
|
||||
|
||||
return movedAdapter;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11288612632de49b99708cdee436692c
|
||||
labels:
|
||||
- al_max
|
||||
- al_max_export_path-MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPluginMigrationHelper.cs
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -24,13 +24,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
public class AppLovinPostProcessAndroid : IPostGenerateGradleAndroidProject
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
private const string PropertyAndroidX = "android.useAndroidX";
|
||||
private const string PropertyJetifier = "android.enableJetifier";
|
||||
private const string EnableProperty = "=true";
|
||||
#endif
|
||||
private const string PropertyDexingArtifactTransform = "android.enableDexingArtifactTransform";
|
||||
private const string DisableProperty = "=false";
|
||||
|
||||
private const string KeyMetaDataAppLovinVerboseLoggingOn = "applovin.sdk.verbose_logging";
|
||||
private const string KeyMetaDataGoogleApplicationId = "com.google.android.gms.ads.APPLICATION_ID";
|
||||
@@ -44,16 +40,12 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private const string AppLovinSettingsFileName = "applovin_settings.json";
|
||||
|
||||
private const string KeyTermsFlowSettings = "terms_flow_settings";
|
||||
private const string KeyTermsFlowEnabled = "terms_flow_enabled";
|
||||
private const string KeyTermsFlowTermsOfService = "terms_flow_terms_of_service";
|
||||
private const string KeyTermsFlowPrivacyPolicy = "terms_flow_privacy_policy";
|
||||
|
||||
private const string KeySdkKey = "sdk_key";
|
||||
private const string KeyConsentFlowSettings = "consent_flow_settings";
|
||||
private const string KeyConsentFlowEnabled = "consent_flow_enabled";
|
||||
private const string KeyConsentFlowTermsOfService = "consent_flow_terms_of_service";
|
||||
private const string KeyConsentFlowPrivacyPolicy = "consent_flow_privacy_policy";
|
||||
private const string KeyConsentFlowShowTermsAndPrivacyPolicyAlertInGDPR = "consent_flow_show_terms_and_privacy_policy_alert_in_gdpr";
|
||||
private const string KeyConsentFlowDebugUserGeography = "consent_flow_debug_user_geography";
|
||||
|
||||
private const string KeyRenderOutsideSafeArea = "render_outside_safe_area";
|
||||
@@ -72,26 +64,11 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static readonly XNamespace AndroidNamespace = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
private static string PluginMediationDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
var pluginParentDir = AppLovinIntegrationManager.MediationSpecificPluginParentDirectory;
|
||||
return Path.Combine(pluginParentDir, "MaxSdk/Mediation/");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPostGenerateGradleAndroidProject(string path)
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
var rootGradleBuildFilePath = Path.Combine(path, "../build.gradle");
|
||||
var gradlePropertiesPath = Path.Combine(path, "../gradle.properties");
|
||||
var gradleWrapperPropertiesPath = Path.Combine(path, "../gradle/wrapper/gradle-wrapper.properties");
|
||||
#else
|
||||
var rootGradleBuildFilePath = Path.Combine(path, "build.gradle");
|
||||
var gradlePropertiesPath = Path.Combine(path, "gradle.properties");
|
||||
var gradleWrapperPropertiesPath = Path.Combine(path, "gradle/wrapper/gradle-wrapper.properties");
|
||||
#endif
|
||||
|
||||
UpdateGradleVersionsIfNeeded(gradleWrapperPropertiesPath, rootGradleBuildFilePath);
|
||||
|
||||
@@ -102,26 +79,13 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
var lines = File.ReadAllLines(gradlePropertiesPath);
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
// Add all properties except AndroidX, Jetifier, and DexingArtifactTransform since they may already exist. We will re-add them below.
|
||||
gradlePropertiesUpdated.AddRange(lines.Where(line => !line.Contains(PropertyAndroidX) && !line.Contains(PropertyJetifier) && !line.Contains(PropertyDexingArtifactTransform)));
|
||||
#else
|
||||
// Add all properties except DexingArtifactTransform since it may already exist. We will re-add it below.
|
||||
gradlePropertiesUpdated.AddRange(lines.Where(line => !line.Contains(PropertyDexingArtifactTransform)));
|
||||
#endif
|
||||
gradlePropertiesUpdated.AddRange(lines.Where(line => !line.Contains(PropertyAndroidX) && !line.Contains(PropertyJetifier)));
|
||||
}
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
// Enable AndroidX and Jetifier properties
|
||||
gradlePropertiesUpdated.Add(PropertyAndroidX + EnableProperty);
|
||||
gradlePropertiesUpdated.Add(PropertyJetifier + EnableProperty);
|
||||
#endif
|
||||
|
||||
// `DexingArtifactTransform` has been removed in Gradle 8+ which is the default Gradle version for Unity 6.
|
||||
#if !UNITY_6000_0_OR_NEWER
|
||||
// Disable dexing using artifact transform (it causes issues for ExoPlayer with Gradle plugin 3.5.0+)
|
||||
gradlePropertiesUpdated.Add(PropertyDexingArtifactTransform + DisableProperty);
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
@@ -139,7 +103,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
public int callbackOrder
|
||||
{
|
||||
get { return int.MaxValue; }
|
||||
get { return AppLovinPreProcess.CallbackOrder; }
|
||||
}
|
||||
|
||||
private static void ProcessAndroidManifest(string path)
|
||||
@@ -223,7 +187,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static void AddGoogleApplicationIdIfNeeded(XElement elementApplication, IEnumerable<XElement> metaDataElements)
|
||||
{
|
||||
if (!AppLovinIntegrationManager.IsAdapterInstalled("Google") && !AppLovinIntegrationManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
if (!AppLovinPackageManager.IsAdapterInstalled("Google") && !AppLovinPackageManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
|
||||
var googleApplicationIdMetaData = GetMetaDataElement(metaDataElements, KeyMetaDataGoogleApplicationId);
|
||||
var appId = AppLovinSettings.Instance.AdMobAndroidAppId;
|
||||
@@ -248,7 +212,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static void AddGoogleOptimizationFlagsIfNeeded(XElement elementApplication, IEnumerable<XElement> metaDataElements)
|
||||
{
|
||||
if (!AppLovinIntegrationManager.IsAdapterInstalled("Google") && !AppLovinIntegrationManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
if (!AppLovinPackageManager.IsAdapterInstalled("Google") && !AppLovinPackageManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
|
||||
var googleOptimizeInitializationMetaData = GetMetaDataElement(metaDataElements, KeyMetaDataGoogleOptimizeInitialization);
|
||||
// If meta data doesn't exist, add it
|
||||
@@ -267,7 +231,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static void DisableAutoInitIfNeeded(XElement elementApplication, IEnumerable<XElement> metaDataElements)
|
||||
{
|
||||
if (AppLovinIntegrationManager.IsAdapterInstalled("MobileFuse"))
|
||||
if (AppLovinPackageManager.IsAdapterInstalled("MobileFuse"))
|
||||
{
|
||||
var mobileFuseMetaData = GetMetaDataElement(metaDataElements, KeyMetaDataMobileFuseAutoInit);
|
||||
// If MobileFuse meta data doesn't exist, add it
|
||||
@@ -277,7 +241,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}
|
||||
}
|
||||
|
||||
if (AppLovinIntegrationManager.IsAdapterInstalled("MyTarget"))
|
||||
if (AppLovinPackageManager.IsAdapterInstalled("MyTarget"))
|
||||
{
|
||||
var myTargetMetaData = GetMetaDataElement(metaDataElements, KeyMetaDataMyTargetAutoInit);
|
||||
// If MyTarget meta data doesn't exist, add it
|
||||
@@ -358,15 +322,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
appLovinSdkSettings[KeySdkKey] = AppLovinSettings.Instance.SdkKey;
|
||||
appLovinSdkSettings[KeyRenderOutsideSafeArea] = PlayerSettings.Android.renderOutsideSafeArea;
|
||||
|
||||
// Add the Consent/Terms flow settings if needed.
|
||||
if (AppLovinInternalSettings.Instance.ConsentFlowEnabled)
|
||||
{
|
||||
EnableConsentFlowIfNeeded(rawResourceDirectory, appLovinSdkSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
EnableTermsFlowIfNeeded(rawResourceDirectory, appLovinSdkSettings);
|
||||
}
|
||||
// Add the Terms and Privacy Policy flow settings if needed.
|
||||
EnableConsentFlowIfNeeded(rawResourceDirectory, appLovinSdkSettings);
|
||||
|
||||
WriteAppLovinSettings(rawResourceDirectory, appLovinSdkSettings);
|
||||
}
|
||||
@@ -399,6 +356,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
consentFlowSettings[KeyConsentFlowTermsOfService] = termsOfServiceUrl;
|
||||
}
|
||||
|
||||
consentFlowSettings[KeyConsentFlowShowTermsAndPrivacyPolicyAlertInGDPR] = AppLovinInternalSettings.Instance.ShouldShowTermsAndPrivacyPolicyAlertInGDPR;
|
||||
|
||||
var debugUserGeography = AppLovinInternalSettings.Instance.DebugUserGeography;
|
||||
if (debugUserGeography == MaxSdkBase.ConsentFlowUserGeography.Gdpr)
|
||||
@@ -409,41 +368,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
applovinSdkSettings[KeyConsentFlowSettings] = consentFlowSettings;
|
||||
}
|
||||
|
||||
private static void EnableTermsFlowIfNeeded(string rawResourceDirectory, Dictionary<string, object> applovinSdkSettings)
|
||||
{
|
||||
if (AppLovinInternalSettings.Instance.ConsentFlowEnabled) return;
|
||||
|
||||
// Check if terms flow is enabled for this format. No need to create the applovin_consent_flow_settings.json if consent flow is disabled.
|
||||
var consentFlowEnabled = AppLovinSettings.Instance.ConsentFlowEnabled;
|
||||
var consentFlowPlatform = AppLovinSettings.Instance.ConsentFlowPlatform;
|
||||
if (!consentFlowEnabled || (consentFlowPlatform != Platform.All && consentFlowPlatform != Platform.Android))
|
||||
{
|
||||
RemoveAppLovinSettingsRawResourceFileIfNeeded(rawResourceDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
var privacyPolicyUrl = AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl;
|
||||
if (string.IsNullOrEmpty(privacyPolicyUrl))
|
||||
{
|
||||
AppLovinIntegrationManager.ShowBuildFailureDialog("You cannot use the AppLovin SDK's consent flow without defining a Privacy Policy URL in the AppLovin Integration Manager.");
|
||||
|
||||
// No need to update the applovin_consent_flow_settings.json here. Default consent flow state will be determined on the SDK side.
|
||||
return;
|
||||
}
|
||||
|
||||
var consentFlowSettings = new Dictionary<string, object>();
|
||||
consentFlowSettings[KeyTermsFlowEnabled] = consentFlowEnabled;
|
||||
consentFlowSettings[KeyTermsFlowPrivacyPolicy] = privacyPolicyUrl;
|
||||
|
||||
var termsOfServiceUrl = AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl;
|
||||
if (MaxSdkUtils.IsValidString(termsOfServiceUrl))
|
||||
{
|
||||
consentFlowSettings[KeyTermsFlowTermsOfService] = termsOfServiceUrl;
|
||||
}
|
||||
|
||||
applovinSdkSettings[KeyTermsFlowSettings] = consentFlowSettings;
|
||||
}
|
||||
|
||||
private static void WriteAppLovinSettingsRawResourceFile(string applovinSdkSettingsJson, string rawResourceDirectory)
|
||||
{
|
||||
if (!Directory.Exists(rawResourceDirectory))
|
||||
|
||||
+2
-21
@@ -22,20 +22,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
if (!AppLovinSettings.Instance.QualityServiceEnabled) return;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
// On Unity 2019.3+, the path returned is the path to the unityLibrary's module.
|
||||
// The AppLovin Quality Service buildscript closure related lines need to be added to the root build.gradle file.
|
||||
var rootGradleBuildFilePath = Path.Combine(path, "../build.gradle");
|
||||
var rootSettingsGradleFilePath = Path.Combine(path, "../settings.gradle");
|
||||
|
||||
// For 2022.2 and newer and 2021.3.41+
|
||||
var qualityServiceAdded = AddPluginToRootGradleBuildFile(rootGradleBuildFilePath);
|
||||
var appLovinRepositoryAdded = AddAppLovinRepository(rootSettingsGradleFilePath);
|
||||
|
||||
// For 2021.3.40 and older and 2022.0 - 2022.1.x
|
||||
var buildScriptChangesAdded = AddQualityServiceBuildScriptLines(rootGradleBuildFilePath);
|
||||
|
||||
var failedToAddPlugin = !buildScriptChangesAdded && !(qualityServiceAdded && appLovinRepositoryAdded);
|
||||
var failedToAddPlugin = !AddQualityServiceToRootGradleFile(path);
|
||||
if (failedToAddPlugin)
|
||||
{
|
||||
MaxSdkLogger.UserWarning("Failed to add AppLovin Quality Service plugin to the gradle project.");
|
||||
@@ -44,12 +31,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
// The plugin needs to be added to the application module (named launcher)
|
||||
var applicationGradleBuildFilePath = Path.Combine(path, "../launcher/build.gradle");
|
||||
#else
|
||||
// If Gradle template is enabled, we would have already updated the plugin.
|
||||
if (AppLovinIntegrationManager.GradleTemplateEnabled) return;
|
||||
|
||||
var applicationGradleBuildFilePath = Path.Combine(path, "build.gradle");
|
||||
#endif
|
||||
|
||||
if (!File.Exists(applicationGradleBuildFilePath))
|
||||
{
|
||||
@@ -62,7 +43,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
public int callbackOrder
|
||||
{
|
||||
get { return int.MaxValue; }
|
||||
get { return CallbackOrder; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using AppLovinMax.Internal;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using UnityEditor.iOS.Xcode.Extensions;
|
||||
#endif
|
||||
using UnityEditor.iOS.Xcode;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using UnityEngine.Networking;
|
||||
using VersionComparisonResult = MaxSdkUtils.VersionComparisonResult;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
@@ -36,9 +32,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
private const string OutputFileName = "AppLovinQualityServiceSetup.rb";
|
||||
|
||||
#if !UNITY_2019_3_OR_NEWER
|
||||
private const string UnityMainTargetName = "Unity-iPhone";
|
||||
#endif
|
||||
// Use a priority of 90 to have AppLovin embed frameworks after Pods are installed (EDM finishes installing Pods at priority 60) and before Firebase Crashlytics runs their scripts (at priority 100).
|
||||
private const int AppLovinEmbedFrameworksPriority = 90;
|
||||
|
||||
@@ -61,28 +54,20 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
private const string KeyConsentFlowEnabled = "ConsentFlowEnabled";
|
||||
private const string KeyConsentFlowTermsOfService = "ConsentFlowTermsOfService";
|
||||
private const string KeyConsentFlowPrivacyPolicy = "ConsentFlowPrivacyPolicy";
|
||||
private const string KeyConsentFlowShowTermsAndPrivacyPolicyAlertInGDPR = "ConsentFlowShowTermsAndPrivacyPolicyAlertInGDPR";
|
||||
private const string KeyConsentFlowDebugUserGeography = "ConsentFlowDebugUserGeography";
|
||||
|
||||
private const string KeyAppLovinSdkKeyToRemove = "AppLovinSdkKey";
|
||||
|
||||
private static readonly Regex PodfilePodLineRegex = new Regex("pod \'([^\']*)\'");
|
||||
|
||||
private static string PluginMediationDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
var pluginParentDir = AppLovinIntegrationManager.MediationSpecificPluginParentDirectory;
|
||||
return Path.Combine(pluginParentDir, "MaxSdk/Mediation/");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds AppLovin Quality Service to the iOS project once the project has been exported.
|
||||
///
|
||||
/// 1. Downloads the Quality Service ruby script.
|
||||
/// 2. Runs the script using Ruby which integrates AppLovin Quality Service to the project.
|
||||
/// </summary>
|
||||
[PostProcessBuild(int.MaxValue)] // We want to run Quality Service script last.
|
||||
[PostProcessBuild(AppLovinPreProcess.CallbackOrder)] // We want to run Quality Service script last.
|
||||
public static void OnPostProcessBuild(BuildTarget buildTarget, string buildPath)
|
||||
{
|
||||
if (!AppLovinSettings.Instance.QualityServiceEnabled) return;
|
||||
@@ -103,49 +88,40 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
return;
|
||||
}
|
||||
|
||||
// Download the ruby script needed to install Quality Service
|
||||
var downloadHandler = new DownloadHandlerFile(outputFilePath);
|
||||
var postJson = string.Format("{{\"sdk_key\" : \"{0}\"}}", sdkKey);
|
||||
var bodyRaw = Encoding.UTF8.GetBytes(postJson);
|
||||
var uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
uploadHandler.contentType = "application/json";
|
||||
|
||||
using (var unityWebRequest = new UnityWebRequest("https://api2.safedk.com/v1/build/ios_setup2"))
|
||||
var webRequestConfig = new WebRequestConfig()
|
||||
{
|
||||
unityWebRequest.method = UnityWebRequest.kHttpVerbPOST;
|
||||
unityWebRequest.downloadHandler = downloadHandler;
|
||||
unityWebRequest.uploadHandler = uploadHandler;
|
||||
var operation = unityWebRequest.SendWebRequest();
|
||||
DownloadHandler = new DownloadHandlerFile(outputFilePath),
|
||||
JsonString = string.Format("{{\"sdk_key\" : \"{0}\"}}", sdkKey),
|
||||
EndPoint = "https://api2.safedk.com/v1/build/ios_setup2",
|
||||
RequestType = WebRequestType.Post,
|
||||
};
|
||||
|
||||
// Wait for the download to complete or the request to timeout.
|
||||
while (!operation.isDone) { }
|
||||
webRequestConfig.Headers.Add("Content-Type", "application/json");
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (unityWebRequest.result != UnityWebRequest.Result.Success)
|
||||
#else
|
||||
if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
|
||||
#endif
|
||||
{
|
||||
MaxSdkLogger.UserError("AppLovin Quality Service installation failed. Failed to download script with error: " + unityWebRequest.error);
|
||||
return;
|
||||
}
|
||||
var maxWebRequest = new MaxWebRequest(webRequestConfig);
|
||||
|
||||
// Check if Ruby is installed
|
||||
var rubyVersion = AppLovinCommandLine.Run("ruby", "--version", buildPath);
|
||||
if (rubyVersion.ExitCode != 0)
|
||||
{
|
||||
MaxSdkLogger.UserError("AppLovin Quality Service installation requires Ruby. Please install Ruby, export it to your system PATH and re-export the project.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ruby is installed, run `ruby AppLovinQualityServiceSetup.rb`
|
||||
var result = AppLovinCommandLine.Run("ruby", OutputFileName, buildPath);
|
||||
|
||||
// Check if we have an error.
|
||||
if (result.ExitCode != 0) MaxSdkLogger.UserError("Failed to set up AppLovin Quality Service");
|
||||
|
||||
MaxSdkLogger.UserDebug(result.Message);
|
||||
var webResponse = maxWebRequest.SendSync();
|
||||
if (!webResponse.IsSuccess)
|
||||
{
|
||||
MaxSdkLogger.UserError("AppLovin Quality Service installation failed. Failed to download script with error: " + webResponse.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if Ruby is installed
|
||||
var rubyVersion = AppLovinCommandLine.Run("ruby", "--version", buildPath);
|
||||
if (rubyVersion.ExitCode != 0)
|
||||
{
|
||||
MaxSdkLogger.UserError("AppLovin Quality Service installation requires Ruby. Please install Ruby, export it to your system PATH and re-export the project.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ruby is installed, run `ruby AppLovinQualityServiceSetup.rb`
|
||||
var result = AppLovinCommandLine.Run("ruby", OutputFileName, buildPath);
|
||||
|
||||
// Check if we have an error.
|
||||
if (result.ExitCode != 0) MaxSdkLogger.UserError("Failed to set up AppLovin Quality Service");
|
||||
|
||||
MaxSdkLogger.UserDebug(result.Message);
|
||||
}
|
||||
|
||||
[PostProcessBuild(AppLovinEmbedFrameworksPriority)]
|
||||
@@ -155,32 +131,19 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var project = new PBXProject();
|
||||
project.ReadFromFile(projectPath);
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
var unityMainTargetGuid = project.GetUnityMainTargetGuid();
|
||||
var unityFrameworkTargetGuid = project.GetUnityFrameworkTargetGuid();
|
||||
#else
|
||||
var unityMainTargetGuid = project.TargetGuidByName(UnityMainTargetName);
|
||||
var unityFrameworkTargetGuid = project.TargetGuidByName(UnityMainTargetName);
|
||||
#endif
|
||||
|
||||
EmbedDynamicLibrariesIfNeeded(buildPath, project, unityMainTargetGuid);
|
||||
|
||||
var internalSettingsEnabled = AppLovinInternalSettings.Instance.ConsentFlowEnabled;
|
||||
var userTrackingUsageDescriptionDe = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionDe : AppLovinSettings.Instance.UserTrackingUsageDescriptionDe;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionDe, "de", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionEn = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn : AppLovinSettings.Instance.UserTrackingUsageDescriptionEn;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionEn, "en", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionEs = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEs : AppLovinSettings.Instance.UserTrackingUsageDescriptionEs;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionEs, "es", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionFr = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionFr : AppLovinSettings.Instance.UserTrackingUsageDescriptionFr;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionFr, "fr", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionJa = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionJa : AppLovinSettings.Instance.UserTrackingUsageDescriptionJa;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionJa, "ja", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionKo = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionKo : AppLovinSettings.Instance.UserTrackingUsageDescriptionKo;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionKo, "ko", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionZhHans = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHans : AppLovinSettings.Instance.UserTrackingUsageDescriptionZhHans;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionZhHans, "zh-Hans", buildPath, project, unityMainTargetGuid);
|
||||
var userTrackingUsageDescriptionZhHant = internalSettingsEnabled ? AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHant : AppLovinSettings.Instance.UserTrackingUsageDescriptionZhHant;
|
||||
LocalizeUserTrackingDescriptionIfNeeded(userTrackingUsageDescriptionZhHant, "zh-Hant", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionDe, "de", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn, "en", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEs, "es", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionFr, "fr", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionJa, "ja", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionKo, "ko", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHans, "zh-Hans", buildPath, project, unityMainTargetGuid);
|
||||
LocalizeUserTrackingDescriptionIfNeeded(AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionZhHant, "zh-Hant", buildPath, project, unityMainTargetGuid);
|
||||
|
||||
AddSwiftSupport(buildPath, project, unityFrameworkTargetGuid, unityMainTargetGuid);
|
||||
AddYandexSettingsIfNeeded(project, unityMainTargetGuid);
|
||||
@@ -197,23 +160,11 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var dynamicLibraryPathsToEmbed = GetDynamicLibraryPathsToEmbed(podsDirectory, buildPath);
|
||||
if (dynamicLibraryPathsToEmbed == null || dynamicLibraryPathsToEmbed.Count == 0) return;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
foreach (var dynamicLibraryPath in dynamicLibraryPathsToEmbed)
|
||||
{
|
||||
var fileGuid = project.AddFile(dynamicLibraryPath, dynamicLibraryPath);
|
||||
project.AddFileToEmbedFrameworks(targetGuid, fileGuid);
|
||||
}
|
||||
#else
|
||||
string runpathSearchPaths;
|
||||
runpathSearchPaths = project.GetBuildPropertyForAnyConfig(targetGuid, "LD_RUNPATH_SEARCH_PATHS");
|
||||
runpathSearchPaths += string.IsNullOrEmpty(runpathSearchPaths) ? "" : " ";
|
||||
|
||||
// Check if runtime search paths already contains the required search paths for dynamic libraries.
|
||||
if (runpathSearchPaths.Contains("@executable_path/Frameworks")) return;
|
||||
|
||||
runpathSearchPaths += "@executable_path/Frameworks";
|
||||
project.SetBuildProperty(targetGuid, "LD_RUNPATH_SEARCH_PATHS", runpathSearchPaths);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -333,13 +284,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var currentIosVersion = network.CurrentVersions.Ios;
|
||||
if (string.IsNullOrEmpty(currentIosVersion)) return false;
|
||||
|
||||
var minIosVersion = libraryToEmbed.MinVersion;
|
||||
var maxIosVersion = libraryToEmbed.MaxVersion;
|
||||
|
||||
var greaterThanOrEqualToMinVersion = string.IsNullOrEmpty(minIosVersion) || MaxSdkUtils.CompareVersions(currentIosVersion, minIosVersion) != VersionComparisonResult.Lesser;
|
||||
var lessThanOrEqualToMaxVersion = string.IsNullOrEmpty(maxIosVersion) || MaxSdkUtils.CompareVersions(currentIosVersion, maxIosVersion) != VersionComparisonResult.Greater;
|
||||
|
||||
return greaterThanOrEqualToMinVersion && lessThanOrEqualToMaxVersion;
|
||||
return MaxSdkUtils.IsVersionInRange(currentIosVersion, libraryToEmbed.MinVersion, libraryToEmbed.MaxVersion);
|
||||
}
|
||||
|
||||
private static List<string> GetDynamicLibraryPathsInProjectToEmbed(string podsDirectory, List<string> dynamicLibrariesToEmbed)
|
||||
@@ -443,11 +388,8 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
if (string.IsNullOrEmpty(localizedUserTrackingDescription)) return true;
|
||||
|
||||
var settings = AppLovinSettings.Instance;
|
||||
var internalSettings = AppLovinInternalSettings.Instance;
|
||||
|
||||
return (!internalSettings.ConsentFlowEnabled || !internalSettings.UserTrackingUsageLocalizationEnabled)
|
||||
&& (!settings.ConsentFlowEnabled || !settings.UserTrackingUsageLocalizationEnabled);
|
||||
return !internalSettings.ConsentFlowEnabled || !internalSettings.UserTrackingUsageLocalizationEnabled;
|
||||
}
|
||||
|
||||
private static void AddSwiftSupport(string buildPath, PBXProject project, string unityFrameworkTargetGuid, string unityMainTargetGuid)
|
||||
@@ -467,9 +409,19 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
project.SetBuildProperty(unityFrameworkTargetGuid, "SWIFT_VERSION", "5.0");
|
||||
}
|
||||
|
||||
// Enable Swift modules
|
||||
project.AddBuildProperty(unityFrameworkTargetGuid, "CLANG_ENABLE_MODULES", "YES");
|
||||
project.AddBuildProperty(unityMainTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
|
||||
// Some publishers may configure these settings in their own post-processing scripts.
|
||||
// Only set them if they haven't already been defined to avoid overwriting publisher-defined values.
|
||||
var enableModules = project.GetBuildPropertyForAnyConfig(unityFrameworkTargetGuid, "CLANG_ENABLE_MODULES");
|
||||
if (string.IsNullOrEmpty(enableModules))
|
||||
{
|
||||
project.SetBuildProperty(unityFrameworkTargetGuid, "CLANG_ENABLE_MODULES", "YES");
|
||||
}
|
||||
|
||||
var alwaysEmbedSwiftLibraries = project.GetBuildPropertyForAnyConfig(unityMainTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES");
|
||||
if (string.IsNullOrEmpty(alwaysEmbedSwiftLibraries))
|
||||
{
|
||||
project.SetBuildProperty(unityMainTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateSwiftFile(string swiftFilePath)
|
||||
@@ -487,43 +439,35 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
}
|
||||
}
|
||||
|
||||
[PostProcessBuild(int.MaxValue)]
|
||||
[PostProcessBuild(AppLovinPreProcess.CallbackOrder)]
|
||||
public static void MaxPostProcessPlist(BuildTarget buildTarget, string path)
|
||||
{
|
||||
var plistPath = Path.Combine(path, "Info.plist");
|
||||
var plist = new PlistDocument();
|
||||
plist.ReadFromFile(plistPath);
|
||||
|
||||
SetAttributionReportEndpointIfNeeded(plist);
|
||||
RemoveAttributionReportEndpointIfNeeded(plist);
|
||||
|
||||
EnableVerboseLoggingIfNeeded(plist);
|
||||
AddGoogleApplicationIdIfNeeded(plist);
|
||||
|
||||
AddSdkSettings(plist, path);
|
||||
EnableTermsFlowIfNeeded(plist);
|
||||
AddSkAdNetworksInfoIfNeeded(plist);
|
||||
RemoveSdkKeyIfNeeded(plist);
|
||||
|
||||
plist.WriteToFile(plistPath);
|
||||
}
|
||||
|
||||
private static void SetAttributionReportEndpointIfNeeded(PlistDocument plist)
|
||||
private static void RemoveAttributionReportEndpointIfNeeded(PlistDocument plist)
|
||||
{
|
||||
if (AppLovinSettings.Instance.SetAttributionReportEndpoint)
|
||||
{
|
||||
plist.root.SetString("NSAdvertisingAttributionReportEndpoint", AppLovinAdvertisingAttributionEndpoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlistElement attributionReportEndPoint;
|
||||
plist.root.values.TryGetValue("NSAdvertisingAttributionReportEndpoint", out attributionReportEndPoint);
|
||||
PlistElement attributionReportEndPoint;
|
||||
plist.root.values.TryGetValue("NSAdvertisingAttributionReportEndpoint", out attributionReportEndPoint);
|
||||
|
||||
// Check if we had previously set the attribution endpoint and un-set it.
|
||||
if (attributionReportEndPoint != null && AppLovinAdvertisingAttributionEndpoint.Equals(attributionReportEndPoint.AsString()))
|
||||
{
|
||||
plist.root.values.Remove("NSAdvertisingAttributionReportEndpoint");
|
||||
}
|
||||
}
|
||||
// We no longer support this feature. Check if we had previously set the attribution endpoint and un-set it.
|
||||
if (attributionReportEndPoint == null || !AppLovinAdvertisingAttributionEndpoint.Equals(attributionReportEndPoint.AsString())) return;
|
||||
|
||||
MaxSdkLogger.UserWarning("Global SKAdNetwork postback forwarding is no longer supported by AppLovin. Removing AppLovin Advertising Attribution Endpoint from Info.plist.");
|
||||
plist.root.values.Remove("NSAdvertisingAttributionReportEndpoint");
|
||||
}
|
||||
|
||||
private static void EnableVerboseLoggingIfNeeded(PlistDocument plist)
|
||||
@@ -543,7 +487,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static void AddGoogleApplicationIdIfNeeded(PlistDocument plist)
|
||||
{
|
||||
if (!AppLovinIntegrationManager.IsAdapterInstalled("Google") && !AppLovinIntegrationManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
if (!AppLovinPackageManager.IsAdapterInstalled("Google") && !AppLovinPackageManager.IsAdapterInstalled("GoogleAdManager")) return;
|
||||
|
||||
const string googleApplicationIdentifier = "GADApplicationIdentifier";
|
||||
var appId = AppLovinSettings.Instance.AdMobIosAppId;
|
||||
@@ -559,7 +503,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static void AddYandexSettingsIfNeeded(PBXProject project, string unityMainTargetGuid)
|
||||
{
|
||||
if (!AppLovinIntegrationManager.IsAdapterInstalled("Yandex")) return;
|
||||
if (!AppLovinPackageManager.IsAdapterInstalled("Yandex")) return;
|
||||
|
||||
if (MaxSdkUtils.CompareVersions(PlayerSettings.iOS.targetOSVersionString, "12.0") == MaxSdkUtils.VersionComparisonResult.Lesser)
|
||||
{
|
||||
@@ -591,13 +535,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var project = new PBXProject();
|
||||
project.ReadFromFile(projectPath);
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
var unityMainTargetGuid = project.GetUnityMainTargetGuid();
|
||||
#else
|
||||
var unityMainTargetGuid = project.TargetGuidByName(UnityMainTargetName);
|
||||
#endif
|
||||
|
||||
var guid = project.AddFile(AppLovinSettingsPlistFileName, AppLovinSettingsPlistFileName, PBXSourceTree.Source);
|
||||
var guid = project.AddFile(AppLovinSettingsPlistFileName, AppLovinSettingsPlistFileName);
|
||||
project.AddFileToBuild(unityMainTargetGuid, guid);
|
||||
project.WriteToFile(projectPath);
|
||||
}
|
||||
@@ -628,6 +568,9 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
consentFlowInfoRoot.SetString(KeyConsentFlowTermsOfService, termsOfServiceUrl);
|
||||
}
|
||||
|
||||
var shouldShowTermsAndPrivacyPolicyAlertInGdpr = AppLovinInternalSettings.Instance.ShouldShowTermsAndPrivacyPolicyAlertInGDPR;
|
||||
consentFlowInfoRoot.SetBoolean(KeyConsentFlowShowTermsAndPrivacyPolicyAlertInGDPR, shouldShowTermsAndPrivacyPolicyAlertInGdpr);
|
||||
|
||||
var debugUserGeography = AppLovinInternalSettings.Instance.DebugUserGeography;
|
||||
if (debugUserGeography == MaxSdkBase.ConsentFlowUserGeography.Gdpr)
|
||||
{
|
||||
@@ -637,40 +580,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
infoPlist.root.SetString("NSUserTrackingUsageDescription", userTrackingUsageDescription);
|
||||
}
|
||||
|
||||
private static void EnableTermsFlowIfNeeded(PlistDocument plist)
|
||||
{
|
||||
// Check if terms flow is enabled. No need to update info.plist if consent flow is disabled.
|
||||
var consentFlowEnabled = AppLovinSettings.Instance.ConsentFlowEnabled;
|
||||
if (!consentFlowEnabled) return;
|
||||
|
||||
// Check if terms flow is enabled for this format.
|
||||
var consentFlowPlatform = AppLovinSettings.Instance.ConsentFlowPlatform;
|
||||
if (consentFlowPlatform != Platform.All && consentFlowPlatform != Platform.iOS) return;
|
||||
|
||||
var userTrackingUsageDescription = AppLovinSettings.Instance.UserTrackingUsageDescriptionEn;
|
||||
var privacyPolicyUrl = AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl;
|
||||
if (string.IsNullOrEmpty(userTrackingUsageDescription) || string.IsNullOrEmpty(privacyPolicyUrl))
|
||||
{
|
||||
AppLovinIntegrationManager.ShowBuildFailureDialog("You cannot use the AppLovin SDK's consent flow without defining a Privacy Policy URL and the `User Tracking Usage Description` in the AppLovin Integration Manager. \n\n" +
|
||||
"Both values must be included to enable the SDK's consent flow.");
|
||||
|
||||
// No need to update the info.plist here. Default consent flow state will be determined on the SDK side.
|
||||
return;
|
||||
}
|
||||
|
||||
var consentFlowInfoRoot = plist.root.CreateDict("AppLovinConsentFlowInfo");
|
||||
consentFlowInfoRoot.SetBoolean("AppLovinConsentFlowEnabled", true);
|
||||
consentFlowInfoRoot.SetString("AppLovinConsentFlowPrivacyPolicy", privacyPolicyUrl);
|
||||
|
||||
var termsOfServiceUrl = AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl;
|
||||
if (!string.IsNullOrEmpty(termsOfServiceUrl))
|
||||
{
|
||||
consentFlowInfoRoot.SetString("AppLovinConsentFlowTermsOfService", termsOfServiceUrl);
|
||||
}
|
||||
|
||||
plist.root.SetString("NSUserTrackingUsageDescription", userTrackingUsageDescription);
|
||||
}
|
||||
|
||||
private static void AddSkAdNetworksInfoIfNeeded(PlistDocument plist)
|
||||
{
|
||||
var skAdNetworkData = GetSkAdNetworkData();
|
||||
@@ -731,51 +640,37 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static SkAdNetworkData GetSkAdNetworkData()
|
||||
{
|
||||
var uriBuilder = new UriBuilder("https://unity.applovin.com/max/1.0/skadnetwork_ids");
|
||||
|
||||
// Get the list of installed ad networks to be passed up
|
||||
var maxMediationDirectory = PluginMediationDirectory;
|
||||
if (Directory.Exists(maxMediationDirectory))
|
||||
var installedNetworks = AppLovinPackageManager.GetInstalledMediationNetworks();
|
||||
var uriBuilder = new UriBuilder("https://unity.applovin.com/max/1.0/skadnetwork_ids");
|
||||
var adNetworks = string.Join(",", installedNetworks.ToArray());
|
||||
if (MaxSdkUtils.IsValidString(adNetworks))
|
||||
{
|
||||
var mediationNetworkDirectories = Directory.GetDirectories(maxMediationDirectory);
|
||||
var installedNetworks = mediationNetworkDirectories.Select(Path.GetFileName).ToList();
|
||||
if (AppLovinSettings.Instance.AddApsSkAdNetworkIds)
|
||||
{
|
||||
installedNetworks.Add("AmazonAdMarketplace");
|
||||
}
|
||||
|
||||
var adNetworks = string.Join(",", installedNetworks.ToArray());
|
||||
if (!string.IsNullOrEmpty(adNetworks))
|
||||
{
|
||||
uriBuilder.Query += string.Format("ad_networks={0}", adNetworks);
|
||||
}
|
||||
uriBuilder.Query += string.Format("ad_networks={0}", adNetworks);
|
||||
}
|
||||
|
||||
using (var unityWebRequest = UnityWebRequest.Get(uriBuilder.ToString()))
|
||||
var webRequestConfig = new WebRequestConfig()
|
||||
{
|
||||
var operation = unityWebRequest.SendWebRequest();
|
||||
// Wait for the download to complete or the request to timeout.
|
||||
while (!operation.isDone) { }
|
||||
EndPoint = uriBuilder.ToString()
|
||||
};
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (unityWebRequest.result != UnityWebRequest.Result.Success)
|
||||
#else
|
||||
if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
|
||||
#endif
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to retrieve SKAdNetwork IDs with error: " + unityWebRequest.error);
|
||||
return new SkAdNetworkData();
|
||||
}
|
||||
var maxWebRequest = new MaxWebRequest(webRequestConfig);
|
||||
var webResponse = maxWebRequest.SendSync();
|
||||
|
||||
try
|
||||
{
|
||||
return JsonUtility.FromJson<SkAdNetworkData>(unityWebRequest.downloadHandler.text);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to parse data '" + unityWebRequest.downloadHandler.text + "' with exception: " + exception);
|
||||
return new SkAdNetworkData();
|
||||
}
|
||||
if (!webResponse.IsSuccess)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to retrieve SKAdNetwork IDs with error: " + webResponse.ErrorMessage);
|
||||
return new SkAdNetworkData();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonUtility.FromJson<SkAdNetworkData>(webResponse.ResponseMessage);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to parse data '" + webResponse.ResponseMessage + "' with exception: " + exception);
|
||||
return new SkAdNetworkData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,16 +7,19 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
public abstract class AppLovinPreProcess
|
||||
{
|
||||
// Use a slightly lower value than max value so pubs have the option to run a post process script after ours.
|
||||
internal const int CallbackOrder = int.MaxValue - 10;
|
||||
private const string AppLovinDependenciesFileExportPath = "MaxSdk/AppLovin/Editor/Dependencies.xml";
|
||||
private const string ElementNameDependencies = "dependencies";
|
||||
|
||||
private static readonly XmlWriterSettings DependenciesFileXmlWriterSettings = new XmlWriterSettings
|
||||
{
|
||||
@@ -26,80 +29,154 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
NewLineHandling = NewLineHandling.Replace
|
||||
};
|
||||
|
||||
protected static string AppLovinDependenciesFilePath
|
||||
{
|
||||
get { return AppLovinIntegrationManager.IsPluginInPackageManager ? Path.Combine("Assets", AppLovinDependenciesFileExportPath) : MaxSdkUtils.GetAssetPathForExportPath(AppLovinDependenciesFileExportPath); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a string into AppLovin's Dependencies.xml file inside the containerElementString if it doesn't exist
|
||||
/// Gets the AppLovin Dependencies.xml file. If `createIfNotExists` is true, a new file will be created if one does not exist.
|
||||
/// </summary>
|
||||
/// <param name="lineToAdd">The line you want to add into the xml file</param>
|
||||
/// <param name="containerElementString">The root XML element under which to add the line. For example, to add a new dependency to Android, pass in "androidPackages"</param>
|
||||
protected static void TryAddStringToDependencyFile(string lineToAdd, string containerElementString)
|
||||
/// <param name="path">The path to the AppLovin Dependencies.xml file</param>
|
||||
/// <param name="createIfNotExists">Whether to create a new Dependencies.xml file if one does not exist</param>
|
||||
/// <returns></returns>
|
||||
protected static XDocument GetAppLovinDependenciesFile(string path, bool createIfNotExists = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dependenciesFilePath = MaxSdkUtils.GetAssetPathForExportPath(AppLovinDependenciesFileExportPath);
|
||||
var dependencies = XDocument.Load(dependenciesFilePath);
|
||||
// Get the container where we are going to insert the line
|
||||
var containerElement = dependencies.Descendants(containerElementString).FirstOrDefault();
|
||||
|
||||
if (containerElement == null)
|
||||
if (File.Exists(path))
|
||||
{
|
||||
MaxSdkLogger.E(containerElementString + " not found in Dependencies.xml file");
|
||||
return;
|
||||
return XDocument.Load(path);
|
||||
}
|
||||
|
||||
var elementToAdd = XElement.Parse(lineToAdd);
|
||||
|
||||
// Check if the xml file doesn't already contain the string.
|
||||
if (containerElement.Elements().Any(element => XNode.DeepEquals(element, elementToAdd))) return;
|
||||
|
||||
// Append the new element to the container element
|
||||
containerElement.Add(elementToAdd);
|
||||
|
||||
using (var xmlWriter = XmlWriter.Create(dependenciesFilePath, DependenciesFileXmlWriterSettings))
|
||||
|
||||
if (createIfNotExists)
|
||||
{
|
||||
dependencies.Save(xmlWriter);
|
||||
return new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
|
||||
new XElement(ElementNameDependencies));
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MaxSdkLogger.UserWarning("Google CMP will not function. Unable to add string to dependency file due to exception: " + exception.Message);
|
||||
MaxSdkLogger.E("Unable to load Dependencies file due to exception: " + exception.Message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a dependency if it exists, otherwise adds a new dependency.
|
||||
/// </summary>
|
||||
/// <param name="dependenciesDocument">The dependencies document we are writing to</param>
|
||||
/// <param name="parentTag">The parent tag that we want to search for the dependency. For example, to add a new dependency to Android, pass in "androidPackages"</param>
|
||||
/// <param name="elementTag">The element we are looking to update/add. For example, to add a new dependency to Android, pass in "androidPackage"</param>
|
||||
/// <param name="matchAttribute">The attribute name we want in the dependency. For example, to add something to the spec attribute, pass in "spec" </param>
|
||||
/// <param name="matchValuePrefix">The attribute value prefix we are looking to replace. For example, "com.google.android.ump:user-messaging-platform"</param>
|
||||
/// <param name="newDependency">The new dependency we want to add.</param>
|
||||
protected static void AddOrUpdateDependency(
|
||||
XDocument dependenciesDocument,
|
||||
string parentTag,
|
||||
string elementTag,
|
||||
string matchAttribute,
|
||||
string matchValuePrefix,
|
||||
XElement newDependency)
|
||||
{
|
||||
var parentElement = dependenciesDocument.Root.Element(parentTag);
|
||||
if (parentElement == null)
|
||||
{
|
||||
parentElement = new XElement(parentTag);
|
||||
dependenciesDocument.Root.Add(parentElement);
|
||||
}
|
||||
|
||||
// Check if a dependency exists that matches the attributes name and value
|
||||
var existingElement = parentElement.Elements(elementTag)
|
||||
.FirstOrDefault(element =>
|
||||
{
|
||||
var attr = element.Attribute(matchAttribute);
|
||||
return attr != null && attr.Value.StartsWith(matchValuePrefix, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
if (existingElement != null)
|
||||
{
|
||||
foreach (var attr in newDependency.Attributes())
|
||||
{
|
||||
existingElement.SetAttributeValue(attr.Name, attr.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parentElement.Add(newDependency);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a string from AppLovin's Dependencies.xml file inside the containerElementString if it exists
|
||||
/// Removes a dependency from an xml file.
|
||||
/// </summary>
|
||||
/// <param name="lineToRemove">The line you want to remove from the xml file</param>
|
||||
/// <param name="containerElementString">The root XML element from which to remove the line. For example, to remove an Android dependency, pass in "androidPackages"</param>
|
||||
protected static void TryRemoveStringFromDependencyFile(string lineToRemove, string containerElementString)
|
||||
/// <param name="doc">The xml file to remove a dependency from</param>
|
||||
/// <param name="parentTag">The parent tag that we want to search for the dependency to remove. For example: "androidPackages"</param>
|
||||
/// <param name="elementTag">The element we are looking to remove. For example: "androidPackage"</param>
|
||||
/// <param name="matchAttribute">The attribute name we want to remove. For example: "spec" </param>
|
||||
/// <param name="matchValuePrefix">The attribute value prefix we are looking to replace. For example: "com.google.android.ump:user-messaging-platform"</param>
|
||||
/// <returns>True if the dependency was removed successfully, otherwise return false.</returns>
|
||||
protected static bool RemoveDependency(
|
||||
XDocument doc,
|
||||
string parentTag,
|
||||
string elementTag,
|
||||
string matchAttribute,
|
||||
string matchValuePrefix)
|
||||
{
|
||||
var root = doc.Root;
|
||||
if (root == null) return false;
|
||||
|
||||
var parentElement = root.Element(parentTag);
|
||||
if (parentElement == null) return false;
|
||||
|
||||
XElement toRemove = null;
|
||||
foreach (var e in parentElement.Elements(elementTag))
|
||||
{
|
||||
var attr = e.Attribute(matchAttribute);
|
||||
if (attr != null && attr.Value.StartsWith(matchValuePrefix))
|
||||
{
|
||||
toRemove = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove == null) return false;
|
||||
|
||||
toRemove.Remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves an xml file.
|
||||
/// </summary>
|
||||
/// <param name="doc">The document to save</param>
|
||||
/// <param name="path">The path to the document to save</param>
|
||||
/// <returns>Returns true if the file was saved successfully</returns>
|
||||
protected static bool SaveDependenciesFile(XDocument doc, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dependenciesFilePath = MaxSdkUtils.GetAssetPathForExportPath(AppLovinDependenciesFileExportPath);
|
||||
var dependencies = XDocument.Load(dependenciesFilePath);
|
||||
var containerElement = dependencies.Descendants(containerElementString).FirstOrDefault();
|
||||
|
||||
if (containerElement == null)
|
||||
// Ensure directory exists before saving the file
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (MaxSdkUtils.IsValidString(directory))
|
||||
{
|
||||
MaxSdkLogger.E(containerElementString + " not found in Dependencies.xml file");
|
||||
return;
|
||||
// Does nothing if directory already exists
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// Check if the dependency line exists.
|
||||
var elementToFind = XElement.Parse(lineToRemove);
|
||||
var existingElement = containerElement.Elements().FirstOrDefault(element => XNode.DeepEquals(element, elementToFind));
|
||||
if (existingElement == null) return;
|
||||
|
||||
existingElement.Remove();
|
||||
|
||||
using (var xmlWriter = XmlWriter.Create(dependenciesFilePath, DependenciesFileXmlWriterSettings))
|
||||
using (var xmlWriter = XmlWriter.Create(path, DependenciesFileXmlWriterSettings))
|
||||
{
|
||||
dependencies.Save(xmlWriter);
|
||||
doc.Save(xmlWriter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MaxSdkLogger.UserWarning("Unable to remove string from dependency file due to exception: " + exception.Message);
|
||||
MaxSdkLogger.E("Unable to save Dependencies file due to exception: " + exception.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#if UNITY_ANDROID
|
||||
|
||||
using System.Xml.Linq;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
@@ -18,9 +19,11 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
public class AppLovinPreProcessAndroid : AppLovinProcessGradleBuildFile, IPreprocessBuildWithReport
|
||||
{
|
||||
private const string UmpLegacyDependencyLine = "<androidPackage spec=\"com.google.android.ump:user-messaging-platform:2.1.0\" />";
|
||||
private const string UmpDependencyLine = "<androidPackage spec=\"com.google.android.ump:user-messaging-platform:2.+\" />";
|
||||
private const string AndroidPackagesContainerElementString = "androidPackages";
|
||||
private const string ElementNameAndroidPackages = "androidPackages";
|
||||
private const string ElementNameAndroidPackage = "androidPackage";
|
||||
private const string AttributeNameSpec = "spec";
|
||||
private const string UmpDependencyPackage = "com.google.android.ump:user-messaging-platform:";
|
||||
private const string UmpDependencyVersion = "4.0.0";
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
@@ -33,33 +36,74 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
// We can only process gradle template file here. If it is not available, we will try again in post build on Unity IDEs newer than 2018_2 (see AppLovinPostProcessGradleProject).
|
||||
if (!AppLovinIntegrationManager.GradleTemplateEnabled) return;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
// The publisher could be migrating from older Unity versions to 2019_3 or newer.
|
||||
// If so, we should delete the plugin from the template. The plugin will be added to the project's application module in the post processing script (AppLovinPostProcessGradleProject).
|
||||
RemoveAppLovinQualityServiceOrSafeDkPlugin(AppLovinIntegrationManager.GradleTemplatePath);
|
||||
#else
|
||||
AddAppLovinQualityServicePlugin(AppLovinIntegrationManager.GradleTemplatePath);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void AddGoogleCmpDependencyIfNeeded()
|
||||
{
|
||||
// Remove the legacy fixed UMP version if it exists, we'll add the dependency with a dynamic version below.
|
||||
TryRemoveStringFromDependencyFile(UmpLegacyDependencyLine, AndroidPackagesContainerElementString);
|
||||
|
||||
if (AppLovinInternalSettings.Instance.ConsentFlowEnabled)
|
||||
{
|
||||
TryAddStringToDependencyFile(UmpDependencyLine, AndroidPackagesContainerElementString);
|
||||
var umpPackage = new XElement(ElementNameAndroidPackage,
|
||||
new XAttribute(AttributeNameSpec, UmpDependencyPackage + UmpDependencyVersion));
|
||||
var success = AddOrUpdateAndroidDependency(UmpDependencyPackage, umpPackage );
|
||||
if (!success)
|
||||
{
|
||||
MaxSdkLogger.UserWarning("Google CMP will not function. Unable to add user-messaging-platform dependency.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TryRemoveStringFromDependencyFile(UmpDependencyLine, AndroidPackagesContainerElementString);
|
||||
RemoveAndroidDependency(UmpDependencyPackage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or updates an Android dependency in the AppLovin Dependencies.xml file.
|
||||
/// </summary>
|
||||
/// <param name="package">The package that we are trying to update</param>
|
||||
/// <param name="newDependency">The new dependency to add if it doesn't exist</param>
|
||||
/// <returns>Returns true if the file was successfully edited</returns>
|
||||
private static bool AddOrUpdateAndroidDependency(string package, XElement newDependency)
|
||||
{
|
||||
var dependenciesFilePath = AppLovinDependenciesFilePath;
|
||||
var dependenciesDocument = GetAppLovinDependenciesFile(dependenciesFilePath, AppLovinIntegrationManager.IsPluginInPackageManager);
|
||||
if (dependenciesDocument == null) return false;
|
||||
|
||||
AddOrUpdateDependency(dependenciesDocument,
|
||||
ElementNameAndroidPackages,
|
||||
ElementNameAndroidPackage,
|
||||
AttributeNameSpec,
|
||||
package,
|
||||
newDependency);
|
||||
return SaveDependenciesFile(dependenciesDocument, dependenciesFilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removed an android dependency from the AppLovin Dependencies.xml file.
|
||||
/// </summary>
|
||||
/// <param name="package">The package to remove</param>
|
||||
private static void RemoveAndroidDependency(string package)
|
||||
{
|
||||
var dependenciesFilePath = AppLovinDependenciesFilePath;
|
||||
var dependenciesDocument = GetAppLovinDependenciesFile(dependenciesFilePath);
|
||||
if (dependenciesDocument == null) return;
|
||||
|
||||
var removed = RemoveDependency(dependenciesDocument,
|
||||
ElementNameAndroidPackages,
|
||||
ElementNameAndroidPackage,
|
||||
AttributeNameSpec,
|
||||
package);
|
||||
|
||||
if (!removed) return;
|
||||
|
||||
SaveDependenciesFile(dependenciesDocument, dependenciesFilePath);
|
||||
}
|
||||
|
||||
public int callbackOrder
|
||||
{
|
||||
get { return int.MaxValue; }
|
||||
get { return CallbackOrder; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#if UNITY_IOS
|
||||
|
||||
using System.Xml.Linq;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
@@ -20,28 +21,77 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
AddGoogleCmpDependencyIfNeeded();
|
||||
}
|
||||
|
||||
private const string UmpLegacyDependencyLine = "<iosPod name=\"GoogleUserMessagingPlatform\" version=\"2.1.0\" />";
|
||||
private const string UmpDependencyLine = "<iosPod name=\"GoogleUserMessagingPlatform\" version=\"~> 2.1\" />";
|
||||
private const string IosPodsContainerElementString = "iosPods";
|
||||
private const string ElementNameIosPods = "iosPods";
|
||||
private const string ElementNameIosPod = "iosPod";
|
||||
private const string AttributeNameName = "name";
|
||||
private const string AttributeNameVersion = "version";
|
||||
private const string UmpDependencyPod = "GoogleUserMessagingPlatform";
|
||||
private const string UmpDependencyVersion = "~> 3.1";
|
||||
|
||||
private static void AddGoogleCmpDependencyIfNeeded()
|
||||
{
|
||||
// Remove the legacy fixed UMP version if it exists, we'll add the dependency with a dynamic version below.
|
||||
TryRemoveStringFromDependencyFile(UmpLegacyDependencyLine, IosPodsContainerElementString);
|
||||
|
||||
if (AppLovinInternalSettings.Instance.ConsentFlowEnabled)
|
||||
{
|
||||
TryAddStringToDependencyFile(UmpDependencyLine, IosPodsContainerElementString);
|
||||
var umpDependency = new XElement(ElementNameIosPod,
|
||||
new XAttribute(AttributeNameName, UmpDependencyPod),
|
||||
new XAttribute(AttributeNameVersion, UmpDependencyVersion));
|
||||
var success = AddOrUpdateIosDependency(UmpDependencyPod, umpDependency);
|
||||
if (!success)
|
||||
{
|
||||
MaxSdkLogger.UserWarning("Google CMP will not function. Unable to add GoogleUserMessagingPlatform dependency.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TryRemoveStringFromDependencyFile(UmpDependencyLine, IosPodsContainerElementString);
|
||||
RemoveIosDependency(UmpDependencyPod);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or updates an iOS pod in the AppLovin Dependencies.xml file.
|
||||
/// </summary>
|
||||
/// <param name="pod">The pod that we are trying to update</param>
|
||||
/// <param name="newDependency">The new dependency to add if it doesn't exist</param>
|
||||
/// <returns>Returns true if the file was successfully edited</returns>
|
||||
private static bool AddOrUpdateIosDependency(string pod, XElement newDependency)
|
||||
{
|
||||
var dependenciesFilePath = AppLovinDependenciesFilePath;
|
||||
var dependenciesDocument = GetAppLovinDependenciesFile(dependenciesFilePath, AppLovinIntegrationManager.IsPluginInPackageManager);
|
||||
if (dependenciesDocument == null) return false;
|
||||
|
||||
AddOrUpdateDependency(dependenciesDocument,
|
||||
ElementNameIosPods,
|
||||
ElementNameIosPod,
|
||||
AttributeNameName,
|
||||
pod,
|
||||
newDependency);
|
||||
return SaveDependenciesFile(dependenciesDocument, dependenciesFilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removed an iOS pod from the AppLovin Dependencies.xml file.
|
||||
/// </summary>
|
||||
/// <param name="pod">The pod to remove</param>
|
||||
private static void RemoveIosDependency(string pod)
|
||||
{
|
||||
var dependenciesFilePath = AppLovinDependenciesFilePath;
|
||||
var dependenciesDocument = GetAppLovinDependenciesFile(dependenciesFilePath);
|
||||
if (dependenciesDocument == null) return;
|
||||
|
||||
var removed = RemoveDependency(dependenciesDocument,
|
||||
ElementNameIosPods,
|
||||
ElementNameIosPod,
|
||||
AttributeNameName,
|
||||
pod);
|
||||
|
||||
if (!removed) return;
|
||||
|
||||
SaveDependenciesFile(dependenciesDocument, dependenciesFilePath);
|
||||
}
|
||||
|
||||
public int callbackOrder
|
||||
{
|
||||
get { return int.MaxValue; }
|
||||
get { return CallbackOrder; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+230
-174
@@ -6,22 +6,21 @@
|
||||
|
||||
#if UNITY_ANDROID
|
||||
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditorInternal;
|
||||
using AppLovinMax.Internal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using UnityEngine.PlayerLoop;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
[Serializable]
|
||||
public class AppLovinQualityServiceData
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming - Need to keep name for response data
|
||||
public string api_key;
|
||||
}
|
||||
|
||||
@@ -57,6 +56,60 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
private const string SafeDkLegacyMavenRepo = "http://download.safedk.com";
|
||||
private const string SafeDkLegacyDependencyClassPath = "com.safedk:SafeDKGradlePlugin:";
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Quality Service plugin to the root gradle file.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the unityLibrary's module.</param>
|
||||
/// <returns>True if the plugin was added successfully, otherwise return false</returns>
|
||||
protected static bool AddQualityServiceToRootGradleFile(string path)
|
||||
{
|
||||
var rootGradleBuildFilePath = Path.Combine(path, "../build.gradle");
|
||||
var shouldAddQualityServiceToDependencies = ShouldAddQualityServiceToDependencies(rootGradleBuildFilePath);
|
||||
|
||||
if (shouldAddQualityServiceToDependencies)
|
||||
{
|
||||
// Add the Quality Service Plugin to the dependencies block in the root build.gradle file
|
||||
return AddQualityServiceBuildScriptLines(rootGradleBuildFilePath);
|
||||
}
|
||||
|
||||
// Add the Quality Service Plugin to the plugin block in the root build.gradle file
|
||||
var rootSettingsGradleFilePath = Path.Combine(path, "../settings.gradle");
|
||||
var qualityServiceAdded = AddPluginToRootGradleBuildFile(rootGradleBuildFilePath);
|
||||
var appLovinRepositoryAdded = AddAppLovinRepository(rootSettingsGradleFilePath);
|
||||
return qualityServiceAdded && appLovinRepositoryAdded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the AppLovin Quality Service plugin should be added to the
|
||||
/// dependencies block in the root build.gradle file or to the plugins block.
|
||||
///
|
||||
/// Gradle's required structure for including plugins varies by version:
|
||||
/// - Older versions of Gradle require the plugin to be added to the dependencies block.
|
||||
/// Example:
|
||||
/// dependencies {
|
||||
/// classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
/// classpath 'com.applovin.quality:AppLovinQualityServiceGradlePlugin:+'
|
||||
/// }
|
||||
///
|
||||
/// - Newer versions of gradle require the plugin to be added to the plugins block.
|
||||
/// Example:
|
||||
/// plugins {
|
||||
/// id 'com.android.application' version '7.4.2' apply false
|
||||
/// id 'com.android.library' version '7.4.2' apply false
|
||||
/// id 'com.applovin.quality' version '+' apply false
|
||||
/// }
|
||||
///
|
||||
/// Since Unity projects may use custom Gradle versions depending on the Unity version or
|
||||
/// user modifications, this check ensures proper integration of the AppLovin plugin.
|
||||
/// </summary>
|
||||
/// <param name="rootGradleBuildFile">The path to project's root build.gradle file.</param>
|
||||
/// <returns><c>true</c> if the file contains a `dependencies` block, indicating an older Gradle version</returns>
|
||||
private static bool ShouldAddQualityServiceToDependencies(string rootGradleBuildFile)
|
||||
{
|
||||
var lines = File.ReadAllLines(rootGradleBuildFile).ToList();
|
||||
return lines.Any(line => TokenBuildScriptDependencies.IsMatch(line));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the provided Gradle script to add Quality Service plugin.
|
||||
/// </summary>
|
||||
@@ -87,11 +140,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
var outputLines = GenerateUpdatedBuildFileLines(
|
||||
sanitizedLines,
|
||||
apiKey,
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
false // On Unity 2019.3+, the buildscript closure related lines will to be added to the root build.gradle file.
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
false // The buildscript closure related lines will to be added to the root build.gradle file.
|
||||
);
|
||||
// outputLines can be null if we couldn't add the plugin.
|
||||
if (outputLines == null) return;
|
||||
@@ -122,10 +171,10 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
/// <param name="rootGradleBuildFile">The path to project's root build.gradle file.</param>
|
||||
/// <returns><c>true</c> when the plugin was added successfully.</returns>
|
||||
protected bool AddPluginToRootGradleBuildFile(string rootGradleBuildFile)
|
||||
private static bool AddPluginToRootGradleBuildFile(string rootGradleBuildFile)
|
||||
{
|
||||
var lines = File.ReadAllLines(rootGradleBuildFile).ToList();
|
||||
|
||||
|
||||
// Check if the plugin is already added to the file.
|
||||
var pluginAdded = lines.Any(line => line.Contains(QualityServicePluginRoot));
|
||||
if (pluginAdded) return true;
|
||||
@@ -182,7 +231,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
/// <param name="settingsGradleFile">The path to the project's settings.gradle file.</param>
|
||||
/// <returns><c>true</c> if the repository was added successfully.</returns>
|
||||
protected bool AddAppLovinRepository(string settingsGradleFile)
|
||||
private static bool AddAppLovinRepository(string settingsGradleFile)
|
||||
{
|
||||
var lines = File.ReadLines(settingsGradleFile).ToList();
|
||||
var outputLines = new List<string>();
|
||||
@@ -244,7 +293,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
return true;
|
||||
}
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Adds the necessary AppLovin Quality Service dependency and maven repo lines to the provided root build.gradle file.
|
||||
/// Sample build.gradle file after adding quality service:
|
||||
@@ -265,7 +313,7 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
/// <param name="rootGradleBuildFile">The root build.gradle file path</param>
|
||||
/// <returns><c>true</c> if the build script lines were applied correctly.</returns>
|
||||
protected bool AddQualityServiceBuildScriptLines(string rootGradleBuildFile)
|
||||
private static bool AddQualityServiceBuildScriptLines(string rootGradleBuildFile)
|
||||
{
|
||||
var lines = File.ReadAllLines(rootGradleBuildFile).ToList();
|
||||
var outputLines = GenerateUpdatedBuildFileLines(lines, null, true);
|
||||
@@ -307,46 +355,35 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
Console.WriteLine(exception);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static AppLovinQualityServiceData RetrieveQualityServiceData(string sdkKey)
|
||||
{
|
||||
var postJson = string.Format("{{\"sdk_key\" : \"{0}\"}}", sdkKey);
|
||||
var bodyRaw = Encoding.UTF8.GetBytes(postJson);
|
||||
// Upload handler is automatically disposed when UnityWebRequest is disposed
|
||||
var uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
uploadHandler.contentType = "application/json";
|
||||
|
||||
using (var unityWebRequest = new UnityWebRequest("https://api2.safedk.com/v1/build/cred"))
|
||||
var webRequestConfig = new WebRequestConfig()
|
||||
{
|
||||
unityWebRequest.method = UnityWebRequest.kHttpVerbPOST;
|
||||
unityWebRequest.uploadHandler = uploadHandler;
|
||||
unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
|
||||
JsonString = string.Format("{{\"sdk_key\" : \"{0}\"}}", sdkKey),
|
||||
EndPoint = "https://api2.safedk.com/v1/build/cred",
|
||||
RequestType = WebRequestType.Post,
|
||||
};
|
||||
|
||||
var operation = unityWebRequest.SendWebRequest();
|
||||
webRequestConfig.Headers.Add("Content-Type", "application/json");
|
||||
|
||||
// Wait for the download to complete or the request to timeout.
|
||||
while (!operation.isDone) { }
|
||||
var maxWebRequest = new MaxWebRequest(webRequestConfig);
|
||||
var webResponse = maxWebRequest.SendSync();
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (unityWebRequest.result != UnityWebRequest.Result.Success)
|
||||
#else
|
||||
if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
|
||||
#endif
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to retrieve API Key for SDK Key: " + sdkKey + "with error: " + unityWebRequest.error);
|
||||
return new AppLovinQualityServiceData();
|
||||
}
|
||||
if (!webResponse.IsSuccess)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to retrieve API Key for SDK Key: " + sdkKey + "with error: " + webResponse.ErrorMessage);
|
||||
return new AppLovinQualityServiceData();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonUtility.FromJson<AppLovinQualityServiceData>(unityWebRequest.downloadHandler.text);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to parse API Key." + exception);
|
||||
return new AppLovinQualityServiceData();
|
||||
}
|
||||
try
|
||||
{
|
||||
return JsonUtility.FromJson<AppLovinQualityServiceData>(webResponse.ResponseMessage);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MaxSdkLogger.UserError("Failed to parse API Key." + exception);
|
||||
return new AppLovinQualityServiceData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +450,13 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
|
||||
private static List<string> GenerateUpdatedBuildFileLines(List<string> lines, string apiKey, bool addBuildScriptLines)
|
||||
{
|
||||
var addPlugin = !string.IsNullOrEmpty(apiKey);
|
||||
// Check if the plugin exists, if so, update the SDK Key.
|
||||
var pluginExists = lines.Any(line => TokenAppLovinPlugin.IsMatch(line));
|
||||
return pluginExists ? UpdateExistingPlugin(lines, apiKey) : AddPluginAndBuildScript(lines, apiKey, addBuildScriptLines);
|
||||
}
|
||||
|
||||
private static List<string> UpdateExistingPlugin(List<string> lines, string apiKey)
|
||||
{
|
||||
// A sample of the template file.
|
||||
// ...
|
||||
// allprojects {
|
||||
@@ -434,149 +477,162 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
// **DEPS**}
|
||||
// ...
|
||||
var outputLines = new List<string>();
|
||||
// Check if the plugin exists, if so, update the SDK Key.
|
||||
var pluginExists = lines.Any(line => TokenAppLovinPlugin.IsMatch(line));
|
||||
if (pluginExists)
|
||||
var pluginMatched = false;
|
||||
var insideAppLovinClosure = false;
|
||||
var updatedApiKey = false;
|
||||
var mavenRepoUpdated = false;
|
||||
var dependencyClassPathUpdated = false;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var pluginMatched = false;
|
||||
var insideAppLovinClosure = false;
|
||||
var updatedApiKey = false;
|
||||
var mavenRepoUpdated = false;
|
||||
var dependencyClassPathUpdated = false;
|
||||
foreach (var line in lines)
|
||||
// Bintray maven repo is no longer being used. Update to s3 maven repo with regex check
|
||||
if (!mavenRepoUpdated && (line.Contains(QualityServiceBintrayMavenRepo) || line.Contains(QualityServiceNoRegexMavenRepo)))
|
||||
{
|
||||
// Bintray maven repo is no longer being used. Update to s3 maven repo with regex check
|
||||
if (!mavenRepoUpdated && (line.Contains(QualityServiceBintrayMavenRepo) || line.Contains(QualityServiceNoRegexMavenRepo)))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
|
||||
mavenRepoUpdated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We no longer use version specific dependency class path. Just use + for version to always pull the latest.
|
||||
if (!dependencyClassPathUpdated && line.Contains(QualityServiceDependencyClassPathV3))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceDependencyClassPath));
|
||||
dependencyClassPathUpdated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pluginMatched && line.Contains(QualityServicePlugin))
|
||||
{
|
||||
insideAppLovinClosure = true;
|
||||
pluginMatched = true;
|
||||
}
|
||||
|
||||
if (insideAppLovinClosure && line.Contains("}"))
|
||||
{
|
||||
insideAppLovinClosure = false;
|
||||
}
|
||||
|
||||
// Update the API key.
|
||||
if (insideAppLovinClosure && !updatedApiKey && TokenApiKey.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(string.Format(QualityServiceApiKey, apiKey));
|
||||
updatedApiKey = true;
|
||||
}
|
||||
// Keep adding the line until we find and update the plugin.
|
||||
else
|
||||
{
|
||||
outputLines.Add(line);
|
||||
}
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
|
||||
mavenRepoUpdated = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Plugin hasn't been added yet, add it.
|
||||
else
|
||||
{
|
||||
var buildScriptClosureDepth = 0;
|
||||
var insideBuildScriptClosure = false;
|
||||
var buildScriptMatched = false;
|
||||
var qualityServiceRepositoryAdded = false;
|
||||
var qualityServiceDependencyClassPathAdded = false;
|
||||
var qualityServicePluginAdded = false;
|
||||
foreach (var line in lines)
|
||||
|
||||
// We no longer use version specific dependency class path. Just use + for version to always pull the latest.
|
||||
if (!dependencyClassPathUpdated && line.Contains(QualityServiceDependencyClassPathV3))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceDependencyClassPath));
|
||||
dependencyClassPathUpdated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pluginMatched && line.Contains(QualityServicePlugin))
|
||||
{
|
||||
insideAppLovinClosure = true;
|
||||
pluginMatched = true;
|
||||
}
|
||||
|
||||
if (insideAppLovinClosure && line.Contains("}"))
|
||||
{
|
||||
insideAppLovinClosure = false;
|
||||
}
|
||||
|
||||
// Update the API key.
|
||||
if (insideAppLovinClosure && !updatedApiKey && TokenApiKey.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(string.Format(QualityServiceApiKey, apiKey));
|
||||
updatedApiKey = true;
|
||||
}
|
||||
// Keep adding the line until we find and update the plugin.
|
||||
else
|
||||
{
|
||||
// Add the line to the output lines.
|
||||
outputLines.Add(line);
|
||||
|
||||
// Check if we need to add the build script lines and add them.
|
||||
if (addBuildScriptLines)
|
||||
{
|
||||
if (!buildScriptMatched && line.Contains(BuildScriptMatcher))
|
||||
{
|
||||
buildScriptMatched = true;
|
||||
insideBuildScriptClosure = true;
|
||||
}
|
||||
|
||||
// Match the parenthesis to track if we are still inside the buildscript closure.
|
||||
if (insideBuildScriptClosure)
|
||||
{
|
||||
if (line.Contains("{"))
|
||||
{
|
||||
buildScriptClosureDepth++;
|
||||
}
|
||||
|
||||
if (line.Contains("}"))
|
||||
{
|
||||
buildScriptClosureDepth--;
|
||||
}
|
||||
|
||||
if (buildScriptClosureDepth == 0)
|
||||
{
|
||||
insideBuildScriptClosure = false;
|
||||
|
||||
// There may be multiple buildscript closures and we need to keep looking until we added both the repository and classpath.
|
||||
buildScriptMatched = qualityServiceRepositoryAdded && qualityServiceDependencyClassPathAdded;
|
||||
}
|
||||
}
|
||||
|
||||
if (insideBuildScriptClosure)
|
||||
{
|
||||
// Add the build script dependency repositories.
|
||||
if (!qualityServiceRepositoryAdded && TokenBuildScriptRepositories.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
|
||||
qualityServiceRepositoryAdded = true;
|
||||
}
|
||||
// Add the build script dependencies.
|
||||
else if (!qualityServiceDependencyClassPathAdded && TokenBuildScriptDependencies.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceDependencyClassPath));
|
||||
qualityServiceDependencyClassPathAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we need to add the plugin and add it.
|
||||
if (addPlugin)
|
||||
{
|
||||
// Add the plugin.
|
||||
if (!qualityServicePluginAdded && TokenApplicationPlugin.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(QualityServiceApplyPlugin);
|
||||
outputLines.AddRange(GenerateAppLovinPluginClosure(apiKey));
|
||||
qualityServicePluginAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((addBuildScriptLines && (!qualityServiceRepositoryAdded || !qualityServiceDependencyClassPathAdded)) || (addPlugin && !qualityServicePluginAdded))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return outputLines;
|
||||
}
|
||||
|
||||
private static List<string> AddPluginAndBuildScript(List<string> lines, string apiKey, bool addBuildScriptLines)
|
||||
{
|
||||
var shouldAddPlugin = MaxSdkUtils.IsValidString(apiKey);
|
||||
if (shouldAddPlugin)
|
||||
{
|
||||
lines = AddPlugin(lines, apiKey);
|
||||
if (lines == null) return null;
|
||||
}
|
||||
|
||||
if (!addBuildScriptLines) return lines;
|
||||
|
||||
lines = AddBuildScript(lines);
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static List<string> AddBuildScript(List<string> lines)
|
||||
{
|
||||
var outputLines = new List<string>();
|
||||
var buildScriptClosureDepth = 0;
|
||||
var insideBuildScriptClosure = false;
|
||||
var buildScriptMatched = false;
|
||||
var qualityServiceRepositoryAdded = false;
|
||||
var qualityServiceDependencyClassPathAdded = false;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
// Add the line to the output lines.
|
||||
outputLines.Add(line);
|
||||
|
||||
if (!buildScriptMatched && line.Contains(BuildScriptMatcher))
|
||||
{
|
||||
buildScriptMatched = true;
|
||||
insideBuildScriptClosure = true;
|
||||
}
|
||||
|
||||
// Match the parenthesis to track if we are still inside the buildscript closure.
|
||||
if (insideBuildScriptClosure)
|
||||
{
|
||||
if (line.Contains("{"))
|
||||
{
|
||||
buildScriptClosureDepth++;
|
||||
}
|
||||
|
||||
if (line.Contains("}"))
|
||||
{
|
||||
buildScriptClosureDepth--;
|
||||
}
|
||||
|
||||
if (buildScriptClosureDepth == 0)
|
||||
{
|
||||
insideBuildScriptClosure = false;
|
||||
|
||||
// There may be multiple buildscript closures and we need to keep looking until we added both the repository and classpath.
|
||||
buildScriptMatched = qualityServiceRepositoryAdded && qualityServiceDependencyClassPathAdded;
|
||||
}
|
||||
}
|
||||
|
||||
if (insideBuildScriptClosure)
|
||||
{
|
||||
// Add the build script dependency repositories.
|
||||
if (!qualityServiceRepositoryAdded && TokenBuildScriptRepositories.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
|
||||
qualityServiceRepositoryAdded = true;
|
||||
}
|
||||
// Add the build script dependencies.
|
||||
else if (!qualityServiceDependencyClassPathAdded && TokenBuildScriptDependencies.IsMatch(line))
|
||||
{
|
||||
outputLines.Add(GetFormattedBuildScriptLine(QualityServiceDependencyClassPath));
|
||||
qualityServiceDependencyClassPathAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!qualityServiceRepositoryAdded || !qualityServiceDependencyClassPathAdded)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return outputLines;
|
||||
}
|
||||
|
||||
private static List<string> AddPlugin(List<string> lines, string apiKey)
|
||||
{
|
||||
var outputLines = new List<string>();
|
||||
var qualityServicePluginAdded = false;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
outputLines.Add(line);
|
||||
|
||||
// Add the plugin.
|
||||
if (qualityServicePluginAdded || !TokenApplicationPlugin.IsMatch(line)) continue;
|
||||
|
||||
outputLines.Add(QualityServiceApplyPlugin);
|
||||
outputLines.AddRange(GenerateAppLovinPluginClosure(apiKey));
|
||||
qualityServicePluginAdded = true;
|
||||
}
|
||||
|
||||
return qualityServicePluginAdded ? outputLines : null;
|
||||
}
|
||||
|
||||
public static string GetFormattedBuildScriptLine(string buildScriptLine)
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
return " "
|
||||
#elif UNITY_2019_3_OR_NEWER
|
||||
return " "
|
||||
#else
|
||||
return " "
|
||||
return " "
|
||||
#endif
|
||||
+ buildScriptLine;
|
||||
}
|
||||
|
||||
@@ -12,17 +12,6 @@ using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
public enum Platform
|
||||
{
|
||||
All,
|
||||
Android,
|
||||
iOS
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ScriptableObject"/> representing the AppLovin Settings that can be set in the Integration Manager Window.
|
||||
///
|
||||
@@ -32,56 +21,19 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
/// </summary>
|
||||
public class AppLovinSettings : ScriptableObject
|
||||
{
|
||||
public const string SettingsExportPath = "MaxSdk/Resources/AppLovinSettings.asset";
|
||||
|
||||
public const string DefaultUserTrackingDescriptionEnV0 = "Pressing \\\"Allow\\\" uses device info for more relevant ad content";
|
||||
public const string DefaultUserTrackingDescriptionEnV1 = "This only uses device info for less annoying, more relevant ads";
|
||||
public const string DefaultUserTrackingDescriptionEnV2 = "This only uses device info for more interesting and relevant ads";
|
||||
public const string DefaultUserTrackingDescriptionEnV3 = "This uses device info for more personalized ads and content";
|
||||
|
||||
public const string DefaultUserTrackingDescriptionDe = "\\\"Erlauben\\\" drücken benutzt Gerätinformationen für relevantere Werbeinhalte";
|
||||
public const string DefaultUserTrackingDescriptionEs = "Presionando \\\"Permitir\\\", se usa la información del dispositivo para obtener contenido publicitario más relevante";
|
||||
public const string DefaultUserTrackingDescriptionFr = "\\\"Autoriser\\\" permet d'utiliser les infos du téléphone pour afficher des contenus publicitaires plus pertinents";
|
||||
public const string DefaultUserTrackingDescriptionJa = "\\\"許可\\\"をクリックすることで、デバイス情報を元により最適な広告を表示することができます";
|
||||
public const string DefaultUserTrackingDescriptionKo = "\\\"허용\\\"을 누르면 더 관련성 높은 광고 콘텐츠를 제공하기 위해 기기 정보가 사용됩니다";
|
||||
public const string DefaultUserTrackingDescriptionZhHans = "点击\\\"允许\\\"以使用设备信息获得更加相关的广告内容";
|
||||
public const string DefaultUserTrackingDescriptionZhHant = "點擊\\\"允許\\\"以使用設備信息獲得更加相關的廣告內容";
|
||||
|
||||
/// <summary>
|
||||
/// A placeholder constant to be replaced with the actual default localization or an empty string based on whether or not localization is enabled when when the getter is called.
|
||||
/// </summary>
|
||||
protected const string DefaultLocalization = "default_localization";
|
||||
private const string SettingsExportPath = "MaxSdk/Resources/AppLovinSettings.asset";
|
||||
|
||||
private static AppLovinSettings instance;
|
||||
|
||||
[SerializeField] private bool qualityServiceEnabled = true;
|
||||
[SerializeField] private string sdkKey;
|
||||
|
||||
[SerializeField] private bool setAttributionReportEndpoint;
|
||||
[SerializeField] private bool addApsSkAdNetworkIds;
|
||||
|
||||
[SerializeField] private string customGradleVersionUrl;
|
||||
[SerializeField] private string customGradleToolsVersion;
|
||||
|
||||
[SerializeField] private bool consentFlowEnabled;
|
||||
[SerializeField] private Platform consentFlowPlatform;
|
||||
[SerializeField] private string consentFlowPrivacyPolicyUrl = string.Empty;
|
||||
[SerializeField] private string consentFlowTermsOfServiceUrl = string.Empty;
|
||||
[FormerlySerializedAs("userTrackingUsageDescription")] [SerializeField] private string userTrackingUsageDescriptionEn = string.Empty;
|
||||
[SerializeField] private bool userTrackingUsageLocalizationEnabled;
|
||||
[SerializeField] private string userTrackingUsageDescriptionDe = string.Empty;
|
||||
[SerializeField] private string userTrackingUsageDescriptionEs = string.Empty;
|
||||
[SerializeField] private string userTrackingUsageDescriptionFr = string.Empty;
|
||||
[SerializeField] private string userTrackingUsageDescriptionJa = string.Empty;
|
||||
[SerializeField] private string userTrackingUsageDescriptionKo = string.Empty;
|
||||
[SerializeField] private string userTrackingUsageDescriptionZhHans = string.Empty;
|
||||
[SerializeField] private string userTrackingUsageDescriptionZhHant = DefaultLocalization;
|
||||
|
||||
[SerializeField] private string adMobAndroidAppId = string.Empty;
|
||||
[SerializeField] private string adMobIosAppId = string.Empty;
|
||||
|
||||
[SerializeField] private bool showInternalSettingsInIntegrationManager;
|
||||
|
||||
/// <summary>
|
||||
/// An instance of AppLovin Setting.
|
||||
/// </summary>
|
||||
@@ -105,16 +57,15 @@ public class AppLovinSettings : ScriptableObject
|
||||
return instance;
|
||||
}
|
||||
|
||||
// If there is no existing AppLovinSettings asset, create one in the default location
|
||||
string settingsFilePath;
|
||||
// The settings file should be under the Assets/ folder so that it can be version controlled and cannot be overriden when updating.
|
||||
// If the plugin is outside the Assets folder, create the settings asset at the default location.
|
||||
if (AppLovinIntegrationManager.IsPluginOutsideAssetsDirectory)
|
||||
// If the plugin is outside the Assets folder or if there is no existing AppLovinSettings asset, create the settings asset at the default location.
|
||||
if (AppLovinIntegrationManager.IsPluginInPackageManager)
|
||||
{
|
||||
// Note: Can't use absolute path when calling `CreateAsset`. Should use relative path to Assets/ directory.
|
||||
settingsFilePath = Path.Combine("Assets", SettingsExportPath);
|
||||
// Note: Can't use absolute path when calling `CreateAsset`. Should use path relative to Assets/ directory.
|
||||
settingsFilePath = MaxSdkUtils.NormalizeToUnityPath(Path.Combine("Assets", SettingsExportPath));
|
||||
|
||||
var maxSdkDir = Path.Combine(Application.dataPath, "MaxSdk");
|
||||
var maxSdkDir = MaxSdkUtils.NormalizeToUnityPath(Path.Combine(Application.dataPath, "MaxSdk"));
|
||||
if (!Directory.Exists(maxSdkDir))
|
||||
{
|
||||
Directory.CreateDirectory(maxSdkDir);
|
||||
@@ -122,7 +73,7 @@ public class AppLovinSettings : ScriptableObject
|
||||
}
|
||||
else
|
||||
{
|
||||
settingsFilePath = Path.Combine(AppLovinIntegrationManager.PluginParentDirectory, SettingsExportPath);
|
||||
settingsFilePath = MaxSdkUtils.NormalizeToUnityPath(Path.Combine(AppLovinIntegrationManager.PluginParentDirectory, SettingsExportPath));
|
||||
}
|
||||
|
||||
var settingsDir = Path.GetDirectoryName(settingsFilePath);
|
||||
@@ -162,24 +113,6 @@ public class AppLovinSettings : ScriptableObject
|
||||
set { Instance.sdkKey = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to set `NSAdvertisingAttributionReportEndpoint` in Info.plist.
|
||||
/// </summary>
|
||||
public bool SetAttributionReportEndpoint
|
||||
{
|
||||
get { return Instance.setAttributionReportEndpoint; }
|
||||
set { Instance.setAttributionReportEndpoint = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to add Amazon Publisher Services SKAdNetworkID's.
|
||||
/// </summary>
|
||||
public bool AddApsSkAdNetworkIds
|
||||
{
|
||||
get { return Instance.addApsSkAdNetworkIds; }
|
||||
set { Instance.addApsSkAdNetworkIds = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A URL to set the distributionUrl in the gradle-wrapper.properties file (ex: https\://services.gradle.org/distributions/gradle-6.9.3-bin.zip)
|
||||
/// </summary>
|
||||
@@ -198,199 +131,6 @@ public class AppLovinSettings : ScriptableObject
|
||||
set { Instance.customGradleToolsVersion = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not AppLovin Consent Flow is enabled.
|
||||
/// </summary>
|
||||
public bool ConsentFlowEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
// Update the default EN description if an old version of the description is still being used.
|
||||
if (DefaultUserTrackingDescriptionEnV0.Equals(Instance.UserTrackingUsageDescriptionEn)
|
||||
|| DefaultUserTrackingDescriptionEnV1.Equals(Instance.UserTrackingUsageDescriptionEn)
|
||||
|| DefaultUserTrackingDescriptionEnV2.Equals(Instance.UserTrackingUsageDescriptionEn))
|
||||
{
|
||||
Instance.UserTrackingUsageDescriptionEn = DefaultUserTrackingDescriptionEnV3;
|
||||
}
|
||||
|
||||
return Instance.consentFlowEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
var previousValue = Instance.consentFlowEnabled;
|
||||
Instance.consentFlowEnabled = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
// If the value didn't change, we don't need to update anything.
|
||||
if (previousValue) return;
|
||||
|
||||
Instance.UserTrackingUsageDescriptionEn = DefaultUserTrackingDescriptionEnV3;
|
||||
Instance.UserTrackingUsageLocalizationEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance.ConsentFlowPlatform = Platform.All;
|
||||
Instance.ConsentFlowPrivacyPolicyUrl = string.Empty;
|
||||
Instance.ConsentFlowTermsOfServiceUrl = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionEn = string.Empty;
|
||||
Instance.UserTrackingUsageLocalizationEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Platform ConsentFlowPlatform
|
||||
{
|
||||
get { return Instance.consentFlowEnabled ? Instance.consentFlowPlatform : Platform.All; }
|
||||
set { Instance.consentFlowPlatform = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A URL pointing to the Privacy Policy for the app to be shown when prompting the user for consent.
|
||||
/// </summary>
|
||||
public string ConsentFlowPrivacyPolicyUrl
|
||||
{
|
||||
get { return Instance.consentFlowPrivacyPolicyUrl; }
|
||||
set { Instance.consentFlowPrivacyPolicyUrl = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An optional URL pointing to the Terms of Service for the app to be shown when prompting the user for consent.
|
||||
/// </summary>
|
||||
public string ConsentFlowTermsOfServiceUrl
|
||||
{
|
||||
get { return Instance.consentFlowTermsOfServiceUrl; }
|
||||
set { Instance.consentFlowTermsOfServiceUrl = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in English to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionEn
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionEn; }
|
||||
set { Instance.userTrackingUsageDescriptionEn = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to localize User Tracking Usage Description.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public bool UserTrackingUsageLocalizationEnabled
|
||||
{
|
||||
get { return Instance.userTrackingUsageLocalizationEnabled; }
|
||||
set
|
||||
{
|
||||
var previousValue = Instance.userTrackingUsageLocalizationEnabled;
|
||||
Instance.userTrackingUsageLocalizationEnabled = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
// If the value didn't change or the english localization text is not the default one, we don't need to update anything.
|
||||
if (previousValue || !DefaultUserTrackingDescriptionEnV3.Equals(Instance.UserTrackingUsageDescriptionEn)) return;
|
||||
|
||||
Instance.UserTrackingUsageDescriptionDe = DefaultUserTrackingDescriptionDe;
|
||||
Instance.UserTrackingUsageDescriptionEs = DefaultUserTrackingDescriptionEs;
|
||||
Instance.UserTrackingUsageDescriptionFr = DefaultUserTrackingDescriptionFr;
|
||||
Instance.UserTrackingUsageDescriptionJa = DefaultUserTrackingDescriptionJa;
|
||||
Instance.UserTrackingUsageDescriptionKo = DefaultUserTrackingDescriptionKo;
|
||||
Instance.UserTrackingUsageDescriptionZhHans = DefaultUserTrackingDescriptionZhHans;
|
||||
Instance.UserTrackingUsageDescriptionZhHant = DefaultUserTrackingDescriptionZhHant;
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance.UserTrackingUsageDescriptionDe = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionEs = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionFr = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionJa = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionKo = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionZhHans = string.Empty;
|
||||
Instance.UserTrackingUsageDescriptionZhHant = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in German to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionDe
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionDe; }
|
||||
set { Instance.userTrackingUsageDescriptionDe = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Spanish to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionEs
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionEs; }
|
||||
set { Instance.userTrackingUsageDescriptionEs = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in French to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionFr
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionFr; }
|
||||
set { Instance.userTrackingUsageDescriptionFr = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Japanese to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionJa
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionJa; }
|
||||
set { Instance.userTrackingUsageDescriptionJa = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Korean to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionKo
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionKo; }
|
||||
set { Instance.userTrackingUsageDescriptionKo = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Chinese (Simplified) to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionZhHans
|
||||
{
|
||||
get { return Instance.userTrackingUsageDescriptionZhHans; }
|
||||
set { Instance.userTrackingUsageDescriptionZhHans = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A User Tracking Usage Description in Chinese (Traditional) to be shown to users when requesting permission to use data for tracking.
|
||||
/// For more information see <see cref="https://developer.apple.com/documentation/bundleresources/information_property_list/nsusertrackingusagedescription">Apple's documentation</see>.
|
||||
/// </summary>
|
||||
public string UserTrackingUsageDescriptionZhHant
|
||||
{
|
||||
get
|
||||
{
|
||||
// Since this localization has been added separate from the other localizations,
|
||||
// we use a placeholder constant to be replaced with the actual value or an empty string based on whether or not the localization was enabled by the publisher.
|
||||
if (DefaultLocalization.Equals(Instance.userTrackingUsageDescriptionZhHant))
|
||||
{
|
||||
Instance.userTrackingUsageDescriptionZhHant = Instance.UserTrackingUsageLocalizationEnabled ? DefaultUserTrackingDescriptionZhHant : string.Empty;
|
||||
}
|
||||
|
||||
return Instance.userTrackingUsageDescriptionZhHant;
|
||||
}
|
||||
set { Instance.userTrackingUsageDescriptionZhHant = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AdMob Android App ID.
|
||||
/// </summary>
|
||||
@@ -409,12 +149,6 @@ public class AppLovinSettings : ScriptableObject
|
||||
set { Instance.adMobIosAppId = value; }
|
||||
}
|
||||
|
||||
public bool ShowInternalSettingsInIntegrationManager
|
||||
{
|
||||
get { return Instance.showInternalSettingsInIntegrationManager; }
|
||||
set { Instance.showInternalSettingsInIntegrationManager = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the instance of the settings.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AppLovinMax.ThirdParty.MiniJson;
|
||||
|
||||
namespace AppLovinMax.Scripts.IntegrationManager.Editor
|
||||
{
|
||||
public class AppLovinUpmManifest
|
||||
{
|
||||
private const string KeyUrl = "url";
|
||||
private const string KeyName = "name";
|
||||
private const string KeyScopes = "scopes";
|
||||
private const string KeyScopedRegistry = "scopedRegistries";
|
||||
|
||||
private Dictionary<string, object> manifest;
|
||||
|
||||
private static string ManifestPath
|
||||
{
|
||||
get { return Path.Combine(Directory.GetCurrentDirectory(), "Packages/manifest.json"); }
|
||||
}
|
||||
|
||||
// Private constructor to enforce the use of the Load() method
|
||||
private AppLovinUpmManifest() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of AppLovinUpmManifest and loads the manifest.json file.
|
||||
/// </summary>
|
||||
/// <returns>An instance of AppLovinUpmManifest</returns>
|
||||
public static AppLovinUpmManifest Load()
|
||||
{
|
||||
return new AppLovinUpmManifest { manifest = GetManifest() };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or updates a scoped registry in the manifest.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the registry</param>
|
||||
/// <param name="url">The url of the registry</param>
|
||||
/// <param name="scopes">The scopes of the registry</param>
|
||||
public void AddOrUpdateRegistry(string name, string url, List<string> scopes)
|
||||
{
|
||||
var registry = GetRegistry(name);
|
||||
if (registry == null)
|
||||
{
|
||||
var registries = GetRegistries();
|
||||
if (registries == null) return;
|
||||
|
||||
registries.Add(new Dictionary<string, object>
|
||||
{
|
||||
{KeyName, name},
|
||||
{KeyUrl, url},
|
||||
{KeyScopes, scopes}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateRegistry(registry, scopes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the manifest by serializing it back to JSON and writing to file.
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
var content = Json.Serialize(manifest, true);
|
||||
File.WriteAllText(ManifestPath, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dependency to the manifest.
|
||||
/// </summary>
|
||||
/// <param name="packageName">The name of the package to add</param>
|
||||
/// <param name="version">The version of the package to add</param>
|
||||
public void AddPackageDependency(string packageName, string version)
|
||||
{
|
||||
var manifestDependencies = GetDependencies();
|
||||
manifestDependencies[packageName] = version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a dependency from the manifest.
|
||||
/// </summary>
|
||||
/// <param name="packageName">The name of the package to remove</param>
|
||||
public void RemovePackageDependency(string packageName)
|
||||
{
|
||||
var manifestDependencies = GetDependencies();
|
||||
manifestDependencies.Remove(packageName);
|
||||
}
|
||||
|
||||
#region Utility
|
||||
|
||||
/// <summary>
|
||||
/// Returns the manifest.json file as a dictionary.
|
||||
/// </summary>
|
||||
private static Dictionary<string, object> GetManifest()
|
||||
{
|
||||
if (!File.Exists(ManifestPath))
|
||||
{
|
||||
throw new Exception("Manifest not Found!");
|
||||
}
|
||||
|
||||
var manifestJson = File.ReadAllText(ManifestPath);
|
||||
if (string.IsNullOrEmpty(manifestJson))
|
||||
{
|
||||
throw new Exception("Manifest is empty!");
|
||||
}
|
||||
|
||||
var deserializedManifest = Json.Deserialize(manifestJson) as Dictionary<string, object>;
|
||||
if (deserializedManifest == null)
|
||||
{
|
||||
throw new Exception("Failed to deserialize manifest");
|
||||
}
|
||||
|
||||
return deserializedManifest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the manifest's dependencies section.
|
||||
/// </summary>
|
||||
/// <returns>The dependencies section of the manifest.</returns>
|
||||
private Dictionary<string, object> GetDependencies()
|
||||
{
|
||||
var dependencies = manifest["dependencies"] as Dictionary<string, object>;
|
||||
if (dependencies == null)
|
||||
{
|
||||
throw new Exception("No dependencies found in manifest.");
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the manifest's registries section. Creates a new registries section if one does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The registries section of the manifest.</returns>
|
||||
private List<object> GetRegistries()
|
||||
{
|
||||
EnsureScopedRegistryExists();
|
||||
return manifest[KeyScopedRegistry] as List<object>;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a scoped registry with the given name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the registry</param>
|
||||
/// <returns>Returns the registry, or null if it can't be found</returns>
|
||||
private Dictionary<string, object> GetRegistry(string name)
|
||||
{
|
||||
var registries = GetRegistries();
|
||||
if (registries == null) return null;
|
||||
|
||||
return registries
|
||||
.OfType<Dictionary<string, object>>()
|
||||
.FirstOrDefault(registry => MaxSdkUtils.GetStringFromDictionary(registry, KeyName).Equals(name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the section for scoped registries in the manifest.json file if it doesn't exist.
|
||||
/// </summary>
|
||||
private void EnsureScopedRegistryExists()
|
||||
{
|
||||
if (manifest.ContainsKey(KeyScopedRegistry)) return;
|
||||
|
||||
manifest.Add(KeyScopedRegistry, new List<object>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a registry to make sure it contains the new scopes.
|
||||
/// </summary>
|
||||
/// <param name="registry">The registry to update</param>
|
||||
/// <param name="newScopes">The scopes we want added to the registry</param>
|
||||
private static void UpdateRegistry(Dictionary<string, object> registry, List<string> newScopes)
|
||||
{
|
||||
var scopes = MaxSdkUtils.GetListFromDictionary(registry, KeyScopes);
|
||||
if (scopes == null)
|
||||
{
|
||||
registry[KeyScopes] = new List<string>(newScopes);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only add scopes that are not already in the list
|
||||
var uniqueNewScopes = newScopes.Where(scope => !scopes.Contains(scope)).ToList();
|
||||
scopes.AddRange(uniqueNewScopes);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40e2ad4a252104688b8627f82e806b2e
|
||||
labels:
|
||||
- al_max
|
||||
- al_max_export_path-MaxSdk/Scripts/AppLovinUpmManifest.cs
|
||||
- al_max_export_path-MaxSdk/Scripts/IntegrationManager/Editor/AppLovinUpmManifest.cs
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user