Skip to content

Commit eef40bb

Browse files
author
Stewart Miles
committed
Fixed up maven repos embedded in Unity projects when in Gradle builds.
When resolving Android dependencies using Gradle and a mainTemplate.gradle file, srcaar artifacts in maven repos embedded in the Unity project are renamed to aar so they can be included in the Android build process. However, some plugins (like Google Play Games) ship with Maven POMs that refrence the srcaar artifacts directly rather than the aar artifacts. This results in the renamed aar files being ignored in the Android build process. This commit patches Maven POMs so they reference the correct artifact when the packaging is changed by the Gradle Android Resolution step. If libraries are removed, the POMs are updated to point at the packaging for the artifact in the directory (e.g srcaar). Fixes googlesamples#208 Bug: 132168073 Change-Id: I357c6a1197d4fc15cc924b5a4d9e4d7c79be922d
1 parent 595ea68 commit eef40bb

File tree

4 files changed

+238
-61
lines changed

4 files changed

+238
-61
lines changed

source/PlayServicesResolver/PlayServicesResolver.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<Compile Include="src\DefaultResolver.cs" />
6363
<Compile Include="src\GradleTemplateResolver.cs" />
6464
<Compile Include="src\IResolver.cs" />
65+
<Compile Include="src\LocalMavenRepository.cs" />
6566
<Compile Include="src\JavaUtilities.cs" />
6667
<Compile Include="src\PlayServicesPreBuild.cs" />
6768
<Compile Include="src\PlayServicesResolver.cs" />

source/PlayServicesResolver/src/GradleTemplateResolver.cs

