Skip to content

Commit fd56fc4

Browse files
Merge pull request #4895 from NativeScript/kddimitrov/refactor-android-tools-info
feat: add support for Android SDK 29 for compilation
2 parents 626db9c + 6d4d5cc commit fd56fc4

8 files changed

+94
-190
lines changed

lib/android-tools-info.ts

+42-164
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,62 @@
11
import * as path from "path";
2-
import * as semver from "semver";
32
import { cache } from "./common/decorators";
43
import { androidToolsInfo } from "nativescript-doctor";
54

65
export class AndroidToolsInfo implements IAndroidToolsInfo {
7-
private static ANDROID_TARGET_PREFIX = "android";
8-
private static SUPPORTED_TARGETS = [
9-
"android-17",
10-
"android-18",
11-
"android-19",
12-
"android-21",
13-
"android-22",
14-
"android-23",
15-
"android-24",
16-
"android-25",
17-
"android-26",
18-
"android-27",
19-
"android-28",
20-
];
21-
private static MIN_REQUIRED_COMPILE_TARGET = 28;
22-
private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=23";
23-
private static VERSION_REGEX = /((\d+\.){2}\d+)/;
24-
25-
private showWarningsAsErrors: boolean;
26-
private toolsInfo: IAndroidToolsInfoData;
27-
private selectedCompileSdk: number;
28-
private get androidHome(): string {
29-
return process.env["ANDROID_HOME"];
30-
}
31-
326
constructor(private $errors: IErrors,
33-
private $fs: IFileSystem,
347
private $logger: ILogger,
358
private $options: IOptions,
369
protected $staticConfig: Config.IStaticConfig) {
3710
}
3811

3912
@cache()
40-
public getToolsInfo(): IAndroidToolsInfoData {
41-
if (!this.toolsInfo) {
42-
const infoData: IAndroidToolsInfoData = Object.create(null);
43-
infoData.androidHomeEnvVar = this.androidHome;
44-
infoData.compileSdkVersion = this.getCompileSdkVersion();
45-
infoData.buildToolsVersion = this.getBuildToolsVersion();
46-
infoData.targetSdkVersion = this.getTargetSdk();
47-
infoData.generateTypings = this.shouldGenerateTypings();
48-
49-
this.toolsInfo = infoData;
50-
}
13+
public getToolsInfo(config: IProjectDir): IAndroidToolsInfoData {
14+
const infoData: IAndroidToolsInfoData = <IAndroidToolsInfoData>(androidToolsInfo.getToolsInfo({projectDir: config.projectDir}));
15+
16+
infoData.androidHomeEnvVar = androidToolsInfo.androidHome;
17+
infoData.compileSdkVersion = this.getCompileSdkVersion(infoData.installedTargets, infoData.compileSdkVersion);
18+
infoData.targetSdkVersion = this.getTargetSdk(infoData.compileSdkVersion);
19+
infoData.generateTypings = this.shouldGenerateTypings();
20+
21+
this.$logger.trace("Installed Android Targets are: ", infoData.installedTargets);
22+
this.$logger.trace("Selected buildToolsVersion is:", infoData.buildToolsVersion);
5123

52-
return this.toolsInfo;
24+
return infoData;
5325
}
5426

5527
public validateInfo(options?: IAndroidToolsInfoValidateInput): boolean {
5628
let detectedErrors = false;
57-
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
58-
const isAndroidHomeValid = this.validateAndroidHomeEnvVariable();
29+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
30+
const isAndroidHomeValid = this.validateAndroidHomeEnvVariable(options);
5931

60-
detectedErrors = androidToolsInfo.validateInfo().map(warning => this.printMessage(warning.warning)).length > 0;
32+
detectedErrors = androidToolsInfo.validateInfo({projectDir: options.projectDir}).map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
6133

6234
if (options && options.validateTargetSdk) {
63-
detectedErrors = this.validateTargetSdk();
35+
detectedErrors = this.validateTargetSdk(options);
6436
}
6537

6638
return detectedErrors || !isAndroidHomeValid;
6739
}
6840

69-
public validateTargetSdk(options?: IAndroidToolsInfoOptions): boolean {
70-
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
41+
public validateTargetSdk(options: IAndroidToolsInfoOptions): boolean {
42+
let detectedErrors = false;
7143

72-
const toolsInfoData = this.getToolsInfo();
44+
const toolsInfoData = this.getToolsInfo({ projectDir: options.projectDir});
7345
const targetSdk = toolsInfoData.targetSdkVersion;
74-
const newTarget = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${targetSdk}`;
7546

76-
if (!_.includes(AndroidToolsInfo.SUPPORTED_TARGETS, newTarget)) {
77-
const supportedVersions = AndroidToolsInfo.SUPPORTED_TARGETS.sort();
78-
const minSupportedVersion = this.parseAndroidSdkString(_.first(supportedVersions));
47+
detectedErrors = androidToolsInfo.validateMinSupportedTargetSdk({targetSdk, projectDir: options.projectDir}).map(warning => this.printMessage(warning.warning, options.showWarningsAsErrors)).length > 0;
7948

80-
if (targetSdk && (targetSdk < minSupportedVersion)) {
81-
this.printMessage(`The selected Android target SDK ${newTarget} is not supported. You must target ${minSupportedVersion} or later.`);
82-
return true;
83-
} else if (!targetSdk || targetSdk > this.getMaxSupportedVersion()) {
84-
this.$logger.warn(`Support for the selected Android target SDK ${newTarget} is not verified. Your Android app might not work as expected.`);
85-
}
49+
if (!detectedErrors) {
50+
androidToolsInfo.validataMaxSupportedTargetSdk({targetSdk, projectDir: options.projectDir}).map(warning => this.$logger.warn(warning.warning));
8651
}
8752

88-
return false;
53+
return detectedErrors;
8954
}
9055

9156
public validateJavacVersion(installedJavacVersion: string, options?: IAndroidToolsInfoOptions): boolean {
92-
if (options) {
93-
this.showWarningsAsErrors = options.showWarningsAsErrors;
94-
}
57+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
9558

96-
return androidToolsInfo.validateJavacVersion(installedJavacVersion).map(warning => this.printMessage(warning.warning)).length > 0;
59+
return androidToolsInfo.validateJavacVersion(installedJavacVersion).map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
9760
}
9861

9962
public async getPathToAdbFromAndroidHome(): Promise<string> {
@@ -102,19 +65,17 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
10265
} catch (err) {
10366
// adb does not exist, so ANDROID_HOME is not set correctly
10467
// try getting default adb path (included in CLI package)
105-
this.$logger.trace(`Error while executing '${path.join(this.androidHome, "platform-tools", "adb")} help'. Error is: ${err.message}`);
68+
this.$logger.trace(`Error while executing '${path.join(androidToolsInfo.androidHome, "platform-tools", "adb")} help'. Error is: ${err.message}`);
10669
}
10770

10871
return null;
10972
}
11073

11174
@cache()
11275
public validateAndroidHomeEnvVariable(options?: IAndroidToolsInfoOptions): boolean {
113-
if (options) {
114-
this.showWarningsAsErrors = options.showWarningsAsErrors;
115-
}
76+
const showWarningsAsErrors = options && options.showWarningsAsErrors;
11677

117-
return androidToolsInfo.validateAndroidHomeEnvVariable().map(warning => this.printMessage(warning.warning)).length > 0;
78+
return androidToolsInfo.validateAndroidHomeEnvVariable().map(warning => this.printMessage(warning.warning, showWarningsAsErrors)).length > 0;
11879
}
11980

12081
private shouldGenerateTypings(): boolean {
@@ -127,119 +88,36 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
12788
* In case additional details must be shown as info message, use the second parameter.
12889
* NOTE: The additional information will not be printed when showWarningsAsErrors flag is set.
12990
* @param {string} msg The message that will be shown as warning or error.
130-
* @param {string} additionalMsg The additional message that will be shown as info message.
13191
* @return {void}
13292
*/
133-
private printMessage(msg: string, additionalMsg?: string): void {
134-
if (this.showWarningsAsErrors) {
93+
private printMessage(msg: string, showWarningsAsErrors: boolean): void {
94+
if (showWarningsAsErrors) {
13595
this.$errors.failWithoutHelp(msg);
13696
} else {
13797
this.$logger.warn(msg);
13898
}
139-
140-
if (additionalMsg) {
141-
this.$logger.printMarkdown(additionalMsg);
142-
}
14399
}
144100

145-
private getCompileSdkVersion(): number {
146-
if (!this.selectedCompileSdk) {
147-
const userSpecifiedCompileSdk = this.$options.compileSdk;
148-
if (userSpecifiedCompileSdk) {
149-
const installedTargets = this.getInstalledTargets();
150-
const androidCompileSdk = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${userSpecifiedCompileSdk}`;
151-
if (!_.includes(installedTargets, androidCompileSdk)) {
152-
this.$errors.failWithoutHelp(`You have specified '${userSpecifiedCompileSdk}' for compile sdk, but it is not installed on your system.`);
153-
}
154-
155-
this.selectedCompileSdk = userSpecifiedCompileSdk;
156-
} else {
157-
const latestValidAndroidTarget = this.getLatestValidAndroidTarget();
158-
if (latestValidAndroidTarget) {
159-
const integerVersion = this.parseAndroidSdkString(latestValidAndroidTarget);
160-
161-
if (integerVersion && integerVersion >= AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET) {
162-
this.selectedCompileSdk = integerVersion;
163-
}
164-
}
165-
}
166-
}
101+
private getCompileSdkVersion(installedTargets: string[], latestCompileSdk: number): number {
102+
const userSpecifiedCompileSdk = this.$options.compileSdk;
167103

168-
return this.selectedCompileSdk;
169-
}
170-
171-
private getTargetSdk(): number {
172-
const targetSdk = this.$options.sdk ? parseInt(this.$options.sdk) : this.getCompileSdkVersion();
173-
this.$logger.trace(`Selected targetSdk is: ${targetSdk}`);
174-
return targetSdk;
175-
}
176-
177-
private getMatchingDir(pathToDir: string, versionRange: string): string {
178-
let selectedVersion: string;
179-
if (this.$fs.exists(pathToDir)) {
180-
const subDirs = this.$fs.readDirectory(pathToDir);
181-
this.$logger.trace(`Directories found in ${pathToDir} are ${subDirs.join(", ")}`);
182-
183-
const subDirsVersions = subDirs
184-
.map(dirName => {
185-
const dirNameGroups = dirName.match(AndroidToolsInfo.VERSION_REGEX);
186-
if (dirNameGroups) {
187-
return dirNameGroups[1];
188-
}
189-
190-
return null;
191-
})
192-
.filter(dirName => !!dirName);
193-
this.$logger.trace(`Versions found in ${pathToDir} are ${subDirsVersions.join(", ")}`);
194-
const version = semver.maxSatisfying(subDirsVersions, versionRange);
195-
if (version) {
196-
selectedVersion = _.find(subDirs, dir => dir.indexOf(version) !== -1);
104+
if (userSpecifiedCompileSdk) {
105+
const androidCompileSdk = `${androidToolsInfo.ANDROID_TARGET_PREFIX}-${userSpecifiedCompileSdk}`;
106+
if (!_.includes(installedTargets, androidCompileSdk)) {
107+
this.$errors.failWithoutHelp(`You have specified '${userSpecifiedCompileSdk}' for compile sdk, but it is not installed on your system.`);
197108
}
198-
}
199-
this.$logger.trace("Selected version is: ", selectedVersion);
200-
return selectedVersion;
201-
}
202-
203-
private getBuildToolsRange(): string {
204-
return `${AndroidToolsInfo.REQUIRED_BUILD_TOOLS_RANGE_PREFIX} <=${this.getMaxSupportedVersion()}`;
205-
}
206109

207-
private getBuildToolsVersion(): string {
208-
let buildToolsVersion: string;
209-
if (this.androidHome) {
210-
const pathToBuildTools = path.join(this.androidHome, "build-tools");
211-
const buildToolsRange = this.getBuildToolsRange();
212-
buildToolsVersion = this.getMatchingDir(pathToBuildTools, buildToolsRange);
110+
return userSpecifiedCompileSdk;
213111
}
214112

215-
return buildToolsVersion;
216-
}
217-
218-
private getLatestValidAndroidTarget(): string {
219-
const installedTargets = this.getInstalledTargets();
220-
return _.findLast(AndroidToolsInfo.SUPPORTED_TARGETS.sort(), supportedTarget => _.includes(installedTargets, supportedTarget));
221-
}
222-
223-
private parseAndroidSdkString(androidSdkString: string): number {
224-
return parseInt(androidSdkString.replace(`${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-`, ""));
113+
return latestCompileSdk;
225114
}
226115

227-
@cache()
228-
private getInstalledTargets(): string[] {
229-
let installedTargets: string[] = [];
230-
if (this.androidHome) {
231-
const pathToInstalledTargets = path.join(this.androidHome, "platforms");
232-
if (this.$fs.exists(pathToInstalledTargets)) {
233-
installedTargets = this.$fs.readDirectory(pathToInstalledTargets);
234-
}
235-
}
236-
this.$logger.trace("Installed Android Targets are: ", installedTargets);
237-
238-
return installedTargets;
239-
}
240-
241-
private getMaxSupportedVersion(): number {
242-
return this.parseAndroidSdkString(_.last(AndroidToolsInfo.SUPPORTED_TARGETS.sort()));
116+
// TODO check if still needed
117+
private getTargetSdk(compileSdk: number): number {
118+
const targetSdk = this.$options.sdk ? parseInt(this.$options.sdk) : compileSdk;
119+
this.$logger.trace(`Selected targetSdk is: ${targetSdk}`);
120+
return targetSdk;
243121
}
244122
}
245123
$injector.register("androidToolsInfo", AndroidToolsInfo);

lib/declarations.d.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -646,9 +646,10 @@ interface IAndroidToolsInfo {
646646
/**
647647
* Provides information about installed Android SDKs, Build Tools, Support Library
648648
* and ANDROID_HOME environement variable.
649+
* @param {IProjectDir} config Object with a single property - projectDir. This is the root directory where NativeScript project is located.
649650
* @return {IAndroidToolsInfoData} Information about installed Android Tools and SDKs.
650651
*/
651-
getToolsInfo(): IAndroidToolsInfoData;
652+
getToolsInfo(config?: IProjectDir): IAndroidToolsInfoData;
652653

653654
/**
654655
* Validates the information about required Android tools and SDK versions.
@@ -689,7 +690,7 @@ interface IAndroidToolsInfo {
689690
/**
690691
* Describes information about installed Android tools and SDKs.
691692
*/
692-
interface IAndroidToolsInfoData {
693+
interface IAndroidToolsInfoData extends NativeScriptDoctor.IAndroidToolsInfoData {
693694
/**
694695
* The value of ANDROID_HOME environment variable.
695696
*/
@@ -720,11 +721,11 @@ interface IAndroidToolsInfoData {
720721
/**
721722
* Describes options that can be passed to methods from IAndroidToolsInfo interface
722723
*/
723-
interface IAndroidToolsInfoOptions {
724+
interface IAndroidToolsInfoOptions extends Partial<IProjectDir> {
724725
/**
725726
* Defines if the warning messages should treated as error.
726727
*/
727-
showWarningsAsErrors: boolean;
728+
showWarningsAsErrors?: boolean;
728729
}
729730

730731
interface IAndroidToolsInfoValidateInput extends IAndroidToolsInfoOptions {

lib/definitions/android-plugin-migrator.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface IAndroidPluginBuildService {
1919
* Describes data required for building plugin for Android.
2020
* The data can be consumed in the buildAndroidPlugin hook.
2121
*/
22-
interface IBuildAndroidPluginData {
22+
interface IBuildAndroidPluginData extends Partial<IProjectDir> {
2323
/**
2424
* Directory where the plugin will be build.
2525
* Usually this is the `<project dir>/platforms/tempPlugin/<plugin name>` dir.

lib/services/android-plugin-build-service.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
189189
await this.updateManifest(manifestFilePath, pluginTempMainSrcDir, shortPluginName);
190190
this.copySourceSetDirectories(androidSourceDirectories, pluginTempMainSrcDir);
191191
await this.setupGradle(pluginTempDir, options.platformsAndroidDirPath, options.projectDir);
192-
await this.buildPlugin({ pluginDir: pluginTempDir, pluginName: options.pluginName });
192+
await this.buildPlugin({ pluginDir: pluginTempDir, pluginName: options.pluginName, projectDir: options.projectDir });
193193
this.$watchIgnoreListService.addFileToIgnoreList(path.join(options.aarOutputDir, `${shortPluginName}.aar`));
194194
this.copyAar(shortPluginName, pluginTempDir, options.aarOutputDir);
195195
this.writePluginHashInfo(pluginSourceFileHashesInfo, pluginTempDir);
@@ -440,8 +440,8 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
440440
@hook("buildAndroidPlugin")
441441
private async buildPlugin(pluginBuildSettings: IBuildAndroidPluginData): Promise<void> {
442442
if (!pluginBuildSettings.androidToolsInfo) {
443-
this.$androidToolsInfo.validateInfo({ showWarningsAsErrors: true, validateTargetSdk: true });
444-
pluginBuildSettings.androidToolsInfo = this.$androidToolsInfo.getToolsInfo();
443+
this.$androidToolsInfo.validateInfo({ showWarningsAsErrors: true, validateTargetSdk: true, projectDir: pluginBuildSettings.projectDir });
444+
pluginBuildSettings.androidToolsInfo = this.$androidToolsInfo.getToolsInfo({ projectDir: pluginBuildSettings.projectDir });
445445
}
446446

447447
const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew";

lib/services/android-project-service.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
121121
notConfiguredEnvOptions
122122
});
123123

124-
this.$androidToolsInfo.validateTargetSdk({ showWarningsAsErrors: true });
124+
this.$androidToolsInfo.validateTargetSdk({ showWarningsAsErrors: true, projectDir: projectData.projectDir });
125125

126126
return {
127127
checkEnvironmentRequirementsOutput
@@ -134,7 +134,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
134134
}
135135

136136
this.$fs.ensureDirectoryExists(this.getPlatformData(projectData).projectRoot);
137-
const androidToolsInfo = this.$androidToolsInfo.getToolsInfo();
137+
const androidToolsInfo = this.$androidToolsInfo.getToolsInfo({ projectDir: projectData.projectDir});
138138
const targetSdkVersion = androidToolsInfo && androidToolsInfo.targetSdkVersion;
139139
this.$logger.trace(`Using Android SDK '${targetSdkVersion}'.`);
140140

lib/services/android/gradle-build-args-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class GradleBuildArgsService implements IGradleBuildArgsService {
2222
private getBaseTaskArgs(buildData: IAndroidBuildData): string[] {
2323
const args = this.getBuildLoggingArgs();
2424

25-
const toolsInfo = this.$androidToolsInfo.getToolsInfo();
25+
const toolsInfo = this.$androidToolsInfo.getToolsInfo({projectDir: buildData.projectDir});
2626
args.push(
2727
`-PcompileSdk=android-${toolsInfo.compileSdkVersion}`,
2828
`-PtargetSdk=${toolsInfo.targetSdkVersion}`,

0 commit comments

Comments
 (0)