@@ -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