Skip to content

Commit ed6e2db

Browse files
committed
Fixed Android Resolver failed when Custom Gradle Template is On
This fails when the package is installed through Unity Package Manager and it ships with local Maven repo (.srcaar and .pom). This change will do the following: 1. When Custom Gradle Template is On, instead of generating .aar right next to .srcaar, both .aar and .pom will be generated under LocalMavenRepoDir, which is default to Assets/GeneratedLocalRepo. 2. An option to change LocalMavenRepoDir in Android Resolver settings. Current this cannot be any directory under "Assets/Plugins/Android" and the UI will enforce the restrictions. Need further investigation about how to remove the restrictions. 3. When PlayServicesResolver removes managed files, with "gpsr" label, it removes empty parent folders as well. Fixed #342 Bug: 153743575 Change-Id: I3208790dcd8a515982654ccb56ad0ccbcf1ed4f8
1 parent 1f97013 commit ed6e2db

File tree

10 files changed

+290
-51
lines changed

10 files changed

+290
-51
lines changed

source/AndroidResolver/src/GradleTemplateResolver.cs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -91,24 +91,27 @@ internal class GradleTemplateResolver {
9191
/// <returns>true if successful, false otherwise.</returns>
9292
private static bool CopySrcAars(ICollection<Dependency> dependencies) {
9393
bool succeeded = true;
94-
var aarFiles = new List<string>();
94+
var aarFiles = new List<KeyValuePair<string, string>>();
9595
// Copy each .srcaar file to .aar while configuring the plugin importer to ignore the
9696
// file.
9797
foreach (var aar in LocalMavenRepository.FindAarsInLocalRepos(dependencies)) {
98-
var dir = Path.GetDirectoryName(aar);
99-
var filename = Path.GetFileNameWithoutExtension(aar);
98+
var aarPath = aar;
99+
if (FileUtils.IsUnderPackageDirectory(aar)) {
100+
var logicalPackagePath = FileUtils.GetPackageDirectory(aar,
101+
FileUtils.PackageDirectoryType.AssetDatabasePath);
102+
aarPath = FileUtils.ReplaceBaseAssetsOrPackagesFolder(
103+
aar, logicalPackagePath);
104+
}
105+
var dir = FileUtils.ReplaceBaseAssetsOrPackagesFolder(
106+
Path.GetDirectoryName(aar),
107+
GooglePlayServices.SettingsDialog.LocalMavenRepoDir);
108+
var filename = Path.GetFileNameWithoutExtension(aarPath);
100109
var targetFilename = Path.Combine(dir, filename + ".aar");
101110
bool configuredAar = File.Exists(targetFilename);
102111
if (!configuredAar) {
103-
bool copiedAndLabeledAar = AssetDatabase.CopyAsset(aar, targetFilename);
104-
if (copiedAndLabeledAar) {
105-
var unlabeledAssets = new HashSet<string>();
106-
PlayServicesResolver.LabelAssets(
107-
new [] { targetFilename },
108-
complete: (unlabeled) => { unlabeledAssets.UnionWith(unlabeled); });
109-
copiedAndLabeledAar = unlabeledAssets.Count == 0;
110-
}
111-
if (copiedAndLabeledAar) {
112+
var error = PlayServicesResolver.CopyAssetAndLabel(
113+
aarPath, targetFilename);
114+
if (String.IsNullOrEmpty(error)) {
112115
try {
113116
PluginImporter importer = (PluginImporter)AssetImporter.GetAtPath(
114117
targetFilename);
@@ -125,24 +128,25 @@ private static bool CopySrcAars(ICollection<Dependency> dependencies) {
125128
} else {
126129
PlayServicesResolver.Log(String.Format(
127130
"Unable to copy {0} to {1}. {1} will not be included in Gradle " +
128-
"builds.", aar, targetFilename), level: LogLevel.Error);
131+
"builds. Reason: {2}", aarPath, targetFilename, error),
132+
level: LogLevel.Error);
129133
}
130-
if (configuredAar) {
131-
aarFiles.Add(targetFilename);
132-
// Some versions of Unity do not mark the asset database as dirty when
133-
// plugin importer settings change so reimport the asset to synchronize
134-
// the state.
135-
AssetDatabase.ImportAsset(targetFilename, ImportAssetOptions.ForceUpdate);
136-
} else {
137-
if (File.Exists(targetFilename)) {
138-
AssetDatabase.DeleteAsset(targetFilename);
139-
}
140-
succeeded = false;
134+
}
135+
if (configuredAar) {
136+
aarFiles.Add(new KeyValuePair<string, string>(aarPath, targetFilename));
137+
// Some versions of Unity do not mark the asset database as dirty when
138+
// plugin importer settings change so reimport the asset to synchronize
139+
// the state.
140+
AssetDatabase.ImportAsset(targetFilename, ImportAssetOptions.ForceUpdate);
141+
} else {
142+
if (File.Exists(targetFilename)) {
143+
AssetDatabase.DeleteAsset(targetFilename);
141144
}
145+
succeeded = false;
142146
}
143147
}
144-
foreach (var aar in aarFiles) {
145-
if (!LocalMavenRepository.PatchPomFile(aar)) succeeded = false;
148+
foreach (var keyValue in aarFiles) {
149+
succeeded &= LocalMavenRepository.PatchPomFile(keyValue.Value, keyValue.Key);
146150
}
147151
return succeeded;
148152
}

source/AndroidResolver/src/LocalMavenRepository.cs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public static List<string> FindAarsInLocalRepos(ICollection<Dependency> dependen
8484
/// </summary>
8585
/// <param name="filename">Path to a file.</param>
8686
/// <returns>Path (including directory) without a filename extension.</returns>
87-
private static string PathWithoutExtension(string path) {
87+
internal static string PathWithoutExtension(string path) {
8888
return Path.Combine(Path.GetDirectoryName(path),
8989
Path.GetFileNameWithoutExtension(path));
9090
}
@@ -95,16 +95,37 @@ private static string PathWithoutExtension(string path) {
9595
/// file.
9696
/// </summary>
9797
/// <param name="artifactFilename">artifactFilename</param>
98+
/// <param name="sourceFilename">If artifactFilename is copied from a different location,
99+
/// pass the original location where POM file lives.</param>
98100
/// <returns>true if successful, false otherwise.</returns>
99-
public static bool PatchPomFile(string artifactFilename) {
101+
public static bool PatchPomFile(string artifactFilename, string sourceFilename) {
102+
if (sourceFilename == null) {
103+
sourceFilename = artifactFilename;
104+
}
105+
if (FileUtils.IsUnderPackageDirectory(artifactFilename)) {
106+
// File under Packages folder is immutable.
107+
PlayServicesResolver.Log(
108+
String.Format("Cannot patch POM from Packages directory since it is immutable" +
109+
" ({0})", artifactFilename), level: LogLevel.Error);
110+
return false;
111+
}
112+
100113
var failureImpact = String.Format("{0} may not be included in your project",
101114
Path.GetFileName(artifactFilename));
102115
var pomFilename = PathWithoutExtension(artifactFilename) + ".pom";
103-
if (!File.Exists(pomFilename)) {
104-
PlayServicesResolver.Log(
105-
String.Format("Maven POM {0} for {1} does not exist. " + failureImpact,
106-
pomFilename, artifactFilename), level: LogLevel.Warning);
107-
return false;
116+
// Copy POM file if artifact has been copied from a different location as well.
117+
if (String.Compare(sourceFilename, artifactFilename) != 0 &&
118+
!File.Exists(pomFilename)) {
119+
var sourcePomFilename = PathWithoutExtension(sourceFilename) + ".pom";
120+
var error = PlayServicesResolver.CopyAssetAndLabel(
121+
sourcePomFilename, pomFilename);
122+
if (!String.IsNullOrEmpty(error)) {
123+
PlayServicesResolver.Log(
124+
String.Format("Failed to copy POM from {0} to {1} due to:\n{2}",
125+
sourcePomFilename, pomFilename, error),
126+
level: LogLevel.Error);
127+
return false;
128+
}
108129
}
109130
var artifactPackaging = Path.GetExtension(artifactFilename).ToLower().Substring(1);
110131
var pom = new XmlDocument();
@@ -168,6 +189,10 @@ public static bool PatchPomFilesInLocalRepos(ICollection<Dependency> dependencie
168189
// Filename extensions by the basename of each file path.
169190
var extensionsByBasenames = new Dictionary<string, HashSet<string>>();
170191
foreach (var filename in FindAarsInLocalRepos(dependencies)) {
192+
// No need to patch POM under package folder.
193+
if (FileUtils.IsUnderPackageDirectory(filename)) {
194+
continue;
195+
}
171196
var pathWithoutExtension = PathWithoutExtension(filename);
172197
HashSet<string> extensions;
173198
if (!extensionsByBasenames.TryGetValue(pathWithoutExtension, out extensions)) {
@@ -191,7 +216,8 @@ public static bool PatchPomFilesInLocalRepos(ICollection<Dependency> dependencie
191216
}
192217
if (foundFile) break;
193218
}
194-
successful &= PatchPomFile(kv.Key + filePackagingToUse);
219+
var artifect = kv.Key + filePackagingToUse;
220+
successful &= PatchPomFile(artifect, artifect);
195221
}
196222
return successful;
197223
}

source/AndroidResolver/src/PlayServicesResolver.cs

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ public class BundleIdChangedEventArgs : EventArgs {
461461
/// <summary>
462462
/// Asset label applied to files managed by this plugin.
463463
/// </summary>
464-
private const string ManagedAssetLabel = "gpsr";
464+
internal const string ManagedAssetLabel = "gpsr";
465465

466466
/// <summary>
467467
/// Get a boolean property from UnityEditor.EditorUserBuildSettings.
@@ -1436,12 +1436,23 @@ private static void ResolveOnAndroidSdkRootChange(
14361436
/// </summary>
14371437
/// <param name="filenames">Files or directories to delete.</param>
14381438
/// <returns>true if files are deleted, false otherwise.</returns>
1439-
private static bool DeleteFiles(IEnumerable<string> filenames)
1440-
{
1439+
private static bool DeleteFiles(IEnumerable<string> filenames) {
14411440
if (filenames == null) return false;
14421441
var failedToDelete = new List<string>();
14431442
foreach (string artifact in filenames) {
14441443
failedToDelete.AddRange(FileUtils.DeleteExistingFileOrDirectory(artifact));
1444+
// Attempt to remove empty parent folders.
1445+
var folder = Path.GetDirectoryName(artifact);
1446+
while (!String.IsNullOrEmpty(folder) &&
1447+
!Path.IsPathRooted(folder) &&
1448+
String.Compare(folder, FileUtils.ASSETS_FOLDER) != 0) {
1449+
if (Directory.GetFiles(folder).Length != 0 ||
1450+
Directory.GetDirectories(folder).Length != 0) {
1451+
break;
1452+
}
1453+
failedToDelete.AddRange(FileUtils.DeleteExistingFileOrDirectory(folder));
1454+
folder = Path.GetDirectoryName(folder);
1455+
}
14451456
}
14461457
var deleteError = FileUtils.FormatError("Failed to delete files:", failedToDelete);
14471458
if (!String.IsNullOrEmpty(deleteError)) {
@@ -1937,20 +1948,36 @@ internal static IList<string> GradleMavenReposLines(ICollection<Dependency> depe
19371948
lines.Add(" maven {");
19381949
lines.Add(" url \"https://maven.google.com\"");
19391950
lines.Add(" }");
1951+
1952+
// Consolidate repos url from Packages folders like
1953+
// "Packages/com.company.pkg1/Path/To/m2repository" and
1954+
// "Packages/com.company.pkg2/Path/To/m2repository"
1955+
Dictionary< string, List<string> > repoUriToSources =
1956+
new Dictionary<string, List<string>>();
19401957
foreach (var repoAndSources in GetRepos(dependencies: dependencies)) {
19411958
string repoUri;
19421959
if (repoAndSources.Key.StartsWith(projectFileUri) && !exportEnabled) {
1943-
repoUri = String.Format(
1944-
"(unityProjectPath + \"/{0}\")",
1945-
repoAndSources.Key.Substring(projectFileUri.Length + 1));
1960+
var repoPath = repoAndSources.Key.Substring(projectFileUri.Length + 1);
1961+
repoPath = FileUtils.ReplaceBaseAssetsOrPackagesFolder(
1962+
repoPath, GooglePlayServices.SettingsDialog.LocalMavenRepoDir);
1963+
repoUri = String.Format("(unityProjectPath + \"/{0}\")", repoPath);
19461964
} else {
19471965
repoUri = String.Format("\"{0}\"", repoAndSources.Key);
19481966
}
1967+
List<string> sources;
1968+
if (!repoUriToSources.TryGetValue(repoUri, out sources)) {
1969+
sources = new List<string>();
1970+
repoUriToSources[repoUri] = sources;
1971+
}
1972+
sources.Add(repoAndSources.Value);
1973+
}
1974+
foreach(var kv in repoUriToSources) {
19491975
lines.Add(" maven {");
1950-
lines.Add(String.Format(" url {0} // {1}", repoUri,
1951-
repoAndSources.Value));
1976+
lines.Add(String.Format(" url {0} // {1}", kv.Key,
1977+
String.Join(", ", kv.Value.ToArray())));
19521978
lines.Add(" }");
19531979
}
1980+
19541981
lines.Add(" mavenLocal()");
19551982
lines.Add(" jcenter()");
19561983
lines.Add(" mavenCentral()");
@@ -2168,6 +2195,66 @@ internal static void LabelAssets(IEnumerable<string> assetPaths,
21682195
}, synchronous: synchronous);
21692196
}
21702197

2198+
/// <summary>
2199+
/// Copy asset to target location and apply labels to be managed by this plugin.
2200+
/// </summary>
2201+
/// <param name="sourceLocation">Location to copy from.</param>
2202+
/// <param name="targetLocation">Location to copy to.</param>
2203+
/// <param name="force">If true, this will attempt to delete existing file at target
2204+
/// location. If false, this will return error if target file exists.</param>
2205+
/// <returns>Error message. Empty if no error occurs.</returns>
2206+
internal static string CopyAssetAndLabel(string sourceLocation, string targetLocation,
2207+
bool force = false) {
2208+
if (String.Compare(sourceLocation, targetLocation) == 0) {
2209+
return "";
2210+
}
2211+
if (!File.Exists(sourceLocation)) {
2212+
return String.Format("Source file {0} not found.",
2213+
sourceLocation);
2214+
}
2215+
if (File.Exists(targetLocation)) {
2216+
if (force) {
2217+
if (FileUtils.DeleteExistingFileOrDirectory(targetLocation, true).Count != 0) {
2218+
return String.Format(
2219+
"Failed to remove existing target file {0}.",
2220+
targetLocation);
2221+
}
2222+
} else {
2223+
return String.Format("Target file {0} exists.",
2224+
targetLocation);
2225+
}
2226+
}
2227+
2228+
var targetDir = Path.GetDirectoryName(targetLocation);
2229+
if (!FileUtils.CreateFolder(targetDir)) {
2230+
return String.Format("Failed to create folders at {0}", targetDir);
2231+
}
2232+
2233+
PlayServicesResolver.Log(String.Format("Copying {0} to {1}",
2234+
sourceLocation, targetLocation),
2235+
level: LogLevel.Verbose);
2236+
2237+
if (!AssetDatabase.CopyAsset(sourceLocation, targetLocation)) {
2238+
return String.Format("Failed to copy {0} to {1}.",
2239+
sourceLocation, targetLocation);
2240+
}
2241+
2242+
var unlabeledAssets = new HashSet<string>();
2243+
LabelAssets(
2244+
new [] { targetLocation },
2245+
complete: (unlabeled) => { unlabeledAssets.UnionWith(unlabeled); });
2246+
if (unlabeledAssets.Count != 0) {
2247+
return String.Format("Cannot label {0} properly.", targetLocation);
2248+
}
2249+
2250+
if (!File.Exists(targetLocation)) {
2251+
return String.Format("Cannot find the file at target location {0} after copy.",
2252+
targetLocation);
2253+
}
2254+
2255+
return "";
2256+
}
2257+
21712258
/// <summary>
21722259
/// Find the set of assets managed by this plugin.
21732260
/// </summary>
@@ -2209,6 +2296,7 @@ internal static Dictionary<string, string> GetResolutionSettings() {
22092296
{"explodeAars", SettingsDialogObj.ExplodeAars.ToString()},
22102297
{"patchAndroidManifest", SettingsDialogObj.PatchAndroidManifest.ToString()},
22112298
{"patchMainTemplateGradle", SettingsDialogObj.PatchMainTemplateGradle.ToString()},
2299+
{"localMavenRepoDir", SettingsDialogObj.LocalMavenRepoDir.ToString()},
22122300
{"useJetifier", SettingsDialogObj.UseJetifier.ToString()},
22132301
{"bundleId", GetAndroidApplicationId()},
22142302
{"gradleBuildEnabled", buildSystemSettings.GradleBuildEnabled.ToString()},
@@ -2224,6 +2312,7 @@ internal static Dictionary<string, string> GetResolutionSettings() {
22242312
"explodeAars",
22252313
"patchAndroidManifest",
22262314
"patchMainTemplateGradle",
2315+
"localMavenRepoDir",
22272316
"useJetifier",
22282317
"gradleBuildEnabled",
22292318
"gradleTemplateEnabled",

0 commit comments

Comments
 (0)