627 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			627 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
|  | 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"; | ||
|  | 
 | ||
|  | #if UNITY_2019_2_OR_NEWER | ||
|  |         private static readonly IPackageManagerClient _upmPackageManager = new AppLovinUpmPackageManager(); | ||
|  | #endif | ||
|  |         private static readonly IPackageManagerClient _assetsPackageManager = new AppLovinAssetsPackageManager(); | ||
|  | 
 | ||
|  |         private static IPackageManagerClient PackageManagerClient | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  | #if UNITY_2019_2_OR_NEWER | ||
|  |                 return AppLovinIntegrationManager.IsPluginInPackageManager ? _upmPackageManager : _assetsPackageManager; | ||
|  | #else | ||
|  |                 return _assetsPackageManager; | ||
|  | #endif | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         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); | ||
|  | 
 | ||
|  | #if UNITY_2019_2_OR_NEWER | ||
|  |             var installedNetworksInPackages = AppLovinUpmPackageManager.GetInstalledMediationNetworks(); | ||
|  |             installedNetworks.AddRange(installedNetworksInPackages); | ||
|  | #endif | ||
|  | 
 | ||
|  |             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-" + exportPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); | ||
|  |             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 UNITY_2019_2_OR_NEWER | ||
|  |             if (HasDuplicateAdapters(assetPaths)) | ||
|  |             { | ||
|  |                 ShowDeleteDuplicateAdapterPrompt(network); | ||
|  |             } | ||
|  | #endif | ||
|  | 
 | ||
|  |             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; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  | #if UNITY_2019_2_OR_NEWER | ||
|  |         /// <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) | ||
|  |         { | ||
|  |             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(); | ||
|  |         } | ||
|  | #endif | ||
|  | 
 | ||
|  |         /// <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 | ||
|  |     } | ||
|  | 
 | ||
|  | #if UNITY_2019_2_OR_NEWER | ||
|  |     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; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 | ||
|  |     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"); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |