public void OnPostGenerateGradleAndroidProject(string path) { #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 buildScriptChangesAdded = AddQualityServiceBuildScriptLines(rootGradleBuildFilePath); if (!buildScriptChangesAdded) { return; } // 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)) { MaxSdkLogger.UserWarning("Couldn't find build.gradle file. Failed to add AppLovin Quality Service plugin to the gradle project."); return; } AddAppLovinQualityServicePlugin(applicationGradleBuildFilePath); }
public AdInfo(string adInfoString) { string adUnitIdentifier; string networkName; string creativeIdentifier; string placement; string revenue; // NOTE: Unity Editor creates empty string var adInfoObject = MaxSdkUtils.PropsStringToDict(adInfoString); AdUnitIdentifier = adInfoObject.TryGetValue("adUnitId", out adUnitIdentifier) ? adUnitIdentifier : ""; NetworkName = adInfoObject.TryGetValue("networkName", out networkName) ? networkName : ""; CreativeIdentifier = adInfoObject.TryGetValue("creativeId", out creativeIdentifier) ? creativeIdentifier : ""; Placement = adInfoObject.TryGetValue("placement", out placement) ? placement : ""; if (adInfoObject.TryGetValue("revenue", out revenue)) { try { // InvariantCulture guarantees the decimal is used for the separator even in regions that use commas as the separator Revenue = double.Parse(revenue, NumberStyles.Any, CultureInfo.InvariantCulture); } catch (Exception exception) { MaxSdkLogger.E("Failed to parse double (" + revenue + ") with exception: " + exception); Revenue = -1; } } else { Revenue = -1; } }
private static void AddSnapAppStoreAppIdIfNeeded(PlistDocument plist) { var snapDependencyPath = Path.Combine(PluginMediationDirectory, "Snap/Editor/Dependencies.xml"); if (!File.Exists(snapDependencyPath)) { return; } // App Store App ID is only needed for iOS versions 2.0.0.0 or newer. var currentVersion = AppLovinIntegrationManager.GetCurrentVersions(snapDependencyPath); var iosVersionComparison = MaxSdkUtils.CompareVersions(currentVersion.Ios, AppLovinSettings.SnapAppStoreAppIdMinVersion); if (iosVersionComparison == MaxSdkUtils.VersionComparisonResult.Lesser) { return; } if (AppLovinSettings.Instance.SnapAppStoreAppId <= 0) { MaxSdkLogger.UserError("Snap App Store App ID is not set. Please enter a valid App ID within the AppLovin Integration Manager window."); return; } plist.root.SetInteger("SCAppStoreAppID", AppLovinSettings.Instance.SnapAppStoreAppId); }
public void OnPostGenerateGradleAndroidProject(string path) { var gradlePropertiesPath = Path.Combine(path, "../gradle.properties"); var gradlePropertiesUpdated = new List <string>(); // If the gradle properties file already exists, make sure to add any previous properties. if (File.Exists(gradlePropertiesPath)) { var lines = File.ReadAllLines(gradlePropertiesPath); // Add all properties except AndroidX and Jetifier, since they could be disabled. We will add them below with those properties enabled. gradlePropertiesUpdated.AddRange(lines.Where(line => !line.Contains(PropertyAndroidX) && !line.Contains(PropertyJetifier))); } // Enable AndroidX and Jetifier properties gradlePropertiesUpdated.Add(PropertyAndroidX + EnableProperty); gradlePropertiesUpdated.Add(PropertyJetifier + EnableProperty); try { File.WriteAllText(gradlePropertiesPath, string.Join("\n", gradlePropertiesUpdated.ToArray()) + "\n"); } catch (Exception exception) { MaxSdkLogger.UserError("Failed to enable AndroidX and Jetifier. gradle.properties file write failed."); Console.WriteLine(exception); } }
public ErrorInfo(IDictionary <string, string> errorInfoDictionary) { string code; string message; string adLoadFailureInfo; Message = errorInfoDictionary.TryGetValue("errorMessage", out message) ? message : ""; AdLoadFailureInfo = errorInfoDictionary.TryGetValue("adLoadFailureInfo", out adLoadFailureInfo) ? adLoadFailureInfo : ""; if (errorInfoDictionary.TryGetValue("errorCode", out code)) { try { Code = (ErrorCode)int.Parse(code); } catch (Exception exception) { MaxSdkLogger.E("Failed to parse int (" + code + ") with exception: " + exception); Code = ErrorCode.Unspecified; } } else { Code = ErrorCode.Unspecified; } }
private static void UpdateAppTransportSecuritySettingsIfNeeded(PlistDocument plist) { var pluginParentDir = AppLovinIntegrationManager.MediationSpecificPluginParentDirectory; var mediationDir = Path.Combine(pluginParentDir, "MaxSdk/Mediation/"); var projectHasAtsRequiringNetworks = AtsRequiringNetworks.Any(atsRequiringNetwork => Directory.Exists(Path.Combine(mediationDir, atsRequiringNetwork))); if (!projectHasAtsRequiringNetworks) { return; } var root = plist.root.values; PlistElement atsRoot; root.TryGetValue("NSAppTransportSecurity", out atsRoot); if (atsRoot == null || atsRoot.GetType() != typeof(PlistElementDict)) { // Add the missing App Transport Security settings for publishers if needed. MaxSdkLogger.UserDebug("Adding App Transport Security settings..."); atsRoot = plist.root.CreateDict("NSAppTransportSecurity"); atsRoot.AsDict().SetBoolean("NSAllowsArbitraryLoads", true); } var atsRootDict = atsRoot.AsDict().values; // Check if both NSAllowsArbitraryLoads and NSAllowsArbitraryLoadsInWebContent are present and remove NSAllowsArbitraryLoadsInWebContent if both are present. if (atsRootDict.ContainsKey("NSAllowsArbitraryLoads") && atsRootDict.ContainsKey("NSAllowsArbitraryLoadsInWebContent")) { MaxSdkLogger.UserDebug("Removing NSAllowsArbitraryLoadsInWebContent"); atsRootDict.Remove("NSAllowsArbitraryLoadsInWebContent"); } }
protected static void ValidateAdUnitIdentifier(string adUnitIdentifier, string debugPurpose) { if (string.IsNullOrEmpty(adUnitIdentifier)) { MaxSdkLogger.UserError("No MAX Ads Ad Unit ID specified for: " + debugPurpose); } }
static MaxInitialize() { AppLovinAutoUpdater.Update(); #if UNITY_IOS // Check that the publisher is targeting iOS 9.0+ if (!PlayerSettings.iOS.targetOSVersionString.StartsWith("9.") && !PlayerSettings.iOS.targetOSVersionString.StartsWith("1")) { MaxSdkLogger.UserError("Detected iOS project version less than iOS 9 - The AppLovin MAX SDK WILL NOT WORK ON < iOS9!!!"); } #endif var changesMade = false; // Check if we have legacy adapter CHANGELOGs. foreach (var network in Networks) { var mediationAdapterDir = Path.Combine("Assets", "MaxSdk/Mediation/" + network); // If new directory exists if (CheckExistence(mediationAdapterDir)) { var androidChangelogFile = Path.Combine(mediationAdapterDir, AndroidChangelog); if (CheckExistence(androidChangelogFile)) { FileUtil.DeleteFileOrDirectory(androidChangelogFile); changesMade = true; } var iosChangelogFile = Path.Combine(mediationAdapterDir, IosChangelog); if (CheckExistence(iosChangelogFile)) { FileUtil.DeleteFileOrDirectory(iosChangelogFile); changesMade = true; } } } // Check if any obsolete networks are installed foreach (var obsoleteNetwork in ObsoleteNetworks) { var networkDir = Path.Combine("Assets", "MaxSdk/Mediation/" + obsoleteNetwork); if (CheckExistence(networkDir)) { MaxSdkLogger.UserDebug("Deleting obsolete network " + obsoleteNetwork + " from path " + networkDir + "..."); FileUtil.DeleteFileOrDirectory(networkDir); changesMade = true; } } // Refresh UI if (changesMade) { AssetDatabase.Refresh(); MaxSdkLogger.UserDebug("AppLovin MAX Migration completed"); } }
/// <summary> /// Show cross promo ad at a position determined by the 'CreateCrossPromoAd' call. /// </summary> /// <param name="adUnitIdentifier">Ad unit identifier of the cross promo ad to show</param> public static void ShowCrossPromoAd(string adUnitIdentifier) { ValidateAdUnitIdentifier(adUnitIdentifier, "show cross promo ad"); if (!IsAdUnitRequested(adUnitIdentifier)) { MaxSdkLogger.UserWarning("Cross promo ad '" + adUnitIdentifier + "' was not created, can not show it"); } }
private static void _ensureHaveSdkKey() { if (_hasSdkKey) { return; } MaxSdkLogger.UserWarning( "MAX Ads SDK did not receive SDK key. Please call Max.SetSdkKey() to assign it"); }
/// <summary> /// Show MREC at a position determined by the 'CreateMRec' call. /// </summary> /// <param name="adUnitIdentifier">Ad unit identifier of the MREC to show</param> public static void ShowMRec(string adUnitIdentifier) { ValidateAdUnitIdentifier(adUnitIdentifier, "show MREC"); if (!IsAdUnitRequested(adUnitIdentifier)) { MaxSdkLogger.UserWarning("MREC '" + adUnitIdentifier + "' was not created, can not show it"); } }
private static void InvokeEvent(Action evt) { if (!CanInvokeEvent(evt)) { return; } MaxSdkLogger.UserDebug("Invoking event: " + evt); evt(); }
public static ConsentDialogState GetConsentDialogState() { if (!IsInitialized()) { MaxSdkLogger.UserWarning( "MAX Ads SDK has not been initialized yet. GetConsentDialogState() may return ConsentDialogState.Unknown"); } return((ConsentDialogState)MaxUnityPluginClass.CallStatic <int>("getConsentDialogState")); }
private static void InvokeEvent <T>(Action <T> evt, T param) { if (!CanInvokeEvent(evt)) { return; } MaxSdkLogger.UserDebug("Invoking event: " + evt + ". Param: " + param); evt(param); }
/// <summary> /// Get the consent dialog state for this user. If no such determination could be made, <see cref="MaxSdkBase.ConsentDialogState.Unknown"/> will be returned. /// /// Note: this method should be called only after SDK has been initialized /// </summary> public static ConsentDialogState GetConsentDialogState() { if (!IsInitialized()) { MaxSdkLogger.UserWarning( "MAX Ads SDK has not been initialized yet. GetConsentDialogState() may return ConsentDialogState.Unknown"); } return((ConsentDialogState)_MaxConsentDialogState()); }
private static void InvokeEvent <T1, T2>(Action <T1, T2> evt, T1 param1, T2 param2) { if (!CanInvokeEvent(evt)) { return; } MaxSdkLogger.UserDebug("Invoking event: " + evt + ". Params: " + param1 + ", " + param2); evt(param1, param2); }
private static void _ensureInitialized() { _ensureHaveSdkKey(); if (_isInitialized) { return; } MaxSdkLogger.UserWarning( "MAX Ads SDK is not initialized by the time ad is requested. Please call Max.InitializeSdk() in your first scene"); }
/// <summary> /// Shows a dialog to the user with the given message and logs the error message to console. /// </summary> /// <param name="message">The failure message to be shown to the user.</param> public static void ShowBuildFailureDialog(string message) { var openIntegrationManager = EditorUtility.DisplayDialog("AppLovin MAX", message, "Open Integration Manager", "Dismiss"); if (openIntegrationManager) { AppLovinIntegrationManagerWindow.ShowManager(); } MaxSdkLogger.UserError(message); }
// Allocate the MaxSdkCallbacks singleton, which receives all callback events from the native SDKs. protected static void InitCallbacks() { var type = typeof(MaxSdkCallbacks); var mgr = new GameObject("MaxSdkCallbacks", type) .GetComponent <MaxSdkCallbacks>(); // Its Awake() method sets Instance. if (MaxSdkCallbacks.Instance != mgr) { MaxSdkLogger.UserWarning("It looks like you have the " + type.Name + " on a GameObject in your scene. Please remove the script from your scene."); } }
private static SkAdNetworkData GetSkAdNetworkData() { var uriBuilder = new UriBuilder("https://dash.applovin.com/docs/v1/unity_integration_manager/sk_ad_networks_info"); // Get the list of installed ad networks to be passed up var pluginParentDir = AppLovinIntegrationManager.MediationSpecificPluginParentDirectory; var maxMediationDirectory = Path.Combine(pluginParentDir, "MaxSdk/Mediation/"); if (Directory.Exists(maxMediationDirectory)) { var mediationNetworkDirectories = Directory.GetDirectories(maxMediationDirectory); var installedNetworks = mediationNetworkDirectories.Select(Path.GetFileName).ToArray(); var adNetworks = string.Join(",", installedNetworks); if (!string.IsNullOrEmpty(adNetworks)) { uriBuilder.Query += string.Format("adnetworks={0}", adNetworks); } } var unityWebRequest = UnityWebRequest.Get(uriBuilder.ToString()); #if UNITY_2017_2_OR_NEWER var operation = unityWebRequest.SendWebRequest(); #else var operation = unityWebRequest.Send(); #endif // Wait for the download to complete or the request to timeout. while (!operation.isDone) { } #if UNITY_2020_1_OR_NEWER if (unityWebRequest.result != UnityWebRequest.Result.Success) #elif UNITY_2017_2_OR_NEWER if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError) #else if (unityWebRequest.isError) #endif { MaxSdkLogger.UserError("Failed to retrieve SKAdNetwork IDs with error: " + unityWebRequest.error); return(new SkAdNetworkData()); } 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()); } }
/// <summary> /// Updates the provided Gradle script to add Quality Service plugin. /// </summary> /// <param name="applicationGradleBuildFilePath">The gradle file to update.</param> protected void AddAppLovinQualityServicePlugin(string applicationGradleBuildFilePath) { if (!AppLovinSettings.Instance.QualityServiceEnabled) { return; } var sdkKey = AppLovinSettings.Instance.SdkKey; if (string.IsNullOrEmpty(sdkKey)) { MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. SDK Key is empty. Please enter the AppLovin SDK Key in the Integration Manager."); return; } // Retrieve the API Key using the SDK Key. var qualityServiceData = RetrieveQualityServiceData(sdkKey); var apiKey = qualityServiceData.api_key; if (string.IsNullOrEmpty(apiKey)) { MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. API Key is empty."); return; } // Generate the updated Gradle file that needs to be written. var lines = File.ReadAllLines(applicationGradleBuildFilePath).ToList(); var sanitizedLines = RemoveLegacySafeDkPlugin(lines); 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 ); // outputLines can be null if we couldn't add the plugin. if (outputLines == null) { return; } try { File.WriteAllText(applicationGradleBuildFilePath, string.Join("\n", outputLines.ToArray()) + "\n"); } catch (Exception exception) { MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. Gradle file write failed."); Console.WriteLine(exception); } }
/// <summary> /// Present the mediation debugger UI. /// This debugger tool provides the status of your integration for each third-party ad network. /// /// Please call this method after the SDK has initialized. /// </summary> public static void ShowMediationDebugger() { if (!_isInitialized) { MaxSdkLogger.UserWarning("The mediation debugger cannot be shown before the MAX SDK has been initialized." + "\nCall 'MaxSdk.InitializeSdk();' and listen for 'MaxSdkCallbacks.OnSdkInitializedEvent' before showing the mediation debugger."); } else { MaxSdkLogger.UserWarning("The mediation debugger cannot be shown in the Unity Editor. Please export the project to Android or iOS first."); } }
/// <summary> /// Present loaded rewarded interstitial ad for a given placement to tie ad events to. Note: if the rewarded interstitial ad is not ready to be displayed nothing will happen. /// </summary> /// <param name="adUnitIdentifier">Ad unit identifier of the rewarded interstitial to show</param> /// <param name="placement">The placement to tie the showing ad's events to</param> public static void ShowRewardedInterstitialAd(string adUnitIdentifier, string placement) { ValidateAdUnitIdentifier(adUnitIdentifier, "show rewarded interstitial ad"); if (IsRewardedInterstitialAdReady(adUnitIdentifier)) { _MaxShowRewardedInterstitialAd(adUnitIdentifier, placement); } else { MaxSdkLogger.UserWarning("Not showing MAX Ads rewarded interstitial ad: ad not ready"); } }
/// <summary> ready to be /// Present loaded rewarded ad for a given placement to tie ad events to. Note: if the rewarded ad is not ready to be displayed nothing will happen. /// </summary> /// <param name="adUnitIdentifier">Ad unit identifier of the interstitial to load</param> /// <param name="placement">The placement to tie the showing ad's events to</param> public static void ShowRewardedAd(string adUnitIdentifier, string placement) { ValidateAdUnitIdentifier(adUnitIdentifier, "show rewarded ad"); if (IsRewardedAdReady(adUnitIdentifier)) { MaxUnityPluginClass.CallStatic("showRewardedAd", adUnitIdentifier, placement); } else { MaxSdkLogger.UserWarning("Not showing MAX Ads rewarded ad: ad not ready"); } }
/// <summary> /// Present loaded interstitial for a given placement to tie ad events to. Note: if the interstitial is not ready to be displayed nothing will happen. /// </summary> /// <param name="adUnitIdentifier">Ad unit identifier of the interstitial to load</param> /// <param name="placement">The placement to tie the showing ad's events to</param> public static void ShowInterstitial(string adUnitIdentifier, string placement) { ValidateAdUnitIdentifier(adUnitIdentifier, "show interstitial"); if (IsInterstitialReady(adUnitIdentifier)) { _MaxShowInterstitial(adUnitIdentifier, placement); } else { MaxSdkLogger.UserWarning("Not showing MAX Ads interstitial: ad not ready"); } }
/// <summary> /// Check if rewarded interstitial ad ad is loaded and ready to be displayed. /// </summary> /// <param name="adUnitIdentifier">Ad unit identifier of the rewarded ad to load</param> /// <returns>True if the ad is ready to be displayed</returns> public static bool IsRewardedInterstitialAdReady(string adUnitIdentifier) { ValidateAdUnitIdentifier(adUnitIdentifier, "check rewarded interstitial ad loaded"); if (!IsAdUnitRequested(adUnitIdentifier)) { MaxSdkLogger.UserWarning("Rewarded interstitial ad '" + adUnitIdentifier + "' was not requested, can not check if it is loaded"); return(false); } return(IsAdUnitReady(adUnitIdentifier)); }
private static bool CanInvokeEvent(Delegate evt) { if (evt == null) { return(false); } // Check that publisher is not over-subscribing if (evt.GetInvocationList().Length > 5) { MaxSdkLogger.UserWarning("Ads Event (" + evt + ") has over 5 subscribers. Please make sure you are properly un-subscribing to actions!!!"); } return(true); }
private static AppLovinQualityServiceData RetrieveQualityServiceData(string sdkKey) { var postJson = string.Format("{{\"sdk_key\" : \"{0}\"}}", sdkKey); var bodyRaw = Encoding.UTF8.GetBytes(postJson); var uploadHandler = new UploadHandlerRaw(bodyRaw); uploadHandler.contentType = "application/json"; var unityWebRequest = new UnityWebRequest("https://api2.safedk.com/v1/build/cred") { method = UnityWebRequest.kHttpVerbPOST, uploadHandler = uploadHandler, downloadHandler = new DownloadHandlerBuffer() }; #if UNITY_2017_2_OR_NEWER var operation = unityWebRequest.SendWebRequest(); #else var operation = webRequest.Send(); #endif // Wait for the download to complete or the request to timeout. while (!operation.isDone) { } #if UNITY_2020_1_OR_NEWER if (unityWebRequest.result != UnityWebRequest.Result.Success) #elif UNITY_2017_2_OR_NEWER if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError) #else if (webRequest.isError) #endif { MaxSdkLogger.UserError("Failed to retrieve API Key for SDK Key: " + sdkKey + "with error: " + unityWebRequest.error); 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()); } }
/// <summary> /// Downloads the plugin file for a given network. /// </summary> /// <param name="network">Network for which to download the current version.</param> /// <returns></returns> public IEnumerator DownloadPlugin(Network network) { var path = Path.Combine(Application.temporaryCachePath, network.PluginFileName); // TODO: Maybe delete plugin file after finishing import. #if UNITY_2017_2_OR_NEWER var downloadHandler = new DownloadHandlerFile(path); #else var downloadHandler = new AppLovinDownloadHandler(path); #endif webRequest = new UnityWebRequest(network.DownloadUrl) { method = UnityWebRequest.kHttpVerbGET, downloadHandler = downloadHandler }; #if UNITY_2017_2_OR_NEWER var operation = webRequest.SendWebRequest(); #else var operation = webRequest.Send(); #endif while (!operation.isDone) { 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) #elif UNITY_2017_2_OR_NEWER if (webRequest.isNetworkError || webRequest.isHttpError) #else if (webRequest.isError) #endif { MaxSdkLogger.UserError(webRequest.error); } else { importingNetwork = network; AssetDatabase.ImportPackage(path, true); } webRequest = null; }
/// <summary> /// Removes the AppLovin Quality Service Plugin or Legacy SafeDK plugin from the given gradle template file if either of them are present. /// </summary> /// <param name="gradleTemplateFile">The gradle template file from which to remove the plugin from</param> protected static void RemoveAppLovinQualityServiceOrSafeDkPlugin(string gradleTemplateFile) { var lines = File.ReadAllLines(gradleTemplateFile).ToList(); lines = RemoveLegacySafeDkPlugin(lines); lines = RemoveAppLovinQualityServicePlugin(lines); try { File.WriteAllText(gradleTemplateFile, string.Join("\n", lines.ToArray()) + "\n"); } catch (Exception exception) { MaxSdkLogger.UserError("Failed to remove AppLovin Quality Service Plugin from mainTemplate.gradle. Please remove the Quality Service plugin from the mainTemplate.gradle manually."); Console.WriteLine(exception); } }