using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using AmazonInternal.ThirdParty; using UnityEditor; using UnityEditor.PackageManager; using UnityEditor.PackageManager.Requests; using UnityEngine; using UnityEngine.Networking; public class AmazonSDKManager : EditorWindow { static string AmazonSdkVersion; static AddRequest Request; static void AddEditorCoroutine () { // Add a package to the Project Request = Client.Add ("com.unity.editorcoroutine"); EditorApplication.update += Progress; } static void Progress () { if (Request.IsCompleted) { if (Request.Status == StatusCode.Success) Debug.Log ("Installed: " + Request.Result.packageId); else if (Request.Status >= StatusCode.Failure) Debug.Log (Request.Error.message); EditorApplication.update -= Progress; } } [MenuItem ("Amazon/About Amazon SDK", false, 0)] public static void About () { AmazonAboutDialog.ShowDialog (); } [MenuItem ("Amazon/Documentation...", false, 1)] public static void Documentation () { Application.OpenURL (AmazonConstants.docUrl); } [MenuItem ("Amazon/Manage SDKs...", false, 4)] public static void SdkManagerProd () { AmazonSDKManager.ShowSDKManager (); } private const string downloadDir = "Assets/Amazon"; private struct SdkInfo { public string Name; public string Key; public string Url; public string LatestVersion; public string CurrentVersion; public string Filename; public bool FromJson (string name, Dictionary dict) { if (string.IsNullOrEmpty (name) || dict == null) return false; object obj; Key = name; if (dict.TryGetValue ("name", out obj)) Name = obj as string; if (dict.TryGetValue ("link", out obj)) Url = obj as string; if (dict.TryGetValue ("version", out obj)) LatestVersion = obj as string; if (!string.IsNullOrEmpty (Url)) { var uri = new Uri (Url); var path = uri.IsAbsoluteUri ? uri.AbsolutePath : uri.LocalPath; Filename = Path.GetFileName (path); } return true; } public bool FromConfig(AmazonPackageConfig config) { if (config == null || string.IsNullOrEmpty(config.Name) || !string.IsNullOrEmpty(Key) && Key != config.Name) return false; CurrentVersion = config.Version; return true; } } // Version and download info for the SDK and network mediation adapters. private static SdkInfo amazonSdkInfo; private static readonly SortedDictionary sdkInfo = new SortedDictionary (); // Async download operations tracked here. private AmazonCoroutines.AmazonCoroutine coroutine; private UnityWebRequest downloader; private string activity; // Custom style for LabelFields. (Don't make static or the dialog doesn't recover well from Unity compiling // a new or changed editor script.) private GUIStyle labelStyle; private GUIStyle labelStyleArea; private GUIStyle labelStyleLink; private GUIStyle headerStyle; private readonly GUILayoutOption fieldWidth = GUILayout.Width (60); private Vector2 scrollPos; public static void ShowSDKManager () { var win = GetWindow (true); win.titleContent = new GUIContent ("Amazon SDK Manager"); win.Focus (); } void Awake () { labelStyle = new GUIStyle (EditorStyles.label) { fontSize = 14, fontStyle = FontStyle.Bold }; labelStyleArea = new GUIStyle (EditorStyles.label) { wordWrap = true }; labelStyleLink = new GUIStyle (EditorStyles.label) { normal = { textColor = Color.blue }, active = { textColor = Color.white }, }; headerStyle = new GUIStyle (EditorStyles.label) { fontSize = 12, fontStyle = FontStyle.Bold, fixedHeight = 18 }; CancelOperation (); } void OnEnable () { coroutine = this.StartCoroutine (GetSDKVersions ()); } void OnDisable () { CancelOperation (); } public void deleteUnwantedFiles() { String[] filesToDel = { "Assets/Amazon/Scripts/Internal/AdResponce.cs", "Assets/Amazon/Scripts/Internal/AdResponce.cs.meta", "Assets/Amazon/Scripts/Internal/IOS/IOSAdResponce.cs", "Assets/Amazon/Scripts/Internal/IOS/IOSAdResponce.cs.meta", "Assets/Amazon/Scripts/Internal/Android/AndroidAdResponce.cs", "Assets/Amazon/Scripts/Internal/Android/AndroidAdResponce.cs.meta", "Assets/Amazon/Plugins/Android/aps-sdk.aar", "Assets/Amazon/Plugins/Android/aps-sdk.aar.meta", "Assets/Amazon/Scripts/Mediations/AdMobMediation/Plugins/Android/aps-admob-adapter.aar", "Assets/Amazon/Scripts/Mediations/AdMobMediation/Plugins/Android/aps-admob-adapter.aar.meta", "Assets/Amazon/Scripts/Mediations/APSConnectionUtil", "Assets/Amazon/Scripts/Mediations/APSConnectionUtil.meta", "Assets/Amazon/Scripts/Mediations/MoPubMediation", "Assets/Amazon/Scripts/Mediations/MoPubMediation.meta", "Assets/APSConnectionUtil", "Assets/APSConnectionUtil.meta", "Assets/Amazon/Sample/AmazonMoPubDemo.cs", "Assets/Amazon/Sample/AmazonMoPubDemo.cs.meta", "Assets/Amazon/Sample/APSMoPubMediation.unity", "Assets/Amazon/Sample/APSMoPubMediation.unity.meta" }; foreach (String fileToDel in filesToDel) { if (Directory.Exists(fileToDel)) { Directory.Delete(fileToDel, true); } else if (File.Exists(fileToDel)) { File.Delete(fileToDel); } } } private IEnumerator GetSDKVersions () { // Wait one frame so that we don't try to show the progress bar in the middle of OnGUI(). yield return null; activity = "Downloading SDK version manifest..."; UnityWebRequest www = new UnityWebRequest (AmazonConstants.manifestURL) { downloadHandler = new DownloadHandlerBuffer (), timeout = 10, // seconds }; yield return www.SendWebRequest (); if (!string.IsNullOrEmpty (www.error)) { Debug.LogError (www.error); EditorUtility.DisplayDialog ( "SDK Manager Service", "The services we need are not accessible. Please consider integrating manually.\n\n" + "For instructions, see " + AmazonConstants.helpLink, "OK"); } var json = www.downloadHandler.text; if (string.IsNullOrEmpty (json)) { json = "{}"; Debug.LogError ("Unable to retrieve SDK version manifest. Showing installed SDKs only."); } www.Dispose (); // Got the file. Now extract info on latest SDKs available. amazonSdkInfo = new SdkInfo (); sdkInfo.Clear (); var dict = Json.Deserialize (json) as Dictionary; if (dict != null) { object obj; if (dict.TryGetValue ("sdk", out obj)) { amazonSdkInfo.FromJson ("sdk", obj as Dictionary); amazonSdkInfo.CurrentVersion = AmazonConstants.VERSION; } if (dict.TryGetValue ("adapters", out obj)){ var info = new SdkInfo (); foreach (var item in obj as Dictionary) { if (info.FromJson (item.Key, item.Value as Dictionary)) sdkInfo[info.Key] = info; } } } var baseType = typeof(AmazonPackageConfig); var configs = from t in Assembly.GetExecutingAssembly().GetTypes() where t.IsSubclassOf(baseType) && !t.IsAbstract select Activator.CreateInstance(t) as AmazonPackageConfig; foreach (var config in configs) { SdkInfo info; sdkInfo.TryGetValue(config.Name, out info); if (info.FromConfig(config) && info.Key != null) sdkInfo[info.Key] = info; } coroutine = null; deleteUnwantedFiles(); Repaint (); } void OnGUI () { // Is any async job in progress? var stillWorking = coroutine != null || downloader != null; GUILayout.Space (5); EditorGUILayout.LabelField ("Amazon SDKs", labelStyle, GUILayout.Height (20)); using (new EditorGUILayout.VerticalScope("box")) { SdkHeaders(); SdkRow(amazonSdkInfo); } if (sdkInfo.Count > 0) { GUILayout.Space (5); EditorGUILayout.LabelField ("Mediated Networks", labelStyle, GUILayout.Height (20)); using (new EditorGUILayout.VerticalScope ("box")) using (var s = new EditorGUILayout.ScrollViewScope (scrollPos, false, false)) { scrollPos = s.scrollPosition; SdkHeaders (); foreach (var item in sdkInfo) SdkRow (item.Value); } } // Indicate async operation in progress. using (new EditorGUILayout.HorizontalScope (GUILayout.ExpandWidth (false))) EditorGUILayout.LabelField (stillWorking ? activity : " "); using (new EditorGUILayout.HorizontalScope ()) { GUILayout.Space (10); if (!stillWorking) { if (GUILayout.Button ("Done", fieldWidth)) Close (); } else { if (GUILayout.Button ("Cancel", fieldWidth)) CancelOperation (); } if (GUILayout.Button ("Help", fieldWidth)) Application.OpenURL (AmazonConstants.helpLink); } } private void SdkHeaders () { using (new EditorGUILayout.HorizontalScope (GUILayout.ExpandWidth (false))) { GUILayout.Space (10); EditorGUILayout.LabelField ("Package", headerStyle); GUILayout.Button ("Version", headerStyle); GUILayout.Space (3); GUILayout.Button ("Action", headerStyle, fieldWidth); GUILayout.Button (" ", headerStyle, GUILayout.Width (1)); GUILayout.Space (5); } GUILayout.Space (4); } private void SdkRow (SdkInfo info, Func customButton = null) { var lat = info.LatestVersion; var cur = info.CurrentVersion; var isInst = !string.IsNullOrEmpty (cur); var canInst = !string.IsNullOrEmpty (lat) && (!isInst || AmazonUtils.CompareVersions (cur, lat) < 0); // Is any async job in progress? var stillWorking = coroutine != null || downloader != null; string tooltip = string.Empty; if (isInst && (AmazonUtils.CompareVersions (cur, lat) != 0)) tooltip += "\n Installed: " + cur; if (!string.IsNullOrEmpty (tooltip)) tooltip = info.Name + "\n Package: " + (lat ?? "n/a") + tooltip; GUILayout.Space (4); using (new EditorGUILayout.HorizontalScope (GUILayout.ExpandWidth (false))) { GUILayout.Space (10); EditorGUILayout.LabelField (new GUIContent { text = info.Name, tooltip = tooltip }); GUILayout.Button (new GUIContent { text = lat ?? "--", tooltip = tooltip }, canInst ? EditorStyles.boldLabel : EditorStyles.label); GUILayout.Space (3); if (customButton == null || !customButton (canInst)) { GUI.enabled = !stillWorking && (canInst); if (GUILayout.Button (new GUIContent { text = isInst ? "Upgrade" : "Install", tooltip = tooltip }, fieldWidth)) this.StartCoroutine (DownloadSDK (info)); GUI.enabled = true; } // Need to fill space so that the Install/Upgrade buttons all line up nicely. GUILayout.Button (" ", EditorStyles.label, GUILayout.Width (17)); GUILayout.Space (5); } GUILayout.Space (4); } private void CancelOperation () { // Stop any async action taking place. if (downloader != null) { downloader.Abort (); // The coroutine should resume and clean up. return; } if (coroutine != null) this.StopCoroutine (coroutine.routine); coroutine = null; downloader = null; } private IEnumerator DownloadSDK (SdkInfo info) { var path = Path.Combine (downloadDir, info.Filename); activity = string.Format ("Downloading {0}...", info.Filename); Debug.Log (activity); // Start the async download job. downloader = new UnityWebRequest (info.Url) { downloadHandler = new DownloadHandlerFile (path), timeout = 60, // seconds }; downloader.SendWebRequest (); // Pause until download done/cancelled/fails, keeping progress bar up to date. while (!downloader.isDone) { yield return null; var progress = Mathf.FloorToInt (downloader.downloadProgress * 100); if (EditorUtility.DisplayCancelableProgressBar ("Amazon SDK Manager", activity, progress)) downloader.Abort (); } EditorUtility.ClearProgressBar (); if (string.IsNullOrEmpty (downloader.error)) AssetDatabase.ImportPackage (path, true); // OK, got the file, so let the user import it if they want. else { var error = downloader.error; if (downloader.isNetworkError) { if (error.EndsWith ("destination host")) error += ": " + info.Url; } else if (downloader.isHttpError) { switch (downloader.responseCode) { case 404: var file = Path.GetFileName (new Uri (info.Url).LocalPath); error = string.Format ("File {0} not found on server.", file); break; default: error = downloader.responseCode + "\n" + error; break; } } Debug.LogError (error); } // Reset async state so the GUI is operational again. downloader.Dispose (); downloader = null; coroutine = null; } }