Skip to content

Commit 7204f4e

Browse files
committed
Inject Maven Repo to settingTemplate.gradle from 2022.2+ (googlesamples#609)
Add a new feature and settings for Unity 2022.2+ in Android Resolver to enable patching `Assets/Plugins/Android/settingsTemplate.gradle` for Maven repository specified in `Dependencies.xml`.
1 parent dc19bd0 commit 7204f4e

32 files changed

+1534
-141
lines changed

source/AndroidResolver/src/GradleTemplateResolver.cs

Lines changed: 243 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,49 @@ namespace GooglePlayServices {
3131
internal class GradleTemplateResolver {
3232

3333
/// <summary>
34-
/// Path of the Gradle properties file.
34+
/// Filename of the Custom Gradle Properties Template file.
35+
/// </summary>
36+
public static string GradlePropertiesTemplateFilename = "gradleTemplate.properties";
37+
38+
/// <summary>
39+
/// Path of the Custom Gradle Properties Template file in the Unity project.
3540
/// Available only from Unity version 2019.3 onwards
3641
/// </summary>
3742
public static string GradlePropertiesTemplatePath =
38-
Path.Combine(SettingsDialog.AndroidPluginsDir, "gradleTemplate.properties");
43+
Path.Combine(SettingsDialog.AndroidPluginsDir, GradlePropertiesTemplateFilename);
44+
45+
/// <summary>
46+
/// Filename of the Custom Gradle Settings Template file.
47+
/// </summary>
48+
public static string GradleSettingsTemplatePathFilename = "settingsTemplate.gradle";
49+
50+
/// <summary>
51+
/// Path of the Custom Gradle Settings Template file.
52+
/// </summary>
53+
public static string GradleSettingsTemplatePath =
54+
Path.Combine(SettingsDialog.AndroidPluginsDir, GradleSettingsTemplatePathFilename);
55+
56+
public static string UnityGradleTemplatesDir {
57+
get {
58+
if (unityGradleTemplatesDir == null) {
59+
var engineDir = PlayServicesResolver.AndroidPlaybackEngineDirectory;
60+
if (String.IsNullOrEmpty(engineDir)) return null;
61+
var gradleTemplateDir =
62+
Path.Combine(Path.Combine(engineDir, "Tools"), "GradleTemplates");
63+
unityGradleTemplatesDir = gradleTemplateDir;
64+
}
65+
return unityGradleTemplatesDir;
66+
}
67+
}
68+
private static string unityGradleTemplatesDir = null;
69+
70+
public static string UnityGradleSettingsTemplatePath {
71+
get {
72+
return Path.Combine(
73+
UnityGradleTemplatesDir,
74+
GradleSettingsTemplatePathFilename);
75+
}
76+
}
3977

4078
/// <summary>
4179
/// Line that indicates the start of the injected properties block in properties template.
@@ -47,11 +85,16 @@ internal class GradleTemplateResolver {
4785
/// </summary>
4886
private const string PropertiesEndLine = "# Android Resolver Properties End";
4987

88+
/// <summary>
89+
/// Filename of the Custom Main Gradle Template file.
90+
/// </summary>
91+
public static string GradleTemplateFilename = "mainTemplate.gradle";
92+
5093
/// <summary>
5194
/// Path of the Gradle template file.
5295
/// </summary>
5396
public static string GradleTemplatePath =
54-
Path.Combine(SettingsDialog.AndroidPluginsDir, "mainTemplate.gradle");
97+
Path.Combine(SettingsDialog.AndroidPluginsDir, GradleTemplateFilename);
5598

5699
/// <summary>
57100
/// Line that indicates the start of the injected repos block in the template.
@@ -69,6 +112,12 @@ internal class GradleTemplateResolver {
69112
private const string ReposInjectionLine =
70113
@".*apply plugin: 'com\.android\.(application|library)'.*";
71114

115+
/// <summary>
116+
/// Line that indicates where to initially inject repos in the settings template.
117+
/// </summary>
118+
private const string ReposInjectionLineInGradleSettings =
119+
@".*flatDir {";
120+
72121
/// <summary>
73122
/// Token that indicates where gradle properties should initially be injected.
74123
/// If this isn't present in the properties template, properties will not be
@@ -108,6 +157,16 @@ internal class GradleTemplateResolver {
108157
/// </summary>
109158
private const string PackagingOptionsToken = @"android +{";
110159

160+
/// <summary>
161+
/// Whether current of Unity has changed the place to specify Maven repos from
162+
/// `mainTemplate.gradle` to `settingsTemplate.gradle`.
163+
/// </summary>
164+
public static bool UnityChangeMavenRepoInSettingsTemplate {
165+
get {
166+
return Google.VersionHandler.GetUnityVersionMajorMinor() >= 2022.2f;
167+
}
168+
}
169+
111170
/// <summary>
112171
/// Copy srcaar files to aar files that are excluded from Unity's build process.
113172
/// </summary>
@@ -429,7 +488,8 @@ public static bool InjectProperties(){
429488
}
430489

431490
/// <summary>
432-
/// Inject / update dependencies in the gradle template file.
491+
/// Inject / update additional Maven repository urls specified from `Dependencies.xml` in
492+
/// the Gradle settings template file.
433493
/// </summary>
434494
/// <param name="dependencies">Dependencies to inject.</param>
435495
/// <returns>true if successful, false otherwise.</returns>
@@ -508,7 +568,9 @@ public static bool InjectDependencies(ICollection<Dependency> dependencies) {
508568
});
509569
}
510570
}
511-
repoLines.AddRange(PlayServicesResolver.GradleMavenReposLines(dependencies));
571+
if (!UnityChangeMavenRepoInSettingsTemplate) {
572+
repoLines.AddRange(PlayServicesResolver.GradleMavenReposLines(dependencies));
573+
}
512574

513575
TextFileLineInjector[] injectors = new [] {
514576
new TextFileLineInjector(ReposInjectionLine, ReposStartLine, ReposEndLine,
@@ -527,5 +589,181 @@ public static bool InjectDependencies(ICollection<Dependency> dependencies) {
527589
"Gradle Template", "gradletemplate",
528590
injectors, resolutionMeasurementParameters);
529591
}
592+
593+
/// <summary>
594+
/// Inject / update dependencies in the gradle template file.
595+
/// </summary>
596+
/// <returns>true if successful, false otherwise.</returns>
597+
public static bool InjectSettings(ICollection<Dependency> dependencies, out string lastError) {
598+
if (!UnityChangeMavenRepoInSettingsTemplate ||
599+
!PlayServicesResolver.GradleTemplateEnabled) {
600+
// Early out since there is no need to patch settings template.
601+
lastError = "";
602+
return true;
603+
}
604+
605+
if (!EnsureGradleTemplateEnabled(GradleSettingsTemplatePathFilename)) {
606+
lastError = String.Format(
607+
"Failed to auto-generate '{0}'. This is required to specify " +
608+
"additional Maven repos from Unity 2022.2. " +
609+
"Please manually generate '{2}' through one " +
610+
"of the following methods:\n" +
611+
"* For Unity 2022.2.10+, enable 'Custom Gradle Settings Template' " +
612+
"found under 'Player Settings > Settings for Android -> Publishing " +
613+
"Settings' menu. \n" +
614+
"* Manually copy '{1}' to '{2}'\n" +
615+
"If you like to patch this yourself, simply disable 'Copy and patch " +
616+
"settingsTemplate.gradle' in Android Resolver settings.",
617+
GradleSettingsTemplatePathFilename,
618+
UnityGradleSettingsTemplatePath,
619+
GradleSettingsTemplatePath);
620+
return false;
621+
}
622+
623+
// ReposInjectionLineInGradleSettings
624+
625+
var resolutionMeasurementParameters =
626+
PlayServicesResolver.GetResolutionMeasurementParameters(null);
627+
PlayServicesResolver.analytics.Report(
628+
"/resolve/gradlesettings", resolutionMeasurementParameters,
629+
"Gradle Settings Template Resolve");
630+
631+
var settingsFileDescription = String.Format(
632+
"gradle settings template " + GradleSettingsTemplatePath);
633+
634+
TextFileLineInjector[] settingsInjectors = new [] {
635+
new TextFileLineInjector(ReposInjectionLineInGradleSettings,
636+
ReposStartLine, ReposEndLine,
637+
GradleMavenReposLinesFromDependencies(
638+
dependencies: dependencies,
639+
addMavenGoogle: false,
640+
addMavenCentral: false,
641+
addMavenLocal: true),
642+
"Repo",
643+
settingsFileDescription)
644+
};
645+
if (!PatchFile(GradleSettingsTemplatePath, settingsFileDescription,
646+
"Gradle Settings", "gradlesettings",
647+
settingsInjectors,
648+
resolutionMeasurementParameters)) {
649+
lastError = String.Format("Unable to patch " + settingsFileDescription);
650+
return false;
651+
}
652+
653+
lastError = "";
654+
return true;
655+
}
656+
657+
/// <summary>
658+
/// Get the included dependency repos as lines that can be included in a Gradle file.
659+
/// </summary>
660+
/// <returns>Lines that can be included in a gradle file.</returns>
661+
internal static IList<string> GradleMavenReposLinesFromDependencies(
662+
ICollection<Dependency> dependencies,
663+
bool addMavenGoogle,
664+
bool addMavenCentral,
665+
bool addMavenLocal) {
666+
var lines = new List<string>();
667+
if (dependencies.Count > 0) {
668+
var exportEnabled = PlayServicesResolver.GradleProjectExportEnabled;
669+
var useFullPath = (
670+
exportEnabled &&
671+
SettingsDialog.UseFullCustomMavenRepoPathWhenExport ) || (
672+
!exportEnabled &&
673+
SettingsDialog.UseFullCustomMavenRepoPathWhenNotExport);
674+
675+
var projectPath = FileUtils.PosixPathSeparators(Path.GetFullPath("."));
676+
var projectFileUri = GradleResolver.RepoPathToUri(projectPath);
677+
// projectPath will point to the Unity project root directory as Unity will
678+
// generate the root Gradle project in "Temp/gradleOut" when *not* exporting a
679+
// gradle project.
680+
if (!useFullPath) {
681+
lines.Add(String.Format(
682+
" def unityProjectPath = $/{0}**DIR_UNITYPROJECT**/$" +
683+
".replace(\"\\\\\", \"/\")", GradleWrapper.FILE_SCHEME));
684+
}
685+
if(addMavenGoogle) {
686+
lines.Add(" maven {");
687+
lines.Add(" url \"https://maven.google.com\"");
688+
lines.Add(" }");
689+
}
690+
// Consolidate repos url from Packages folders like
691+
// "Packages/com.company.pkg1/Path/To/m2repository" and
692+
// "Packages/com.company.pkg2/Path/To/m2repository"
693+
Dictionary< string, List<string> > repoUriToSources =
694+
new Dictionary<string, List<string>>();
695+
foreach (var repoAndSources in PlayServicesResolver.GetRepos(dependencies: dependencies)) {
696+
string repoUri;
697+
if (repoAndSources.Key.StartsWith(projectFileUri)) {
698+
var relativePath = repoAndSources.Key.Substring(projectFileUri.Length + 1);
699+
// Convert "Assets", "Packages/packageid", or
700+
// "Library/PackageCache/packageid@version" prefix to local maven repo
701+
// path. Note that local maven repo path only exists if the original repo
702+
// path contains .srcaar.
703+
var repoPath = FileUtils.PosixPathSeparators(
704+
FileUtils.ReplaceBaseAssetsOrPackagesFolder(
705+
relativePath, GooglePlayServices.SettingsDialog.LocalMavenRepoDir));
706+
if (!Directory.Exists(repoPath)) {
707+
repoPath = relativePath;
708+
}
709+
710+
if (useFullPath) {
711+
// build.gradle expects file:/// URI so file separator will be "/" in anycase
712+
// and we must NOT use Path.Combine here because it will use "\" for win platforms
713+
repoUri = String.Format("\"{0}/{1}\"", projectFileUri, repoPath);
714+
} else {
715+
repoUri = String.Format("(unityProjectPath + \"/{0}\")", repoPath);
716+
}
717+
} else {
718+
repoUri = String.Format("\"{0}\"", repoAndSources.Key);
719+
}
720+
List<string> sources;
721+
if (!repoUriToSources.TryGetValue(repoUri, out sources)) {
722+
sources = new List<string>();
723+
repoUriToSources[repoUri] = sources;
724+
}
725+
sources.Add(repoAndSources.Value);
726+
}
727+
foreach(var kv in repoUriToSources) {
728+
lines.Add(" maven {");
729+
lines.Add(String.Format(" url {0} // {1}", kv.Key,
730+
String.Join(", ", kv.Value.ToArray())));
731+
lines.Add(" }");
732+
}
733+
if (addMavenLocal) {
734+
lines.Add(" mavenLocal()");
735+
}
736+
if (addMavenCentral) {
737+
lines.Add(" mavenCentral()");
738+
}
739+
}
740+
return lines;
741+
}
742+
743+
public static bool EnsureGradleTemplateEnabled(string templateName) {
744+
string templatePath = Path.Combine(SettingsDialog.AndroidPluginsDir, templateName);
745+
if (File.Exists(templatePath)) {
746+
return true;
747+
}
748+
749+
string templateSourcePath = Path.Combine(UnityGradleTemplatesDir, templateName);
750+
751+
try {
752+
File.Copy(templateSourcePath, templatePath);
753+
} catch (Exception e) {
754+
PlayServicesResolver.Log(String.Format(
755+
"Unable to copy '{0}' from Unity engine folder '{1}' to this project " +
756+
"folder '{2}'. \n {3}",
757+
templateName,
758+
UnityGradleTemplatesDir,
759+
SettingsDialog.AndroidPluginsDir,
760+
e.ToString()), LogLevel.Error);
761+
return false;
762+
}
763+
PlayServicesResolver.Log(String.Format(
764+
"Copied '{0}' from Unity engine folder to this project '{1}'",
765+
templateName, SettingsDialog.AndroidPluginsDir));
766+
return true;
767+
}
530768
}
531769
}

0 commit comments

Comments
 (0)