Lines changed: 44 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -67,83 +67,64 @@ internal class GradleTemplateResolver {
6767
/// </summary>
6868
private const string DependenciesToken = "**DEPS**";
6969

70-
/// <summary>
71-
/// Find all srcaar files under a directory.
72-
/// </summary>
73-
private static List<string> FindSrcAars(string directory) {
74-
var foundFiles = new List<string>();
75-
foreach (string filename in Directory.GetFiles(directory)) {
76-
if (Path.GetExtension(filename).ToLower() == ".srcaar") {
77-
foundFiles.Add(filename);
78-
}
79-
}
80-
foreach (string currentDirectory in Directory.GetDirectories(directory)) {
81-
foundFiles.AddRange(FindSrcAars(currentDirectory));
82-
}
83-
return foundFiles;
84-
}
8570

8671
/// <summary>
8772
/// Copy srcaar files to aar files that are excluded from Unity's build process.
8873
/// </summary>
74+
/// <param name="dependencies">Dependencies to inject.</param>
75+
/// <returns>true if successful, false otherwise.</returns>
8976
private static bool CopySrcAars(ICollection<Dependency> dependencies) {
9077
// Find all repositories embedded in the project.
91-
var repos = new HashSet<string>();
92-
foreach (var dependency in dependencies) {
93-
foreach (var repo in dependency.Repositories) {
94-
if (repo.Replace("\\", "/").ToLower().StartsWith("assets/")) {
95-
repos.Add(repo);
96-
}
97-
}
98-
}
9978
bool succeeded = true;
10079
var aarFiles = new List<string>();
10180
// Copy each .srcaar file to .aar while configuring the plugin importer to ignore the
10281
// file.
103-
foreach (var repo in repos) {
104-
foreach (var srcaar in FindSrcAars(repo)) {
105-
var dir = Path.GetDirectoryName(srcaar);
106-
var filename = Path.GetFileNameWithoutExtension(srcaar);
107-
var targetFilename = Path.Combine(dir, filename + ".aar");
108-
aarFiles.Add(targetFilename);
109-
if (!File.Exists(targetFilename)) {
110-
bool configuredAar = false;
111-
bool copiedAndLabeledAar = AssetDatabase.CopyAsset(srcaar, targetFilename);
112-
if (copiedAndLabeledAar) {
113-
var unlabeledAssets = new HashSet<string>();
114-
PlayServicesResolver.LabelAssets(
115-
new [] { targetFilename },
116-
complete: (unlabeled) => { unlabeledAssets.UnionWith(unlabeled); });
117-
copiedAndLabeledAar = unlabeledAssets.Count == 0;
118-
}
119-
if (copiedAndLabeledAar) {
120-
try {
121-
PluginImporter importer = (PluginImporter)AssetImporter.GetAtPath(
122-
targetFilename);
123-
importer.SetCompatibleWithAnyPlatform(false);
124-
importer.SetCompatibleWithPlatform(BuildTarget.Android, false);
125-
configuredAar = true;
126-
} catch (Exception ex) {
127-
PlayServicesResolver.Log(String.Format(
128-
"Failed to disable {0} from being included by Unity's " +
129-
"internal build. {0} has been deleted and will not be " +
130-
"included in Gradle builds. ({1})", srcaar, ex),
131-
level: LogLevel.Error);
132-
}
133-
} else {
82+
foreach (var aar in LocalMavenRepository.FindAarsInLocalRepos(dependencies)) {
83+
var dir = Path.GetDirectoryName(aar);
84+
var filename = Path.GetFileNameWithoutExtension(aar);
85+
var targetFilename = Path.Combine(dir, filename + ".aar");
86+
bool configuredAar = File.Exists(targetFilename);
87+
if (!configuredAar) {
88+
bool copiedAndLabeledAar = AssetDatabase.CopyAsset(aar, targetFilename);
89+
if (copiedAndLabeledAar) {
90+
var unlabeledAssets = new HashSet<string>();
91+
PlayServicesResolver.LabelAssets(
92+
new [] { targetFilename },
93+
complete: (unlabeled) => { unlabeledAssets.UnionWith(unlabeled); });
94+
copiedAndLabeledAar = unlabeledAssets.Count == 0;
95+
}
96+
if (copiedAndLabeledAar) {
97+
try {
98+
PluginImporter importer = (PluginImporter)AssetImporter.GetAtPath(
99+
targetFilename);
100+
importer.SetCompatibleWithAnyPlatform(false);
101+
importer.SetCompatibleWithPlatform(BuildTarget.Android, false);
102+
configuredAar = true;
103+
} catch (Exception ex) {
134104
PlayServicesResolver.Log(String.Format(
135-
"Unable to copy {0} to {1}. {1} will not be included in Gradle " +
136-
"builds.", srcaar, targetFilename), level: LogLevel.Error);
105+
"Failed to disable {0} from being included by Unity's " +
106+
"internal build. {0} has been deleted and will not be " +
107+
"included in Gradle builds. ({1})", aar, ex),
108+
level: LogLevel.Error);
137109
}
138-
if (!configuredAar) {
139-
if (File.Exists(targetFilename)) {
140-
AssetDatabase.DeleteAsset(targetFilename);
141-
}
142-
succeeded = false;
110+
} else {
111+
PlayServicesResolver.Log(String.Format(
112+
"Unable to copy {0} to {1}. {1} will not be included in Gradle " +
113+
"builds.", aar, targetFilename), level: LogLevel.Error);
114+
}
115+
if (configuredAar) {
116+
aarFiles.Add(targetFilename);
117+
} else {
118+
if (File.Exists(targetFilename)) {
119+
AssetDatabase.DeleteAsset(targetFilename);
143120
}
121+
succeeded = false;
144122
}
145123
}
146124
}
125+
foreach (var aar in aarFiles) {
126+
if (!LocalMavenRepository.PatchPomFile(aar)) succeeded = false;
127+
}
147128
return succeeded;
148129
}
149130

@@ -245,6 +226,8 @@ public List<string> ProcessLine(string line, out bool injectionApplied) {
245226
/// <summary>
246227
/// Inject / update dependencies in the gradle template file.
247228
/// </summary>
229+
/// <param name="dependencies">Dependencies to inject.</param>
230+
/// <returns>true if successful, false otherwise.</returns>
248231
public static bool InjectDependencies(ICollection<Dependency> dependencies) {
249232
var fileDescription = String.Format("gradle template {0}", GradleTemplatePath);
250233
PlayServicesResolver.Log(String.Format("Reading {0}", fileDescription),
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// <copyright file="LocalMavenRepository.cs" company="Google Inc.">
2+
// Copyright (C) 2019 Google Inc. All Rights Reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
// </copyright>
16+
17+
namespace GooglePlayServices {
18+
using System;
19+
using System.Collections.Generic;
20+
using System.IO;
21+
using System.Xml;
22+
23+
using Google;
24+
using Google.JarResolver;
25+
26+
/// <summary>
27+
/// Finds and operates on Maven repositories embedded in the Unity project.
28+
/// </summary>
29+
internal class LocalMavenRepository {
30+
31+
/// <summary>
32+
/// Find paths to repositories that are included in the project.
33+
/// </summary>
34+
/// <param name="dependencies">Dependencies to search for local repositories.</param>
35+
/// <returns>Set of repository paths in the project.</returns>
36+
public static HashSet<string> FindLocalRepos(ICollection<Dependency> dependencies) {
37+
// Find all repositories embedded in the project.
38+
var repos = new HashSet<string>();
39+
foreach (var dependency in dependencies) {
40+
foreach (var repo in dependency.Repositories) {
41+
if (repo.Replace("\\", "/").ToLower().StartsWith("assets/")) {
42+
repos.Add(repo);
43+
}
44+
}
45+
}
46+
return repos;
47+
}
48+
49+
/// <summary>
50+
/// Find all .aar and .srcaar files under a directory.
51+
/// </summary>
52+
/// <param name="directory">Directory to recursively search.</param>
53+
/// <returns>A list of found aar and srcaar files.</returns>
54+
public static List<string> FindAars(string directory) {
55+
var foundFiles = new List<string>();
56+
foreach (string filename in Directory.GetFiles(directory)) {
57+
var packaging = Path.GetExtension(filename).ToLower();
58+
if (packaging == ".aar" || packaging == ".srcaar") foundFiles.Add(filename);
59+
}
60+
foreach (string currentDirectory in Directory.GetDirectories(directory)) {
61+
foundFiles.AddRange(FindAars(currentDirectory));
62+
}
63+
return foundFiles;
64+
}
65+
66+
/// <summary>
67+
/// Find all .aar and .srcaar files in the project's repositories.
68+
/// </summary>
69+
/// <param name="dependencies">Dependencies to search for local repositories.</param>
70+
/// <returns>A list of found aar and srcaar files.</returns>
71+
public static List<string> FindAarsInLocalRepos(ICollection<Dependency> dependencies) {
72+
var libraries = new List<string>();
73+
foreach (var repo in FindLocalRepos(dependencies)) {
74+
libraries.AddRange(FindAars(repo));
75+
}
76+
return libraries;
77+
}
78+
79+
/// <summary>
80+
/// Get a path without a filename extension.
81+
/// </summary>
82+
/// <param name="filename">Path to a file.</param>
83+
/// <returns>Path (including directory) without a filename extension.</returns>
84+
private static string PathWithoutExtension(string path) {
85+
return Path.Combine(Path.GetDirectoryName(path),
86+
Path.GetFileNameWithoutExtension(path));
87+
}
88+
89+
/// <summary>
90+
/// Search for the POM file associated with the specified maven artifact and patch the
91+
/// packaging reference if the POM doesn't reference the artifact.
92+
/// file.
93+
/// </summary>
94+
/// <param name="artifactFilename">artifactFilename</param>
95+
/// <returns>true if successful, false otherwise.</returns>
96+
public static bool PatchPomFile(string artifactFilename) {
97+
var failureImpact = String.Format("{0} may not be included in your project",
98+
Path.GetFileName(artifactFilename));
99+
var pomFilename = PathWithoutExtension(artifactFilename) + ".pom";
100+
if (!File.Exists(pomFilename)) {
101+
PlayServicesResolver.Log(
102+
String.Format("Maven POM {0} for {1} does not exist. " + failureImpact,
103+
pomFilename, artifactFilename), level: LogLevel.Warning);
104+
return false;
105+
}
106+
var artifactPackaging = Path.GetExtension(artifactFilename).ToLower().Substring(1);
107+
var pom = new XmlDocument();
108+
try {
109+
using (var stream = new StreamReader(pomFilename)) {
110+
pom.Load(stream);
111+
}
112+
} catch (Exception ex) {
113+
PlayServicesResolver.Log(
114+
String.Format("Unable to read maven POM {0} for {1} ({2}). " + failureImpact,
115+
pom, artifactFilename, ex), level: LogLevel.Error);
116+
return false;
117+
}
118+
bool updatedPackaging = false;
119+
XmlNodeList packagingNode = pom.GetElementsByTagName("packaging");
120+
foreach (XmlNode node in packagingNode) {
121+
if (node.InnerText != artifactPackaging) {
122+
PlayServicesResolver.Log(String.Format(
123+
"Replacing packaging of maven POM {0} {1} --> {2}",
124+
pomFilename, node.InnerText, artifactPackaging), level: LogLevel.Verbose);
125+
node.InnerText = artifactPackaging;
126+
updatedPackaging = true;
127+
}
128+
}
129+
if (updatedPackaging) {
130+
try {
131+
using (var xmlWriter =
132+
XmlWriter.Create(pomFilename,
133+
new XmlWriterSettings {
134+
Indent = true,
135+
IndentChars = " ",
136+
NewLineChars = "\n",
137+
NewLineHandling = NewLineHandling.Replace
138+
})) {
139+
pom.Save(xmlWriter);
140+
}
141+
} catch (Exception ex) {
142+
PlayServicesResolver.Log(
143+
String.Format("Unable to write patch maven POM {0} for {1} with " +
144+
"packaging {2} ({3}). " + failureImpact,
145+
pom, artifactFilename, artifactPackaging, ex));
146+
return false;
147+
}
148+
}
149+
return true;
150+
}
151+
152+
/// <summary>
153+
/// Patch all POM files in the local repository with PatchPomFile().
154+
/// If a srcaar and an aar are present in the same directory the POM is patched with a
155+
/// reference to the aar.
156+
/// </summary>
157+
/// <returns>true if successful, false otherwise.</returns>
158+
public static bool PatchPomFilesInLocalRepos(ICollection<Dependency> dependencies) {
159+
// Filename extensions by the basename of each file path.
160+
var extensionsByBasenames = new Dictionary<string, HashSet<string>>();
161+
foreach (var filename in FindAarsInLocalRepos(dependencies)) {
162+
var pathWithoutExtension = PathWithoutExtension(filename);
163+
HashSet<string> extensions;
164+
if (!extensionsByBasenames.TryGetValue(pathWithoutExtension, out extensions)) {
165+
extensions = new HashSet<string>();
166+
extensionsByBasenames[pathWithoutExtension] = extensions;
167+
}
168+
extensions.Add(Path.GetExtension(filename));
169+
}
170+
bool successful = true;
171+
var packagingPriority = new [] { ".aar", ".srcaar" };
172+
foreach (var kv in extensionsByBasenames) {
173+
string filePackagingToUse = "";
174+
foreach (var packaging in packagingPriority) {
175+
bool foundFile = false;
176+
foreach (var filenamePackaging in kv.Value) {
177+
filePackagingToUse = filenamePackaging;
178+
if (filenamePackaging.ToLower() == packaging) {
179+
foundFile = true;
180+
break;
181+
}
182+
}
183+
if (foundFile) break;
184+
}
185+
successful &= PatchPomFile(kv.Key + filePackagingToUse);
186+
}
187+
return successful;
188+
}
189+
}
190+
191+
}

source/PlayServicesResolver/src/PlayServicesResolver.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,8 @@ public static void DeleteResolvedLibraries(System.Action complete = null) {
13591359
GooglePlayServices.SettingsDialog.EnableAutoResolution = false;
13601360
}
13611361
DeleteLabeledAssets();
1362+
LocalMavenRepository.PatchPomFilesInLocalRepos(
1363+
PlayServicesSupport.GetAllDependencies().Values);
13621364
if (GradleTemplateEnabled) {
13631365
GradleTemplateResolver.InjectDependencies(new List<Dependency>());
13641366
}

0 commit comments

Comments
 (0)