Skip to content

Commit c1fa89d

Browse files
author
Stewart Miles
committed
Support use of embedded JDK/Android SDK in Unity 2019.3+
Added support for the discovery of the JDK and Android SDK in Unity 2019.3 and newer. Thanks to @unace for the start of this... #329 Fixes #320 Bug: 149463393 Change-Id: I7ed2b9bb70cd32a36d3de2735ff7bb9932baee94
1 parent 9ac0c9f commit c1fa89d

File tree

3 files changed

+158
-52
lines changed

3 files changed

+158
-52
lines changed

source/AndroidResolver/src/JavaUtilities.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public ToolNotFoundException(string message) : base(message) {}
4141
/// <summary>
4242
/// Environment variable used to specify the Java distribution directory.
4343
/// </summary>
44-
private const string JAVA_HOME = "JAVA_HOME";
44+
internal const string JAVA_HOME = "JAVA_HOME";
4545

4646
/// <summary>
4747
/// Minimum JDK version required to build with recently released Android libraries.
@@ -52,9 +52,14 @@ public ToolNotFoundException(string message) : base(message) {}
5252
/// Find the JDK path (JAVA_HOME) either configured in the Unity editor or via the JAVA_HOME
5353
/// environment variable.
5454
/// </summary>
55-
private static string JavaHome {
55+
internal static string JavaHome {
5656
get {
57-
var javaHome = UnityEditor.EditorPrefs.GetString("JdkPath");
57+
var javaHome = null;
58+
// Unity 2019.3 added AndroidExternalToolsSettings which contains the JDK path so
59+
// try to use that first.
60+
var javaRootPath = UnityCompat.AndroidExternalToolsSettingsJdkRootPath;
61+
if (!String.IsNullOrEmpty(javaRootPath)) javaHome = javaRootPath;
62+
5863
// Unity 2019.x added installation of the JDK in the AndroidPlayer directory
5964
// so fallback to searching for it there.
6065
if (String.IsNullOrEmpty(javaHome) || EditorPrefs.GetBool("JdkUseEmbedded")) {
@@ -66,13 +71,18 @@ private static string JavaHome {
6671
androidPlayerDir, "Tools"), "OpenJDK"), platformDir);
6772
if (Directory.Exists(openJdkDir)) {
6873
javaHome = openJdkDir;
69-
}
70-
else {
74+
} else {
7175
openJdkDir = Path.Combine(androidPlayerDir, "OpenJDK");
7276
if (Directory.Exists(openJdkDir)) javaHome = openJdkDir;
7377
}
7478
}
7579
}
80+
81+
// Pre Unity 2019, use the JDK path in the preferences.
82+
if (String.IsNullOrEmpty(javaHome)) {
83+
javaHome = UnityEditor.EditorPrefs.GetString("JdkPath");
84+
}
85+
7686
// If the JDK stil isn't found, check the environment.
7787
if (String.IsNullOrEmpty(javaHome)) {
7888
javaHome = Environment.GetEnvironmentVariable(JAVA_HOME);
@@ -169,7 +179,7 @@ private static void LogJdkVersionFailedWarning(string javaPath, string commandLi
169179
PlayServicesResolver.Log(
170180
String.Format(
171181
"Failed to get Java version when running {0}\n" +
172-
"It is not be possible to verify your Java installation is new enough to " +
182+
"It is not possible to verify your Java installation is new enough to " +
173183
"compile with the latest Android SDK\n\n" +
174184
"{1}", javaPath, commandLineSummary),
175185
level: LogLevel.Warning);

source/AndroidResolver/src/PlayServicesResolver.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -513,12 +513,22 @@ public static string GradleVersion {
513513
set { gradleVersion = value; }
514514
get {
515515
if (!String.IsNullOrEmpty(gradleVersion)) return gradleVersion;
516-
var engineDir = AndroidPlaybackEngineDirectory;
517-
if (String.IsNullOrEmpty(engineDir)) return null;
516+
string gradleLibDir = null;
517+
518+
// Unity 2019.3 added AndroidExternalToolsSettings which contains the Gradle path
519+
// so try to use that first.
520+
var gradleDir = UnityCompat.AndroidExternalToolsSettingsGradlePath;
521+
if (Directory.Exists(gradleDir)) gradleLibDir = Path.Combine(gradleDir, "lib");
522+
523+
// Fallback to searching for gradle redistributed with Unity in the Android plugin.
524+
if (String.IsNullOrEmpty(gradleDir)) {
525+
var engineDir = AndroidPlaybackEngineDirectory;
526+
if (String.IsNullOrEmpty(engineDir)) return null;
527+
gradleLibDir = Path.Combine(Path.Combine(Path.Combine(engineDir, "Tools"),
528+
"gradle"), "lib");
529+
}
518530

519-
var gradleLibDir =
520-
Path.Combine(Path.Combine(Path.Combine(engineDir, "Tools"), "gradle"), "lib");
521-
if (Directory.Exists(gradleLibDir)) {
531+
if (!String.IsNullOrEmpty(gradleLibDir) && Directory.Exists(gradleLibDir)) {
522532
foreach (var path in Directory.GetFiles(gradleLibDir, "gradle-core-*.jar",
523533
SearchOption.TopDirectoryOnly)) {
524534
var match = gradleJarVersionExtract.Match(Path.GetFileName(path));
@@ -780,7 +790,12 @@ public class AndroidAbisChangedArgs : EventArgs {
780790
/// </summary>
781791
public static string AndroidSdkRoot {
782792
get {
783-
var sdkPath = EditorPrefs.GetString("AndroidSdkRoot");
793+
string sdkPath = null;
794+
// Unity 2019.3 added AndroidExternalToolsSettings which contains the Android SDK
795+
// path so try to use that first.
796+
var androidSdkRootPath = UnityCompat.AndroidExternalToolsSettingsSdkRootPath;
797+
if (!String.IsNullOrEmpty(androidSdkRootPath)) sdkPath = androidSdkRootPath;
798+
784799
// Unity 2019.x added installation of the Android SDK in the AndroidPlayer directory
785800
// so fallback to searching for it there.
786801
if (String.IsNullOrEmpty(sdkPath) || EditorPrefs.GetBool("SdkUseEmbedded")) {
@@ -790,6 +805,11 @@ public static string AndroidSdkRoot {
790805
if (Directory.Exists(androidPlayerSdkDir)) sdkPath = androidPlayerSdkDir;
791806
}
792807
}
808+
809+
// Pre Unity 2019 Android SDK path.
810+
if (String.IsNullOrEmpty(sdkPath)) {
811+
sdkPath = EditorPrefs.GetString("AndroidSdkRoot");
812+
}
793813
return sdkPath;
794814
}
795815
}

source/AndroidResolver/src/UnityCompat.cs

Lines changed: 116 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public class UnityCompat {
3939
private const string UNITY_ANDROID_EXTENSION_ASSEMBLY = "UnityEditor.Android.Extensions";
4040
private const string UNITY_ANDROID_JAVA_TOOLS_CLASS = "UnityEditor.Android.AndroidJavaTools";
4141
private const string UNITY_ANDROID_SDKTOOLS_CLASS = "UnityEditor.Android.AndroidSDKTools";
42+
private const string UNITY_ANDROID_EXTERNAL_TOOLS_SETTINGS_CLASS =
43+
"UnityEditor.Android.AndroidExternalToolsSettings";
4244
private const string UNITY_ANDROID_POST_PROCESS_ANDROID_PLAYER_CLASS =
4345
"UnityEditor.Android.PostProcessAndroidPlayer";
4446
private const string WRITE_A_BUG =
@@ -151,6 +153,64 @@ private static bool SetAndroidSDKVersion(int sdkVersion, string propertyName) {
151153
[ObsoleteAttribute("InBatchMode is obsolete, use ExecutionEnvironment.InBatchMode instead")]
152154
public static bool InBatchMode { get { return ExecutionEnvironment.InBatchMode; } }
153155

156+
private static Type AndroidExternalToolsClass {
157+
get {
158+
return Type.GetType(UNITY_ANDROID_EXTERNAL_TOOLS_SETTINGS_CLASS + ", " +
159+
UNITY_ANDROID_EXTENSION_ASSEMBLY);
160+
}
161+
}
162+
163+
/// <summary>
164+
/// Get a property of the UnityEditor.Android.AndroidExternalToolsSettings class which was
165+
/// introduced in Unity 2019.
166+
/// </summary>
167+
/// <param name="propertyName">Name of the property to query.</param>
168+
/// <returns>Value of the string property or null if the property isn't found or isn't a
169+
/// string.</returns>
170+
private static string GetAndroidExternalToolsSettingsProperty(string propertyName) {
171+
string value = null;
172+
var androidExternalTools = AndroidExternalToolsClass;
173+
if (androidExternalTools != null) {
174+
var property = androidExternalTools.GetProperty(propertyName);
175+
if (property != null) {
176+
value = property.GetValue(null, null) as string;
177+
}
178+
}
179+
return value;
180+
}
181+
182+
/// <summary>
183+
/// Get the JDK path from UnityEditor.Android.AndroidExternalToolsSettings if it's
184+
/// available.
185+
/// </summary>
186+
public static string AndroidExternalToolsSettingsJdkRootPath {
187+
get { return GetAndroidExternalToolsSettingsProperty("jdkRootPath"); }
188+
}
189+
190+
/// <summary>
191+
/// Get the Android NDK path from UnityEditor.Android.AndroidExternalToolsSettings if it's
192+
/// available.
193+
/// </summary>
194+
public static string AndroidExternalToolsSettingsNdkRootPath {
195+
get { return GetAndroidExternalToolsSettingsProperty("ndkRootPath"); }
196+
}
197+
198+
/// <summary>
199+
/// Get the Android SDK path from UnityEditor.Android.AndroidExternalToolsSettings if it's
200+
/// available.
201+
/// </summary>
202+
public static string AndroidExternalToolsSettingsSdkRootPath {
203+
get { return GetAndroidExternalToolsSettingsProperty("sdkRootPath"); }
204+
}
205+
206+
/// <summary>
207+
/// Get the Gradle path from UnityEditor.Android.AndroidExternalToolsSettings if it's
208+
/// available.
209+
/// </summary>
210+
public static string AndroidExternalToolsSettingsGradlePath {
211+
get { return GetAndroidExternalToolsSettingsProperty("gradlePath"); }
212+
}
213+
154214
private static Type AndroidJavaToolsClass {
155215
get {
156216
return Type.GetType(
@@ -248,54 +308,70 @@ private static int WarnOnAndroidSdkFallbackVersion() {
248308
public static int FindNewestInstalledAndroidSDKVersion() {
249309
var androidSdkToolsClass = AndroidSDKToolsClass;
250310
if (androidSdkToolsClass != null) {
251-
var androidSdkToolsInstance = AndroidSDKToolsInstance;
252-
if (androidSdkToolsInstance == null) return WarnOnAndroidSdkFallbackVersion();
253-
// Unity 2019+ only has a method to list the installed targets, so we need to parse
254-
// the returned list to determine the newest Android SDK version.
255-
var listTargetPlatforms = androidSdkToolsClass.GetMethod(
256-
"ListTargetPlatforms", BindingFlags.Instance | BindingFlags.NonPublic);
257-
if (listTargetPlatforms != null) {
258-
var sdkVersionList = new List<int>();
259-
const string PLATFORM_STRING_PREFIX = "android-";
260-
IEnumerable<string> platformStrings = null;
261-
try {
262-
// Unity 2019+
263-
platformStrings = (IEnumerable<string>)listTargetPlatforms.Invoke(
264-
androidSdkToolsInstance, null);
265-
} catch (Exception) {
266-
}
267-
if (platformStrings != null) {
311+
// To fetch the Android SDK version Unity runs tools in the Android SDK but doesn't
312+
// set the JAVA_HOME environment variable before launching them via these internal
313+
// methods. Therefore, we override JAVA_HOME in the process with the directory specified
314+
// in Unity's settings while querying the Android SDK and then restore the JAVA_HOME
315+
// variable to it's default state when we're finished.
316+
var previousJavaHome = Environment.GetEnvironmentVariable(JavaUtilities.JAVA_HOME);
317+
var javaHome = JavaUtilities.JavaHome;
318+
if (!String.IsNullOrEmpty(javaHome)) {
319+
Environment.SetEnvironmentVariable(JavaUtilities.JAVA_HOME, javaHome,
320+
EnvironmentVariableTarget.Process);
321+
}
322+
try {
323+
var androidSdkToolsInstance = AndroidSDKToolsInstance;
324+
if (androidSdkToolsInstance == null) return WarnOnAndroidSdkFallbackVersion();
325+
// Unity 2019+ only has a method to list the installed targets, so we need to parse
326+
// the returned list to determine the newest Android SDK version.
327+
var listTargetPlatforms = androidSdkToolsClass.GetMethod(
328+
"ListTargetPlatforms", BindingFlags.Instance | BindingFlags.NonPublic);
329+
if (listTargetPlatforms != null) {
330+
var sdkVersionList = new List<int>();
331+
const string PLATFORM_STRING_PREFIX = "android-";
332+
IEnumerable<string> platformStrings = null;
268333
try {
269-
// Unity 2018+
334+
// Unity 2019+
270335
platformStrings = (IEnumerable<string>)listTargetPlatforms.Invoke(
271-
androidSdkToolsInstance, new object[] { AndroidJavaToolsInstance });
336+
androidSdkToolsInstance, null);
272337
} catch (Exception) {
273338
}
274-
}
275-
if (platformStrings != null) {
276-
foreach (var platformString in platformStrings) {
277-
if (platformString.StartsWith(PLATFORM_STRING_PREFIX)) {
278-
int sdkVersion;
279-
if (Int32.TryParse(
280-
platformString.Substring(PLATFORM_STRING_PREFIX.Length),
281-
out sdkVersion)) {
282-
sdkVersionList.Add(sdkVersion);
283-
}
339+
if (platformStrings != null) {
340+
try {
341+
// Unity 2018+
342+
platformStrings = (IEnumerable<string>)listTargetPlatforms.Invoke(
343+
androidSdkToolsInstance, new object[] { AndroidJavaToolsInstance });
344+
} catch (Exception) {
284345
}
285346
}
286-
sdkVersionList.Sort();
287-
var numberOfSdks = sdkVersionList.Count;
288-
if (numberOfSdks > 0) {
289-
return sdkVersionList[numberOfSdks - 1];
347+
if (platformStrings != null) {
348+
foreach (var platformString in platformStrings) {
349+
if (platformString.StartsWith(PLATFORM_STRING_PREFIX)) {
350+
int sdkVersion;
351+
if (Int32.TryParse(
352+
platformString.Substring(PLATFORM_STRING_PREFIX.Length),
353+
out sdkVersion)) {
354+
sdkVersionList.Add(sdkVersion);
355+
}
356+
}
357+
}
358+
sdkVersionList.Sort();
359+
var numberOfSdks = sdkVersionList.Count;
360+
if (numberOfSdks > 0) {
361+
return sdkVersionList[numberOfSdks - 1];
362+
}
290363
}
291364
}
292-
}
293-
var getTopAndroidPlatformAvailable =
294-
androidSdkToolsClass.GetMethod("GetTopAndroidPlatformAvailable");
295-
if (getTopAndroidPlatformAvailable != null) {
296-
return (int)getTopAndroidPlatformAvailable.Invoke(
297-
androidSdkToolsInstance, BindingFlags.NonPublic, null,
298-
new object[] { null }, null);
365+
var getTopAndroidPlatformAvailable =
366+
androidSdkToolsClass.GetMethod("GetTopAndroidPlatformAvailable");
367+
if (getTopAndroidPlatformAvailable != null) {
368+
return (int)getTopAndroidPlatformAvailable.Invoke(
369+
androidSdkToolsInstance, BindingFlags.NonPublic, null,
370+
new object[] { null }, null);
371+
}
372+
} finally {
373+
Environment.SetEnvironmentVariable(JavaUtilities.JAVA_HOME, previousJavaHome,
374+
EnvironmentVariableTarget.Process);
299375
}
300376
}
301377

0 commit comments

Comments
 (0)