// Draw the array of leaderboards or achievements inside a foldout and the relevant buttons. void DrawGameServiceItemArray(string itemType, EMProperty myProp, ref bool isFoldout) { if (myProp.property.arraySize > 0) { EditorGUI.indentLevel++; isFoldout = EditorGUILayout.Foldout(isFoldout, myProp.property.arraySize + " " + myProp.content.text); EditorGUI.indentLevel--; if (isFoldout) { // Update the string array of Android GPGPS ids to display in the leaderboards and achievements. gpgsIds = new string[gpgsIdDict.Count + 1]; gpgsIds[0] = EM_Constants.NoneSymbol; gpgsIdDict.Keys.CopyTo(gpgsIds, 1); System.Action <SerializedProperty> drawer; if (itemType.Equals("Leaderboard")) { drawer = DrawGameServiceLeaderboard; } else if (itemType.Equals("Achievement")) { drawer = DrawGameServiceAchievement; } else { throw new System.Exception("Invalid itemType"); } // Draw the array of achievements or leaderboards. DrawArrayProperty(myProp.property, drawer); // Detect duplicate names. string duplicateName = EM_EditorUtil.FindDuplicateFieldInArrayProperty(myProp.property, GameServiceItem_NameProperty); if (!string.IsNullOrEmpty(duplicateName)) { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Found duplicate name of \"" + duplicateName + "\".", MessageType.Warning); } } } else { EditorGUILayout.HelpBox("No " + itemType + " added.", MessageType.None); } EditorGUILayout.Space(); if (GUILayout.Button("Add New " + itemType, GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { // Add new leaderboard. AddNewGameServiceItem(myProp.property); // Open the foldout if it's closed. isFoldout = true; } }
// Generate a static class containing constants of IAP product names. void GenerateIAPConstants() { // First create a hashtable containing all the names to be stored as constants. SerializedProperty productsProp = IAPProperties.products.property; // First check if there're duplicate names. string duplicateName = EM_EditorUtil.FindDuplicateFieldInArrayProperty(productsProp, IAPProduct_NameProperty); if (!string.IsNullOrEmpty(duplicateName)) { EM_EditorUtil.Alert("Error: Duplicate Names", "Found duplicate product name of \"" + duplicateName + "\"."); return; } // Proceed with adding resource keys. Hashtable resourceKeys = new Hashtable(); // Add the product names. for (int i = 0; i < productsProp.arraySize; i++) { SerializedProperty element = productsProp.GetArrayElementAtIndex(i); string name = element.FindPropertyRelative(IAPProduct_NameProperty).stringValue; // Ignore all items with an empty name. if (!string.IsNullOrEmpty(name)) { string key = "Product_" + name; resourceKeys.Add(key, name); } } if (resourceKeys.Count > 0) { // Now build the class. EM_EditorUtil.GenerateConstantsClass( EM_Constants.GeneratedFolder, EM_Constants.RootNameSpace + "." + EM_Constants.IAPConstantsClassName, resourceKeys, true ); } else { EM_EditorUtil.Alert("Constants Class Generation", "Please fill in required information for all products."); } }
//---------------------------------------------------------------- // Draw Category Groups //---------------------------------------------------------------- void DrawNotificationCategoryGroupsArray(EMProperty prop, ref bool isFoldout) { if (prop.property.arraySize <= 0) { EditorGUILayout.HelpBox(NotificationCategoryGroupIntro, MessageType.Info); } else { EditorGUILayout.HelpBox(NotificationCategoryGroupInvalidWarning, MessageType.None); EditorGUI.indentLevel++; isFoldout = EditorGUILayout.Foldout(isFoldout, prop.property.arraySize + " " + prop.content.text); EditorGUI.indentLevel--; if (isFoldout) { // Draw the array of category groups. DrawArrayProperty(prop.property, DrawNotificationCategoryGroup); // Detect duplicate names. string duplicateId = EM_EditorUtil.FindDuplicateFieldInArrayProperty(prop.property, NotificationCategoryGroup_Id); if (!string.IsNullOrEmpty(duplicateId)) { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Found duplicate category group ID of \"" + duplicateId + "\".", MessageType.Warning); } } } EditorGUILayout.Space(); if (GUILayout.Button("Add New Category Group", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { // Add new category group. AddNewNotificationCategoryGroup(prop.property); // Open the foldout if it's closed. isFoldout = true; } }
void IAPModuleGUI() { DrawModuleHeader(); // Now draw the GUI. if (!isIAPModuleEnable.boolValue) { return; } #if !EM_UIAP EditorGUILayout.Space(); EditorGUILayout.BeginVertical(EM_GUIStyleManager.UppercaseSectionBox); EditorGUILayout.HelpBox(UnityIAPEnableInstruction, MessageType.Error, true); EditorGUILayout.EndVertical(); #else EditorGUILayout.Space(); DrawUppercaseSection("IAP_AUTO_INIT_CONFIG", "AUTO INITIALIZATION", () => { EditorGUILayout.PropertyField(IAPProperties.autoInit.property, IAPProperties.autoInit.content); if (!IAPProperties.autoInit.property.boolValue) { EditorGUILayout.HelpBox(IAPManualInitInstruction, MessageType.Info); } }); // Select target Android store, like using the Window > Unity IAP > Android > Target ... menu item. EditorGUILayout.Space(); DrawUppercaseSection("ANDROID_TARGET_STORE_FOLDOUT_KEY", "TARGET ANDROID STORE", () => { EditorGUI.BeginChangeCheck(); IAPProperties.targetAndroidStore.property.enumValueIndex = EditorGUILayout.Popup( IAPProperties.targetAndroidStore.content.text, IAPProperties.targetAndroidStore.property.enumValueIndex, IAPProperties.targetAndroidStore.property.enumDisplayNames ); if (EditorGUI.EndChangeCheck()) { SetTargetAndroidStore((IAPAndroidStore)IAPProperties.targetAndroidStore.property.enumValueIndex); } // Enable Amazon sandbox testing. androidStore = (IAPAndroidStore)IAPProperties.targetAndroidStore.property.enumValueIndex; if (androidStore == IAPAndroidStore.AmazonAppStore) { EditorGUILayout.PropertyField(IAPProperties.enableAmazoneSandboxTesting.property, IAPProperties.enableAmazoneSandboxTesting.content); } }); // Apple's Ask To Buy settings. EditorGUILayout.Space(); DrawUppercaseSection("APPLE_ASK_TO_BUY_FOLDOUT_KEY", "APPLE ASK-TO-BUY", () => { // Apple Ask To Buy simulation in sandbox. EditorGUILayout.PropertyField(IAPProperties.simulateAppleAskToBuy.property, IAPProperties.simulateAppleAskToBuy.content); }); // Apple's promotional purchases settings. EditorGUILayout.Space(); DrawUppercaseSection("APPLE_PROMOTIONAL_PURCHASES_FOLDOUT_KEY", "APPLE PROMOTIONAL PURCHASES", () => { // Whether to intercept Apple's promotional purchases. EditorGUILayout.PropertyField(IAPProperties.interceptApplePromotionalPurchases.property, IAPProperties.interceptApplePromotionalPurchases.content); }); // Receipt validation EditorGUILayout.Space(); DrawUppercaseSection("RECEIPT_VALIDATION_FOLDOUT_KEY", "RECEIPT VALIDATION", () => { EditorGUILayout.HelpBox("Unity IAP offers local receipt validation for extra security. Apple stores and Google Play store only.", MessageType.None); // iOS store. EditorGUI.BeginDisabledGroup(!isAppleTangleValid); IAPProperties.validateAppleReceipt.property.boolValue = EditorGUILayout.Toggle(IAPProperties.validateAppleReceipt.content, IAPProperties.validateAppleReceipt.property.boolValue); EditorGUI.EndDisabledGroup(); // Always disable the option if AppleTangle is not valid. if (!isAppleTangleValid) { IAPProperties.validateAppleReceipt.property.boolValue = false; } // Google Play store. bool isTargetingGooglePlay = androidStore == IAPAndroidStore.GooglePlay; EditorGUI.BeginDisabledGroup(!isGooglePlayTangleValid); IAPProperties.validateGooglePlayReceipt.property.boolValue = EditorGUILayout.Toggle(IAPProperties.validateGooglePlayReceipt.content, IAPProperties.validateGooglePlayReceipt.property.boolValue); EditorGUI.EndDisabledGroup(); // Always disable the option if GooglePlayTangle is not valid. if (!isGooglePlayTangleValid) { IAPProperties.validateGooglePlayReceipt.property.boolValue = false; } if (!isAppleTangleValid || (!isGooglePlayTangleValid && isTargetingGooglePlay)) { string rvMsg = "Please go to Window > Unity IAP > IAP Receipt Validation Obfuscator and create obfuscated secrets to enable receipt validation for Apple stores and Google Play store."; if (!isAppleTangleValid) { rvMsg += " Note that you don't need to provide a Google Play public key if you're only targeting Apple stores."; } else { rvMsg = rvMsg.Replace("Apple stores and ", ""); } if (isGooglePlayTangleValid || !isTargetingGooglePlay) { rvMsg = rvMsg.Replace(" and Google Play store", ""); } EditorGUILayout.HelpBox(rvMsg, MessageType.Warning); } }); // Product list EditorGUILayout.Space(); DrawUppercaseSection("PRODUCTS_FOLDOUT_KEY", "PRODUCTS", () => { EMProperty products = IAPProperties.products; if (products.property.arraySize > 0) { EditorGUI.indentLevel++; isIAPProductsFoldout = EditorGUILayout.Foldout(isIAPProductsFoldout, products.property.arraySize + " " + products.content.text, true); EditorGUI.indentLevel--; if (isIAPProductsFoldout) { // Draw the array of IAP products. DrawArrayProperty(products.property, DrawIAPProduct); // Detect duplicate product names. string duplicateName = EM_EditorUtil.FindDuplicateFieldInArrayProperty(products.property, IAPProduct_NameProperty); if (!string.IsNullOrEmpty(duplicateName)) { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Found duplicate name of \"" + duplicateName + "\".", MessageType.Warning); } } } else { EditorGUILayout.HelpBox("No products added.", MessageType.None); } if (GUILayout.Button("Add New Product", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { // Add new IAP product. AddNewProduct(products.property); // Open the foldout if it's closed. isIAPProductsFoldout = true; } }); // Constant generation. EditorGUILayout.Space(); DrawUppercaseSection("IAP_CONTANTS_GENERATION_FOLDOUT_KEY", "CONSTANTS GENERATION", () => { EditorGUILayout.HelpBox(IAPConstantGenerationIntro, MessageType.None); if (GUILayout.Button("Generate Constants Class", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { GenerateIAPConstants(); } }); #endif }
void IAPModuleGUI() { EditorGUILayout.BeginVertical(EM_GUIStyleManager.GetCustomStyle("Module Box")); EditorGUI.BeginChangeCheck(); isIAPModuleEnable.boolValue = EM_EditorGUI.ModuleToggle(isIAPModuleEnable.boolValue, IAPModuleLabel); if (EditorGUI.EndChangeCheck()) { GameObject prefab = EM_EditorUtil.GetMainPrefab(); if (!isIAPModuleEnable.boolValue) { EM_PluginManager.DisableIAPModule(prefab); } else { EM_PluginManager.EnableIAPModule(prefab); } } // Now draw the GUI. if (!isIAPModuleEnable.boolValue) { EditorGUILayout.Space(); EditorGUILayout.HelpBox(IAPModuleIntro, MessageType.Info); } else { #if !EM_UIAP EditorGUILayout.Space(); EditorGUILayout.HelpBox(UnityIAPEnableInstruction, MessageType.Error); #else // Select target Android store, like using the Window > Unity IAP > Android > Target ... menu item. EditorGUILayout.Space(); EditorGUILayout.LabelField("[ANDROID] TARGET STORE", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); IAPProperties.targetAndroidStore.property.enumValueIndex = EditorGUILayout.Popup( IAPProperties.targetAndroidStore.content.text, IAPProperties.targetAndroidStore.property.enumValueIndex, IAPProperties.targetAndroidStore.property.enumDisplayNames ); if (EditorGUI.EndChangeCheck()) { SetTargetAndroidStore((IAPAndroidStore)IAPProperties.targetAndroidStore.property.enumValueIndex); } // Receipt validation EditorGUILayout.Space(); EditorGUILayout.LabelField("RECEIPT VALIDATION", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Unity IAP offers local receipt validation for extra security. Apple stores and Google Play store only.", MessageType.None); // iOS store. EditorGUI.BeginDisabledGroup(!isAppleTangleValid); IAPProperties.validateAppleReceipt.property.boolValue = EditorGUILayout.Toggle(IAPProperties.validateAppleReceipt.content, IAPProperties.validateAppleReceipt.property.boolValue); EditorGUI.EndDisabledGroup(); // Always disable the option if AppleTangle is not valid. if (!isAppleTangleValid) { IAPProperties.validateAppleReceipt.property.boolValue = false; } // Google Play store. bool isTargetingGooglePlay = IAPProperties.targetAndroidStore.property.enumValueIndex == (int)IAPAndroidStore.GooglePlay; EditorGUI.BeginDisabledGroup(!isGooglePlayTangleValid); IAPProperties.validateGooglePlayReceipt.property.boolValue = EditorGUILayout.Toggle(IAPProperties.validateGooglePlayReceipt.content, IAPProperties.validateGooglePlayReceipt.property.boolValue); EditorGUI.EndDisabledGroup(); // Always disable the option if GooglePlayTangle is not valid. if (!isGooglePlayTangleValid) { IAPProperties.validateGooglePlayReceipt.property.boolValue = false; } if (!isAppleTangleValid || (!isGooglePlayTangleValid && isTargetingGooglePlay)) { string rvMsg = "Please go to Window > Unity IAP > IAP Receipt Validation Obfuscator and create obfuscated secrets to enable receipt validation for Apple stores and Google Play store."; if (!isAppleTangleValid) { rvMsg += " Note that you don't need to provide a Google Play public key if you're only targeting Apple stores."; } else { rvMsg = rvMsg.Replace("Apple stores and ", ""); } if (isGooglePlayTangleValid || !isTargetingGooglePlay) { rvMsg = rvMsg.Replace(" and Google Play store", ""); } EditorGUILayout.HelpBox(rvMsg, MessageType.Warning); } // Product list EditorGUILayout.Space(); EditorGUILayout.LabelField("PRODUCTS", EditorStyles.boldLabel); EMProperty products = IAPProperties.products; if (products.property.arraySize > 0) { EditorGUI.indentLevel++; isIAPProductsFoldout = EditorGUILayout.Foldout(isIAPProductsFoldout, products.property.arraySize + " " + products.content.text); EditorGUI.indentLevel--; if (isIAPProductsFoldout) { // Draw the array of IAP products. DrawArrayProperty(products.property, DrawIAPProduct); // Detect duplicate product names. string duplicateName = EM_EditorUtil.FindDuplicateFieldInArrayProperty(products.property, IAPProduct_NameProperty); if (!string.IsNullOrEmpty(duplicateName)) { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Found duplicate name of \"" + duplicateName + "\".", MessageType.Warning); } } } else { EditorGUILayout.HelpBox("No products added.", MessageType.None); } EditorGUILayout.Space(); if (GUILayout.Button("Add New Product", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { // Add new IAP product. AddNewProduct(products.property); // Open the foldout if it's closed. isIAPProductsFoldout = true; } // Constant generation. EditorGUILayout.Space(); EditorGUILayout.LabelField("CONSTANTS GENERATION", EditorStyles.boldLabel); EditorGUILayout.HelpBox(IAPConstantGenerationIntro, MessageType.None); EditorGUILayout.Space(); if (GUILayout.Button("Generate Constants Class", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { GenerateIAPConstants(); } #endif } EditorGUILayout.EndVertical(); }
string[] BuildListOfNotificationCategoryGroupsName(IDictionary <string, string> categoryGroupsDict) { if (categoryGroupsDict == null) { return new string[] { EM_Constants.NoneSymbol } } ; var list = new string[categoryGroupsDict.Count + 1]; // Add "None" as first item. list[0] = EM_Constants.NoneSymbol; // Copy keys from the dict. categoryGroupsDict.Keys.CopyTo(list, 1); return(list); } string GetNotificationCategoryNameFromId(IDictionary <string, string> dict, string id) { string name = string.Empty; if (string.IsNullOrEmpty(id)) { name = EM_Constants.NoneSymbol; } else if (dict != null) { name = EM_EditorUtil.GetKeyForValue(dict, id); } return(name); } // Generate a static class containing constants of category IDs. void GenerateNotificationConstants() { // First create a hashtable containing all the names to be stored as constants. SerializedProperty userCategoriesProp = NotificationProperties.userCategories.property; // First check if there're duplicate IDs. string duplicateID = EM_EditorUtil.FindDuplicateFieldInArrayProperty(userCategoriesProp, NotificationCategory_Id); if (!string.IsNullOrEmpty(duplicateID)) { EM_EditorUtil.Alert("Error: Duplicate IDs", "Found duplicate category ID of \"" + duplicateID + "\"."); return; } // Proceed with adding resource keys. Hashtable resourceKeys = new Hashtable(); // Add the category IDs. for (int i = 0; i < userCategoriesProp.arraySize; i++) { SerializedProperty element = userCategoriesProp.GetArrayElementAtIndex(i); string id = element.FindPropertyRelative(NotificationCategory_Id).stringValue; // Ignore all items with an empty ID. if (!string.IsNullOrEmpty(id)) { string key = "UserCategory_" + id; resourceKeys.Add(key, id); } } if (resourceKeys.Count > 0) { // Now build the class. EM_EditorUtil.GenerateConstantsClass( EM_Constants.GeneratedFolder, EM_Constants.RootNameSpace + "." + EM_Constants.NotificationsConstantsClassName, resourceKeys, true ); } else { EM_EditorUtil.Alert("Constants Class Generation", "No user category has been defined or category ID is missing."); } } //---------------------------------------------------------------- // Importing Android Notification Res Folder //---------------------------------------------------------------- void ImportAndroidNotificationResFolder() { string selectedFolder = EditorUtility.OpenFolderPanel(null, notificationSelectedAndroidResFolder, null); if (!string.IsNullOrEmpty(selectedFolder)) { // Some folder was selected. notificationSelectedAndroidResFolder = selectedFolder; // Build Android library from the selected folder. if (EM_EditorUtil.DisplayDialog( "Building Android Resources", "Please make sure the selected folder is correct before proceeding.\n" + notificationSelectedAndroidResFolder, "Go Ahead", "Cancel")) { // Prepare the lib config. var config = new EM_AndroidLibBuilder.AndroidLibConfig(); config.packageName = EM_Constants.AndroidNativeNotificationPackageName; config.targetLibFolderName = EM_Constants.NotificationAndroidResFolderName; config.targetContentFolderName = "res"; EM_AndroidLibBuilder.BuildAndroidLibFromFolder( notificationSelectedAndroidResFolder, config, OnAndroidNotificationResBuildProgress, OnAndroidNotificationResBuildNewStep, OnAndroidNotificationResBuildComplete ); } } } void OnAndroidNotificationResBuildProgress(float progress) { // Display progress bar. EditorUtility.DisplayProgressBar( "Generating Android Notification Resources", notificationCreateAndroidResCurrentStep, progress ); } void OnAndroidNotificationResBuildNewStep(string step) { notificationCreateAndroidResCurrentStep = step; } void OnAndroidNotificationResBuildComplete() { EditorUtility.ClearProgressBar(); EM_EditorUtil.Alert( "Android Resources Imported", "Android notification resources have been imported successfully!" ); } }
// Generate a static class containing constants of leaderboard and achievement names. void GenerateGameServiceConstants() { // First create a hashtable containing all the names to be stored as constants. SerializedProperty ldbProp = GameServiceProperties.leaderboards.property; SerializedProperty acmProp = GameServiceProperties.achievements.property; // First check if there're duplicate names. string duplicateLdbName = EM_EditorUtil.FindDuplicateFieldInArrayProperty(ldbProp, GameServiceItem_NameProperty); if (!string.IsNullOrEmpty(duplicateLdbName)) { EM_EditorUtil.Alert("Error: Duplicate Names", "Found duplicate leaderboard name of \"" + duplicateLdbName + "\"."); return; } string duplicateAcmName = EM_EditorUtil.FindDuplicateFieldInArrayProperty(acmProp, GameServiceItem_NameProperty); if (!string.IsNullOrEmpty(duplicateAcmName)) { EM_EditorUtil.Alert("Error: Duplicate Names", "Found duplicate achievement name of \"" + duplicateAcmName + "\"."); return; } // Proceed with adding resource keys. Hashtable resourceKeys = new Hashtable(); // Add the leaderboard names. for (int i = 0; i < ldbProp.arraySize; i++) { SerializedProperty element = ldbProp.GetArrayElementAtIndex(i); string name = element.FindPropertyRelative(GameServiceItem_NameProperty).stringValue; // Ignore all items with an empty name. if (!string.IsNullOrEmpty(name)) { string key = "Leaderboard_" + name; resourceKeys.Add(key, name); } } // Add the achievement names. for (int j = 0; j < acmProp.arraySize; j++) { SerializedProperty element = acmProp.GetArrayElementAtIndex(j); string name = element.FindPropertyRelative(GameServiceItem_NameProperty).stringValue; // Ignore all items with an empty name. if (!string.IsNullOrEmpty(name)) { string key = "Achievement_" + name; resourceKeys.Add(key, name); } } if (resourceKeys.Count > 0) { // Now build the class. EM_EditorUtil.GenerateConstantsClass( EM_Constants.GeneratedFolder, EM_Constants.RootNameSpace + "." + EM_Constants.GameServicesConstantsClassName, resourceKeys, true ); } else { EM_EditorUtil.Alert("Constants Class Generation", "Please fill in required information for all leaderboards and achievements."); } }