AppLovinProcessGradleBuildFile.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. // AppLovin MAX Unity Plugin
  2. //
  3. // Created by Santosh Bagadi on 9/3/19.
  4. // Copyright © 2019 AppLovin. All rights reserved.
  5. //
  6. #if UNITY_ANDROID
  7. using System.Text;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Text.RegularExpressions;
  13. using UnityEditorInternal;
  14. using UnityEngine;
  15. using UnityEngine.Networking;
  16. using Debug = UnityEngine.Debug;
  17. namespace AppLovinMax.Scripts.IntegrationManager.Editor
  18. {
  19. [Serializable]
  20. public class AppLovinQualityServiceData
  21. {
  22. // ReSharper disable once InconsistentNaming - Need to keep name for response data
  23. public string api_key;
  24. }
  25. /// <summary>
  26. /// Adds or updates the AppLovin Quality Service plugin to the provided build.gradle file.
  27. /// If the gradle file already has the plugin, the API key is updated.
  28. /// </summary>
  29. public abstract class AppLovinProcessGradleBuildFile : AppLovinPreProcess
  30. {
  31. private static readonly Regex TokenBuildScriptRepositories = new Regex(".*repositories.*");
  32. private static readonly Regex TokenBuildScriptDependencies = new Regex(".*classpath \'com.android.tools.build:gradle.*");
  33. private static readonly Regex TokenApplicationPlugin = new Regex(".*apply plugin: \'com.android.application\'.*");
  34. private static readonly Regex TokenApiKey = new Regex(".*apiKey.*");
  35. private static readonly Regex TokenAppLovinPlugin = new Regex(".*apply plugin:.+?(?=applovin-quality-service).*");
  36. private const string PluginsMatcher = "plugins";
  37. private const string PluginManagementMatcher = "pluginManagement";
  38. private const string QualityServicePluginRoot = " id 'com.applovin.quality' version '+' apply false // NOTE: Requires version 4.8.3+ for Gradle version 7.2+";
  39. private const string BuildScriptMatcher = "buildscript";
  40. private const string QualityServiceMavenRepo = "maven { url 'https://artifacts.applovin.com/android'; content { includeGroupByRegex 'com.applovin.*' } }";
  41. private const string QualityServiceDependencyClassPath = "classpath 'com.applovin.quality:AppLovinQualityServiceGradlePlugin:+'";
  42. private const string QualityServiceApplyPlugin = "apply plugin: 'applovin-quality-service'";
  43. private const string QualityServicePlugin = "applovin {";
  44. private const string QualityServiceApiKey = " apiKey '{0}'";
  45. private const string QualityServiceBintrayMavenRepo = "https://applovin.bintray.com/Quality-Service";
  46. private const string QualityServiceNoRegexMavenRepo = "maven { url 'https://artifacts.applovin.com/android' }";
  47. // Legacy plugin detection variables
  48. private const string QualityServiceDependencyClassPathV3 = "classpath 'com.applovin.quality:AppLovinQualityServiceGradlePlugin:3.+'";
  49. private static readonly Regex TokenSafeDkLegacyApplyPlugin = new Regex(".*apply plugin:.+?(?=safedk).*");
  50. private const string SafeDkLegacyPlugin = "safedk {";
  51. private const string SafeDkLegacyMavenRepo = "http://download.safedk.com";
  52. private const string SafeDkLegacyDependencyClassPath = "com.safedk:SafeDKGradlePlugin:";
  53. /// <summary>
  54. /// Determines whether the AppLovin Quality Service plugin should be added to the
  55. /// dependencies block in the root build.gradle file or to the plugins block.
  56. ///
  57. /// Gradle's required structure for including plugins varies by version:
  58. /// - Older versions of Gradle require the plugin to be added to the dependencies block.
  59. /// Example:
  60. /// dependencies {
  61. /// classpath 'com.android.tools.build:gradle:4.0.1'
  62. /// classpath 'com.applovin.quality:AppLovinQualityServiceGradlePlugin:+'
  63. /// }
  64. ///
  65. /// - Newer versions of gradle require the plugin to be added to the plugins block.
  66. /// Example:
  67. /// plugins {
  68. /// id 'com.android.application' version '7.4.2' apply false
  69. /// id 'com.android.library' version '7.4.2' apply false
  70. /// id 'com.applovin.quality' version '+' apply false
  71. /// }
  72. ///
  73. /// Since Unity projects may use custom Gradle versions depending on the Unity version or
  74. /// user modifications, this check ensures proper integration of the AppLovin plugin.
  75. /// </summary>
  76. /// <param name="rootGradleBuildFile">The path to project's root build.gradle file.</param>
  77. /// <returns><c>true</c> if the file contains a `dependencies` block, indicating an older Gradle version</returns>
  78. protected static bool ShouldAddQualityServiceToDependencies(string rootGradleBuildFile)
  79. {
  80. var lines = File.ReadAllLines(rootGradleBuildFile).ToList();
  81. return lines.Any(line => TokenBuildScriptDependencies.IsMatch(line));
  82. }
  83. /// <summary>
  84. /// Updates the provided Gradle script to add Quality Service plugin.
  85. /// </summary>
  86. /// <param name="applicationGradleBuildFilePath">The gradle file to update.</param>
  87. protected static void AddAppLovinQualityServicePlugin(string applicationGradleBuildFilePath)
  88. {
  89. if (!AppLovinSettings.Instance.QualityServiceEnabled) return;
  90. var sdkKey = AppLovinSettings.Instance.SdkKey;
  91. if (string.IsNullOrEmpty(sdkKey))
  92. {
  93. MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. SDK Key is empty. Please enter the AppLovin SDK Key in the Integration Manager.");
  94. return;
  95. }
  96. // Retrieve the API Key using the SDK Key.
  97. var qualityServiceData = RetrieveQualityServiceData(sdkKey);
  98. var apiKey = qualityServiceData.api_key;
  99. if (string.IsNullOrEmpty(apiKey))
  100. {
  101. MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. API Key is empty.");
  102. return;
  103. }
  104. // Generate the updated Gradle file that needs to be written.
  105. var lines = File.ReadAllLines(applicationGradleBuildFilePath).ToList();
  106. var sanitizedLines = RemoveLegacySafeDkPlugin(lines);
  107. var outputLines = GenerateUpdatedBuildFileLines(
  108. sanitizedLines,
  109. apiKey,
  110. #if UNITY_2019_3_OR_NEWER
  111. false // On Unity 2019.3+, the buildscript closure related lines will to be added to the root build.gradle file.
  112. #else
  113. true
  114. #endif
  115. );
  116. // outputLines can be null if we couldn't add the plugin.
  117. if (outputLines == null) return;
  118. try
  119. {
  120. File.WriteAllText(applicationGradleBuildFilePath, string.Join("\n", outputLines.ToArray()) + "\n");
  121. }
  122. catch (Exception exception)
  123. {
  124. MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. Gradle file write failed.");
  125. Console.WriteLine(exception);
  126. }
  127. }
  128. /// <summary>
  129. /// Adds AppLovin Quality Service plugin DSL element to the project's root build.gradle file.
  130. /// Sample build.gradle file after adding quality service:
  131. /// plugins {
  132. /// id 'com.android.application' version '7.4.2' apply false
  133. /// id 'com.android.library' version '7.4.2' apply false
  134. /// id 'com.applovin.quality' version '+' apply false
  135. /// }
  136. /// tasks.register('clean', Delete) {
  137. /// delete rootProject.layout.buildDirectory
  138. /// }
  139. ///
  140. /// </summary>
  141. /// <param name="rootGradleBuildFile">The path to project's root build.gradle file.</param>
  142. /// <returns><c>true</c> when the plugin was added successfully.</returns>
  143. protected bool AddPluginToRootGradleBuildFile(string rootGradleBuildFile)
  144. {
  145. var lines = File.ReadAllLines(rootGradleBuildFile).ToList();
  146. // Check if the plugin is already added to the file.
  147. var pluginAdded = lines.Any(line => line.Contains(QualityServicePluginRoot));
  148. if (pluginAdded) return true;
  149. var outputLines = new List<string>();
  150. var insidePluginsClosure = false;
  151. foreach (var line in lines)
  152. {
  153. if (line.Contains(PluginsMatcher))
  154. {
  155. insidePluginsClosure = true;
  156. }
  157. if (!pluginAdded && insidePluginsClosure && line.Contains("}"))
  158. {
  159. outputLines.Add(QualityServicePluginRoot);
  160. pluginAdded = true;
  161. insidePluginsClosure = false;
  162. }
  163. outputLines.Add(line);
  164. }
  165. if (!pluginAdded) return false;
  166. try
  167. {
  168. File.WriteAllText(rootGradleBuildFile, string.Join("\n", outputLines.ToArray()) + "\n");
  169. }
  170. catch (Exception exception)
  171. {
  172. MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. Root Gradle file write failed.");
  173. Console.WriteLine(exception);
  174. return false;
  175. }
  176. return true;
  177. }
  178. /// <summary>
  179. /// Adds the AppLovin maven repository to the project's settings.gradle file.
  180. /// Sample settings.gradle file after adding AppLovin Repository:
  181. /// pluginManagement {
  182. /// repositories {
  183. /// maven { url 'https://artifacts.applovin.com/android'; content { includeGroupByRegex 'com.applovin.*' } }
  184. ///
  185. /// gradlePluginPortal()
  186. /// google()
  187. /// mavenCentral()
  188. /// }
  189. /// }
  190. /// ...
  191. ///
  192. /// </summary>
  193. /// <param name="settingsGradleFile">The path to the project's settings.gradle file.</param>
  194. /// <returns><c>true</c> if the repository was added successfully.</returns>
  195. protected bool AddAppLovinRepository(string settingsGradleFile)
  196. {
  197. var lines = File.ReadLines(settingsGradleFile).ToList();
  198. var outputLines = new List<string>();
  199. var mavenRepoAdded = false;
  200. var pluginManagementClosureDepth = 0;
  201. var insidePluginManagementClosure = false;
  202. var pluginManagementMatched = false;
  203. foreach (var line in lines)
  204. {
  205. outputLines.Add(line);
  206. if (!pluginManagementMatched && line.Contains(PluginManagementMatcher))
  207. {
  208. pluginManagementMatched = true;
  209. insidePluginManagementClosure = true;
  210. }
  211. if (insidePluginManagementClosure)
  212. {
  213. if (line.Contains("{"))
  214. {
  215. pluginManagementClosureDepth++;
  216. }
  217. if (line.Contains("}"))
  218. {
  219. pluginManagementClosureDepth--;
  220. }
  221. if (pluginManagementClosureDepth == 0)
  222. {
  223. insidePluginManagementClosure = false;
  224. }
  225. }
  226. if (insidePluginManagementClosure)
  227. {
  228. if (!mavenRepoAdded && TokenBuildScriptRepositories.IsMatch(line))
  229. {
  230. outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
  231. mavenRepoAdded = true;
  232. }
  233. }
  234. }
  235. if (!mavenRepoAdded) return false;
  236. try
  237. {
  238. File.WriteAllText(settingsGradleFile, string.Join("\n", outputLines.ToArray()) + "\n");
  239. }
  240. catch (Exception exception)
  241. {
  242. MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. Setting Gradle file write failed.");
  243. Console.WriteLine(exception);
  244. return false;
  245. }
  246. return true;
  247. }
  248. #if UNITY_2019_3_OR_NEWER
  249. /// <summary>
  250. /// Adds the necessary AppLovin Quality Service dependency and maven repo lines to the provided root build.gradle file.
  251. /// Sample build.gradle file after adding quality service:
  252. /// allprojects {
  253. /// buildscript {
  254. /// repositories {
  255. /// maven { url 'https://artifacts.applovin.com/android'; content { includeGroupByRegex 'com.applovin.*' } }
  256. /// google()
  257. /// jcenter()
  258. /// }
  259. ///
  260. /// dependencies {
  261. /// classpath 'com.android.tools.build:gradle:4.0.1'
  262. /// classpath 'com.applovin.quality:AppLovinQualityServiceGradlePlugin:+'
  263. /// }
  264. /// ...
  265. ///
  266. /// </summary>
  267. /// <param name="rootGradleBuildFile">The root build.gradle file path</param>
  268. /// <returns><c>true</c> if the build script lines were applied correctly.</returns>
  269. protected bool AddQualityServiceBuildScriptLines(string rootGradleBuildFile)
  270. {
  271. var lines = File.ReadAllLines(rootGradleBuildFile).ToList();
  272. var outputLines = GenerateUpdatedBuildFileLines(lines, null, true);
  273. // outputLines will be null if we couldn't add the build script lines.
  274. if (outputLines == null) return false;
  275. try
  276. {
  277. File.WriteAllText(rootGradleBuildFile, string.Join("\n", outputLines.ToArray()) + "\n");
  278. }
  279. catch (Exception exception)
  280. {
  281. MaxSdkLogger.UserError("Failed to install AppLovin Quality Service plugin. Root Gradle file write failed.");
  282. Console.WriteLine(exception);
  283. return false;
  284. }
  285. return true;
  286. }
  287. /// <summary>
  288. /// Removes the AppLovin Quality Service Plugin or Legacy SafeDK plugin from the given gradle template file if either of them are present.
  289. /// </summary>
  290. /// <param name="gradleTemplateFile">The gradle template file from which to remove the plugin from</param>
  291. protected static void RemoveAppLovinQualityServiceOrSafeDkPlugin(string gradleTemplateFile)
  292. {
  293. var lines = File.ReadAllLines(gradleTemplateFile).ToList();
  294. lines = RemoveLegacySafeDkPlugin(lines);
  295. lines = RemoveAppLovinQualityServicePlugin(lines);
  296. try
  297. {
  298. File.WriteAllText(gradleTemplateFile, string.Join("\n", lines.ToArray()) + "\n");
  299. }
  300. catch (Exception exception)
  301. {
  302. MaxSdkLogger.UserError("Failed to remove AppLovin Quality Service Plugin from mainTemplate.gradle. Please remove the Quality Service plugin from the mainTemplate.gradle manually.");
  303. Console.WriteLine(exception);
  304. }
  305. }
  306. #endif
  307. private static AppLovinQualityServiceData RetrieveQualityServiceData(string sdkKey)
  308. {
  309. var postJson = string.Format("{{\"sdk_key\" : \"{0}\"}}", sdkKey);
  310. var bodyRaw = Encoding.UTF8.GetBytes(postJson);
  311. // Upload handler is automatically disposed when UnityWebRequest is disposed
  312. var uploadHandler = new UploadHandlerRaw(bodyRaw);
  313. uploadHandler.contentType = "application/json";
  314. using (var unityWebRequest = new UnityWebRequest("https://api2.safedk.com/v1/build/cred"))
  315. {
  316. unityWebRequest.method = UnityWebRequest.kHttpVerbPOST;
  317. unityWebRequest.uploadHandler = uploadHandler;
  318. unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
  319. var operation = unityWebRequest.SendWebRequest();
  320. // Wait for the download to complete or the request to timeout.
  321. while (!operation.isDone) { }
  322. #if UNITY_2020_1_OR_NEWER
  323. if (unityWebRequest.result != UnityWebRequest.Result.Success)
  324. #else
  325. if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
  326. #endif
  327. {
  328. MaxSdkLogger.UserError("Failed to retrieve API Key for SDK Key: " + sdkKey + "with error: " + unityWebRequest.error);
  329. return new AppLovinQualityServiceData();
  330. }
  331. try
  332. {
  333. return JsonUtility.FromJson<AppLovinQualityServiceData>(unityWebRequest.downloadHandler.text);
  334. }
  335. catch (Exception exception)
  336. {
  337. MaxSdkLogger.UserError("Failed to parse API Key." + exception);
  338. return new AppLovinQualityServiceData();
  339. }
  340. }
  341. }
  342. private static List<string> RemoveLegacySafeDkPlugin(List<string> lines)
  343. {
  344. return RemovePlugin(lines, SafeDkLegacyPlugin, SafeDkLegacyMavenRepo, SafeDkLegacyDependencyClassPath, TokenSafeDkLegacyApplyPlugin);
  345. }
  346. private static List<string> RemoveAppLovinQualityServicePlugin(List<string> lines)
  347. {
  348. return RemovePlugin(lines, QualityServicePlugin, QualityServiceMavenRepo, QualityServiceDependencyClassPath, TokenAppLovinPlugin);
  349. }
  350. private static List<string> RemovePlugin(List<string> lines, string pluginLine, string mavenRepo, string dependencyClassPath, Regex applyPluginToken)
  351. {
  352. var sanitizedLines = new List<string>();
  353. var legacyRepoRemoved = false;
  354. var legacyDependencyClassPathRemoved = false;
  355. var legacyPluginRemoved = false;
  356. var legacyPluginMatched = false;
  357. var insideLegacySafeDkClosure = false;
  358. foreach (var line in lines)
  359. {
  360. if (!legacyPluginMatched && line.Contains(pluginLine))
  361. {
  362. legacyPluginMatched = true;
  363. insideLegacySafeDkClosure = true;
  364. }
  365. if (insideLegacySafeDkClosure && line.Contains("}"))
  366. {
  367. insideLegacySafeDkClosure = false;
  368. continue;
  369. }
  370. if (insideLegacySafeDkClosure)
  371. {
  372. continue;
  373. }
  374. if (!legacyRepoRemoved && line.Contains(mavenRepo))
  375. {
  376. legacyRepoRemoved = true;
  377. continue;
  378. }
  379. if (!legacyDependencyClassPathRemoved && line.Contains(dependencyClassPath))
  380. {
  381. legacyDependencyClassPathRemoved = true;
  382. continue;
  383. }
  384. if (!legacyPluginRemoved && applyPluginToken.IsMatch(line))
  385. {
  386. legacyPluginRemoved = true;
  387. continue;
  388. }
  389. sanitizedLines.Add(line);
  390. }
  391. return sanitizedLines;
  392. }
  393. private static List<string> GenerateUpdatedBuildFileLines(List<string> lines, string apiKey, bool addBuildScriptLines)
  394. {
  395. var addPlugin = MaxSdkUtils.IsValidString(apiKey);
  396. // A sample of the template file.
  397. // ...
  398. // allprojects {
  399. // repositories {**ARTIFACTORYREPOSITORY**
  400. // google()
  401. // jcenter()
  402. // flatDir {
  403. // dirs 'libs'
  404. // }
  405. // }
  406. // }
  407. //
  408. // apply plugin: 'com.android.application'
  409. // **APPLY_PLUGINS**
  410. //
  411. // dependencies {
  412. // implementation fileTree(dir: 'libs', include: ['*.jar'])
  413. // **DEPS**}
  414. // ...
  415. var outputLines = new List<string>();
  416. // Check if the plugin exists, if so, update the SDK Key.
  417. var pluginExists = lines.Any(line => TokenAppLovinPlugin.IsMatch(line));
  418. if (pluginExists)
  419. {
  420. var pluginMatched = false;
  421. var insideAppLovinClosure = false;
  422. var updatedApiKey = false;
  423. var mavenRepoUpdated = false;
  424. var dependencyClassPathUpdated = false;
  425. foreach (var line in lines)
  426. {
  427. // Bintray maven repo is no longer being used. Update to s3 maven repo with regex check
  428. if (!mavenRepoUpdated && (line.Contains(QualityServiceBintrayMavenRepo) || line.Contains(QualityServiceNoRegexMavenRepo)))
  429. {
  430. outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
  431. mavenRepoUpdated = true;
  432. continue;
  433. }
  434. // We no longer use version specific dependency class path. Just use + for version to always pull the latest.
  435. if (!dependencyClassPathUpdated && line.Contains(QualityServiceDependencyClassPathV3))
  436. {
  437. outputLines.Add(GetFormattedBuildScriptLine(QualityServiceDependencyClassPath));
  438. dependencyClassPathUpdated = true;
  439. continue;
  440. }
  441. if (!pluginMatched && line.Contains(QualityServicePlugin))
  442. {
  443. insideAppLovinClosure = true;
  444. pluginMatched = true;
  445. }
  446. if (insideAppLovinClosure && line.Contains("}"))
  447. {
  448. insideAppLovinClosure = false;
  449. }
  450. // Update the API key.
  451. if (insideAppLovinClosure && !updatedApiKey && TokenApiKey.IsMatch(line))
  452. {
  453. outputLines.Add(string.Format(QualityServiceApiKey, apiKey));
  454. updatedApiKey = true;
  455. }
  456. // Keep adding the line until we find and update the plugin.
  457. else
  458. {
  459. outputLines.Add(line);
  460. }
  461. }
  462. }
  463. // Plugin hasn't been added yet, add it.
  464. else
  465. {
  466. var buildScriptClosureDepth = 0;
  467. var insideBuildScriptClosure = false;
  468. var buildScriptMatched = false;
  469. var qualityServiceRepositoryAdded = false;
  470. var qualityServiceDependencyClassPathAdded = false;
  471. var qualityServicePluginAdded = false;
  472. foreach (var line in lines)
  473. {
  474. // Add the line to the output lines.
  475. outputLines.Add(line);
  476. // Check if we need to add the build script lines and add them.
  477. if (addBuildScriptLines)
  478. {
  479. if (!buildScriptMatched && line.Contains(BuildScriptMatcher))
  480. {
  481. buildScriptMatched = true;
  482. insideBuildScriptClosure = true;
  483. }
  484. // Match the parenthesis to track if we are still inside the buildscript closure.
  485. if (insideBuildScriptClosure)
  486. {
  487. if (line.Contains("{"))
  488. {
  489. buildScriptClosureDepth++;
  490. }
  491. if (line.Contains("}"))
  492. {
  493. buildScriptClosureDepth--;
  494. }
  495. if (buildScriptClosureDepth == 0)
  496. {
  497. insideBuildScriptClosure = false;
  498. // There may be multiple buildscript closures and we need to keep looking until we added both the repository and classpath.
  499. buildScriptMatched = qualityServiceRepositoryAdded && qualityServiceDependencyClassPathAdded;
  500. }
  501. }
  502. if (insideBuildScriptClosure)
  503. {
  504. // Add the build script dependency repositories.
  505. if (!qualityServiceRepositoryAdded && TokenBuildScriptRepositories.IsMatch(line))
  506. {
  507. outputLines.Add(GetFormattedBuildScriptLine(QualityServiceMavenRepo));
  508. qualityServiceRepositoryAdded = true;
  509. }
  510. // Add the build script dependencies.
  511. else if (!qualityServiceDependencyClassPathAdded && TokenBuildScriptDependencies.IsMatch(line))
  512. {
  513. outputLines.Add(GetFormattedBuildScriptLine(QualityServiceDependencyClassPath));
  514. qualityServiceDependencyClassPathAdded = true;
  515. }
  516. }
  517. }
  518. // Check if we need to add the plugin and add it.
  519. if (addPlugin)
  520. {
  521. // Add the plugin.
  522. if (!qualityServicePluginAdded && TokenApplicationPlugin.IsMatch(line))
  523. {
  524. outputLines.Add(QualityServiceApplyPlugin);
  525. outputLines.AddRange(GenerateAppLovinPluginClosure(apiKey));
  526. qualityServicePluginAdded = true;
  527. }
  528. }
  529. }
  530. if ((addBuildScriptLines && (!qualityServiceRepositoryAdded || !qualityServiceDependencyClassPathAdded)) || (addPlugin && !qualityServicePluginAdded))
  531. {
  532. return null;
  533. }
  534. }
  535. return outputLines;
  536. }
  537. public static string GetFormattedBuildScriptLine(string buildScriptLine)
  538. {
  539. #if UNITY_2022_2_OR_NEWER
  540. return " "
  541. #elif UNITY_2019_3_OR_NEWER
  542. return " "
  543. #else
  544. return " "
  545. #endif
  546. + buildScriptLine;
  547. }
  548. private static IEnumerable<string> GenerateAppLovinPluginClosure(string apiKey)
  549. {
  550. // applovin {
  551. // // NOTE: DO NOT CHANGE - this is NOT your AppLovin MAX SDK key - this is a derived key.
  552. // apiKey "456...a1b"
  553. // }
  554. var linesToInject = new List<string>(5);
  555. linesToInject.Add("");
  556. linesToInject.Add("applovin {");
  557. linesToInject.Add(" // NOTE: DO NOT CHANGE - this is NOT your AppLovin MAX SDK key - this is a derived key.");
  558. linesToInject.Add(string.Format(QualityServiceApiKey, apiKey));
  559. linesToInject.Add("}");
  560. return linesToInject;
  561. }
  562. }
  563. }
  564. #endif