/// <summary> /// Inject properties in the gradle properties template file. /// Because of a change in structure of android projects built with /// Unity 2019.3 and above, the correct way to enable jetifier and /// Android X is by updating the gradle properties template. /// </summary> /// <returns>true if successful, false otherwise.</returns> public static bool InjectProperties() { var resolutionMeasurementParameters = PlayServicesResolver.GetResolutionMeasurementParameters(null); PlayServicesResolver.analytics.Report( "/resolve/gradleproperties", resolutionMeasurementParameters, "Gradle Properties Resolve"); var propertiesLines = new List <string>(); // Lines to add Custom Gradle properties template to enable // jetifier and androidx propertiesLines.AddRange(new [] { "android.useAndroidX=true", "android.enableJetifier=true", }); var propertiesFileDescription = String.Format( "gradle properties template" + GradlePropertiesTemplatePath); TextFileLineInjector[] propertiesInjectors = new [] { new TextFileLineInjector(PropertiesInjectionLine, PropertiesStartLine, PropertiesEndLine, propertiesLines, "Properties", propertiesFileDescription) }; if (!PatchFile(GradlePropertiesTemplatePath, propertiesFileDescription, "Gradle Properties", "gradleproperties", propertiesInjectors, resolutionMeasurementParameters)) { PlayServicesResolver.Log( String.Format("Unable to patch " + propertiesFileDescription), level: LogLevel.Error); return(false); } return(true); }
/// <summary> /// Inject / update dependencies in the gradle template file. /// </summary> /// <param name="dependencies">Dependencies to inject.</param> /// <returns>true if successful, false otherwise.</returns> public static bool InjectDependencies(ICollection <Dependency> dependencies) { var resolutionMeasurementParameters = PlayServicesResolver.GetResolutionMeasurementParameters(null); if (dependencies.Count > 0) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate", resolutionMeasurementParameters, "Gradle Template Resolve"); } var fileDescription = String.Format("gradle template {0}", GradleTemplatePath); PlayServicesResolver.Log(String.Format("Reading {0}", fileDescription), level: LogLevel.Verbose); IEnumerable <string> lines; try { lines = File.ReadAllLines(GradleTemplatePath); } catch (Exception ex) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/templateunreadable", "Gradle Template Resolve: Failed Template Unreadable"); PlayServicesResolver.Log( String.Format("Unable to patch {0} ({1})", fileDescription, ex.ToString()), level: LogLevel.Error); return(false); } PlayServicesResolver.Log(String.Format("Searching for {0} in {1}", DependenciesToken, fileDescription), level: LogLevel.Verbose); // Determine whether dependencies should be injected. var dependenciesToken = new Regex(DependenciesToken); bool containsDeps = false; foreach (var line in lines) { if (dependenciesToken.IsMatch(line)) { containsDeps = true; break; } } // If a dependencies token isn't present report a warning and abort. if (!containsDeps) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/noinjectionpoint", "Gradle Template Resolve: Failed No Injection Point"); PlayServicesResolver.Log( String.Format("No {0} token found in {1}, Android Resolver libraries will " + "not be added to the file.", DependenciesToken, fileDescription), level: LogLevel.Warning); return(true); } // Copy all srcaar files in the project to aar filenames so that they'll be included in // the Gradle build. if (!CopySrcAars(dependencies)) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/srcaarcopy", "Gradle Template Resolve: Failed srcaar I/O"); return(false); } var repoLines = new List <string>(); // Optionally enable the jetifier. if (SettingsDialog.UseJetifier && dependencies.Count > 0) { repoLines.AddRange(new [] { "([rootProject] + (rootProject.subprojects as List)).each {", " ext {", " it.setProperty(\"android.useAndroidX\", true)", " it.setProperty(\"android.enableJetifier\", true)", " }", "}" }); } repoLines.AddRange(PlayServicesResolver.GradleMavenReposLines(dependencies)); TextFileLineInjector[] injectors = new [] { new TextFileLineInjector(ReposInjectionLine, ReposStartLine, ReposEndLine, repoLines, "Repos", fileDescription), new TextFileLineInjector(DependenciesToken, DependenciesStartLine, DependenciesEndLine, PlayServicesResolver.GradleDependenciesLines( dependencies, includeDependenciesBlock: false), "Dependencies", fileDescription), new TextFileLineInjector(PackagingOptionsToken, PackagingOptionsStartLine, PackagingOptionsEndLine, PlayServicesResolver.PackagingOptionsLines(dependencies), "Packaging Options", fileDescription), }; // Lines that will be written to the output file. var outputLines = new List <string>(); foreach (var line in lines) { var currentOutputLines = new List <string>(); foreach (var injector in injectors) { bool injectionApplied = false; currentOutputLines = injector.ProcessLine(line, out injectionApplied); if (injectionApplied || currentOutputLines.Count == 0) { break; } } outputLines.AddRange(currentOutputLines); } var inputText = String.Join("\n", (new List <string>(lines)).ToArray()) + "\n"; var outputText = String.Join("\n", outputLines.ToArray()) + "\n"; if (inputText == outputText) { PlayServicesResolver.Log(String.Format("No changes to {0}", fileDescription), level: LogLevel.Verbose); return(true); } if (!FileUtils.CheckoutFile(GradleTemplatePath, PlayServicesResolver.logger)) { PlayServicesResolver.Log( String.Format("Failed to checkout '{0}', unable to patch the file.", GradleTemplatePath), level: LogLevel.Error); PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/checkout", "Gradle Template Resolve: Failed to checkout"); return(false); } PlayServicesResolver.Log( String.Format("Writing updated {0}", fileDescription), level: LogLevel.Verbose); try { File.WriteAllText(GradleTemplatePath, outputText); PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/success", resolutionMeasurementParameters, "Gradle Template Resolve Success"); } catch (Exception ex) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/write", "Gradle Template Resolve: Failed to write"); PlayServicesResolver.Log( String.Format("Unable to patch {0} ({1})", fileDescription, ex.ToString()), level: LogLevel.Error); return(false); } return(true); }
/// <summary> /// Inject / update dependencies in the gradle template file. /// </summary> /// <param name="dependencies">Dependencies to inject.</param> /// <returns>true if successful, false otherwise.</returns> public static bool InjectDependencies(ICollection <Dependency> dependencies) { var resolutionMeasurementParameters = PlayServicesResolver.GetResolutionMeasurementParameters(null); if (dependencies.Count > 0) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate", resolutionMeasurementParameters, "Gradle Template Resolve"); } var fileDescription = String.Format("gradle template {0}", GradleTemplatePath); PlayServicesResolver.Log(String.Format("Reading {0}", fileDescription), level: LogLevel.Verbose); IEnumerable <string> lines; try { lines = File.ReadAllLines(GradleTemplatePath); } catch (Exception ex) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/templateunreadable", "Gradle Template Resolve: Failed Template Unreadable"); PlayServicesResolver.Log( String.Format("Unable to patch {0} ({1})", fileDescription, ex.ToString()), level: LogLevel.Error); return(false); } PlayServicesResolver.Log(String.Format("Searching for {0} in {1}", DependenciesToken, fileDescription), level: LogLevel.Verbose); // Determine whether dependencies should be injected. var dependenciesToken = new Regex(DependenciesToken); bool containsDeps = false; foreach (var line in lines) { if (dependenciesToken.IsMatch(line)) { containsDeps = true; break; } } // If a dependencies token isn't present report a warning and abort. if (!containsDeps) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/noinjectionpoint", "Gradle Template Resolve: Failed No Injection Point"); PlayServicesResolver.Log( String.Format("No {0} token found in {1}, Android Resolver libraries will " + "not be added to the file.", DependenciesToken, fileDescription), level: LogLevel.Warning); return(true); } // Copy all srcaar files in the project to aar filenames so that they'll be included in // the Gradle build. if (!CopySrcAars(dependencies)) { PlayServicesResolver.analytics.Report( "/resolve/gradletemplate/failed/srcaarcopy", "Gradle Template Resolve: Failed srcaar I/O"); return(false); } var repoLines = new List <string>(); // Optionally enable the jetifier. if (SettingsDialog.UseJetifier && dependencies.Count > 0) { // For Unity versions lower than 2019.3 add jetifier and AndroidX // properties to custom main gradle template if (VersionHandler.GetUnityVersionMajorMinor() < 2019.3f) { repoLines.AddRange(new [] { "([rootProject] + (rootProject.subprojects as List)).each {", " ext {", " it.setProperty(\"android.useAndroidX\", true)", " it.setProperty(\"android.enableJetifier\", true)", " }", "}" }); } } repoLines.AddRange(PlayServicesResolver.GradleMavenReposLines(dependencies)); TextFileLineInjector[] injectors = new [] { new TextFileLineInjector(ReposInjectionLine, ReposStartLine, ReposEndLine, repoLines, "Repos", fileDescription), new TextFileLineInjector(DependenciesToken, DependenciesStartLine, DependenciesEndLine, PlayServicesResolver.GradleDependenciesLines( dependencies, includeDependenciesBlock: false), "Dependencies", fileDescription), new TextFileLineInjector(PackagingOptionsToken, PackagingOptionsStartLine, PackagingOptionsEndLine, PlayServicesResolver.PackagingOptionsLines(dependencies), "Packaging Options", fileDescription), }; return(PatchFile(GradleTemplatePath, fileDescription, "Gradle Template", "gradletemplate", injectors, resolutionMeasurementParameters)); }