@@ -6,52 +6,68 @@ import { Helpers } from './helpers';
6
6
import { EOL } from "os" ;
7
7
import * as semver from "semver" ;
8
8
import * as path from "path" ;
9
+ import * as _ from "lodash" ;
9
10
10
11
export class AndroidToolsInfo implements NativeScriptDoctor . IAndroidToolsInfo {
11
- private static ANDROID_TARGET_PREFIX = "android" ;
12
- private static SUPPORTED_TARGETS = [
13
- "android-17" ,
14
- "android-18" ,
15
- "android-19" ,
16
- "android-21" ,
17
- "android-22" ,
18
- "android-23" ,
19
- "android-24" ,
20
- "android-25" ,
21
- "android-26" ,
22
- "android-27" ,
23
- "android-28" ,
24
- ] ;
12
+ public readonly ANDROID_TARGET_PREFIX = "android" ;
13
+ private getSupportedTargets ( projectDir : string ) {
14
+ const runtimeVersion = this . getRuntimeVersion ( { projectDir} ) ;
15
+ let baseTargets = [
16
+ "android-17" ,
17
+ "android-18" ,
18
+ "android-19" ,
19
+ "android-21" ,
20
+ "android-22" ,
21
+ "android-23" ,
22
+ "android-24" ,
23
+ "android-25" ,
24
+ "android-26" ,
25
+ "android-27" ,
26
+ "android-28" ,
27
+ "android-29"
28
+ ] ;
29
+
30
+ if ( runtimeVersion && semver . lt ( semver . coerce ( runtimeVersion ) , "6.1.0" ) ) {
31
+ baseTargets . sort ( ) ;
32
+ const indexOfSdk29 = baseTargets . indexOf ( "android-29" ) ;
33
+ baseTargets = baseTargets . slice ( 0 , indexOfSdk29 ) ;
34
+ }
35
+
36
+ return baseTargets ;
37
+ }
25
38
private static MIN_REQUIRED_COMPILE_TARGET = 28 ;
26
39
private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=23" ;
27
40
private static VERSION_REGEX = / ( ( \d + \. ) { 2 } \d + ) / ;
28
41
private static MIN_JAVA_VERSION = "1.8.0" ;
29
42
30
43
private toolsInfo : NativeScriptDoctor . IAndroidToolsInfoData ;
31
- private androidHome = process . env [ "ANDROID_HOME" ] ;
44
+ public get androidHome ( ) : string {
45
+ return process . env [ "ANDROID_HOME" ] ;
46
+ }
32
47
private pathToEmulatorExecutable : string ;
33
48
34
49
constructor ( private childProcess : ChildProcess ,
35
50
private fs : FileSystem ,
36
51
private hostInfo : HostInfo ,
37
52
private helpers : Helpers ) { }
38
53
39
- public getToolsInfo ( ) : NativeScriptDoctor . IAndroidToolsInfoData {
54
+ public getToolsInfo ( config : Partial < NativeScriptDoctor . IProjectDir > = { } ) : NativeScriptDoctor . IAndroidToolsInfoData {
40
55
if ( ! this . toolsInfo ) {
41
56
const infoData : NativeScriptDoctor . IAndroidToolsInfoData = Object . create ( null ) ;
42
57
infoData . androidHomeEnvVar = this . androidHome ;
43
- infoData . compileSdkVersion = this . getCompileSdk ( ) ;
44
- infoData . buildToolsVersion = this . getBuildToolsVersion ( ) ;
58
+ infoData . installedTargets = this . getInstalledTargets ( ) ;
59
+ infoData . compileSdkVersion = this . getCompileSdk ( infoData . installedTargets , config . projectDir ) ;
60
+ infoData . buildToolsVersion = this . getBuildToolsVersion ( config . projectDir ) ;
45
61
46
62
this . toolsInfo = infoData ;
47
63
}
48
64
49
65
return this . toolsInfo ;
50
66
}
51
67
52
- public validateInfo ( ) : NativeScriptDoctor . IWarning [ ] {
68
+ public validateInfo ( config : Partial < NativeScriptDoctor . IProjectDir > = { } ) : NativeScriptDoctor . IWarning [ ] {
53
69
const errors : NativeScriptDoctor . IWarning [ ] = [ ] ;
54
- const toolsInfoData = this . getToolsInfo ( ) ;
70
+ const toolsInfoData = this . getToolsInfo ( config ) ;
55
71
const isAndroidHomeValid = this . isAndroidHomeValid ( ) ;
56
72
if ( ! toolsInfoData . compileSdkVersion ) {
57
73
errors . push ( {
@@ -62,7 +78,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
62
78
}
63
79
64
80
if ( ! toolsInfoData . buildToolsVersion ) {
65
- const buildToolsRange = this . getBuildToolsRange ( ) ;
81
+ const buildToolsRange = this . getBuildToolsRange ( config . projectDir ) ;
66
82
const versionRangeMatches = buildToolsRange . match ( / ^ .* ?( [ \d \. ] + ) \s + .* ?( [ \d \. ] + ) $ / ) ;
67
83
let message = `You can install any version in the following range: '${ buildToolsRange } '.` ;
68
84
@@ -105,7 +121,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
105
121
if ( semver . lt ( installedJavaCompilerSemverVersion , AndroidToolsInfo . MIN_JAVA_VERSION ) ) {
106
122
warning = `Javac version ${ installedJavaCompilerVersion } is not supported. You have to install at least ${ AndroidToolsInfo . MIN_JAVA_VERSION } .` ;
107
123
} else {
108
- runtimeVersion = this . getRealRuntimeVersion ( runtimeVersion || this . getAndroidRuntimeVersionFromProjectDir ( projectDir ) ) ;
124
+ runtimeVersion = this . getRuntimeVersion ( { runtimeVersion, projectDir} ) ;
109
125
if ( runtimeVersion ) {
110
126
// get the item from the dictionary that corresponds to our current Javac version:
111
127
let runtimeMinVersion : string = null ;
@@ -145,7 +161,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
145
161
146
162
public async getPathToAdbFromAndroidHome ( ) : Promise < string > {
147
163
if ( this . androidHome ) {
148
- let pathToAdb = path . join ( this . androidHome , "platform-tools" , "adb" ) ;
164
+ const pathToAdb = path . join ( this . androidHome , "platform-tools" , "adb" ) ;
149
165
try {
150
166
await this . childProcess . execFile ( pathToAdb , [ "help" ] ) ;
151
167
return pathToAdb ;
@@ -179,6 +195,44 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
179
195
return errors ;
180
196
}
181
197
198
+ public validateMinSupportedTargetSdk ( { targetSdk, projectDir} : NativeScriptDoctor . ITargetValidationOptions ) : NativeScriptDoctor . IWarning [ ] {
199
+ const errors : NativeScriptDoctor . IWarning [ ] = [ ] ;
200
+ const newTarget = `${ this . ANDROID_TARGET_PREFIX } -${ targetSdk } ` ;
201
+ const supportedTargets = this . getSupportedTargets ( projectDir ) ;
202
+ const targetSupported = _ . includes ( supportedTargets , newTarget ) ;
203
+
204
+ if ( ! _ . includes ( supportedTargets , newTarget ) ) {
205
+ const supportedVersions = supportedTargets . sort ( ) ;
206
+ const minSupportedVersion = this . parseAndroidSdkString ( _ . first ( supportedVersions ) ) ;
207
+
208
+ if ( ! targetSupported && targetSdk && ( targetSdk < minSupportedVersion ) ) {
209
+ errors . push ( {
210
+ warning :`The selected Android target SDK ${ newTarget } is not supported. You must target ${ minSupportedVersion } or later.` ,
211
+ additionalInformation : "" ,
212
+ platforms : [ Constants . ANDROID_PLATFORM_NAME ]
213
+ } ) ;
214
+ }
215
+ }
216
+
217
+ return errors ;
218
+ }
219
+
220
+ public validataMaxSupportedTargetSdk ( { targetSdk, projectDir} : NativeScriptDoctor . ITargetValidationOptions ) : NativeScriptDoctor . IWarning [ ] {
221
+ const errors : NativeScriptDoctor . IWarning [ ] = [ ] ;
222
+ const newTarget = `${ this . ANDROID_TARGET_PREFIX } -${ targetSdk } ` ;
223
+ const targetSupported = _ . includes ( this . getSupportedTargets ( projectDir ) , newTarget ) ;
224
+
225
+ if ( ! targetSupported && ! targetSdk || targetSdk > this . getMaxSupportedVersion ( projectDir ) ) {
226
+ errors . push ( {
227
+ warning :`Support for the selected Android target SDK ${ newTarget } is not verified. Your Android app might not work as expected.` ,
228
+ additionalInformation : "" ,
229
+ platforms : [ Constants . ANDROID_PLATFORM_NAME ]
230
+ } ) ;
231
+ }
232
+
233
+ return errors ;
234
+ }
235
+
182
236
public getPathToEmulatorExecutable ( ) : string {
183
237
if ( ! this . pathToEmulatorExecutable ) {
184
238
const emulatorExecutableName = "emulator" ;
@@ -222,10 +276,10 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
222
276
return sdkManagementToolPath ;
223
277
}
224
278
225
- private getCompileSdk ( ) : number {
226
- let latestValidAndroidTarget = this . getLatestValidAndroidTarget ( ) ;
279
+ private getCompileSdk ( installedTargets : string [ ] , projectDir : string ) : number {
280
+ const latestValidAndroidTarget = this . getLatestValidAndroidTarget ( installedTargets , projectDir ) ;
227
281
if ( latestValidAndroidTarget ) {
228
- let integerVersion = this . parseAndroidSdkString ( latestValidAndroidTarget ) ;
282
+ const integerVersion = this . parseAndroidSdkString ( latestValidAndroidTarget ) ;
229
283
230
284
if ( integerVersion && integerVersion >= AndroidToolsInfo . MIN_REQUIRED_COMPILE_TARGET ) {
231
285
return integerVersion ;
@@ -236,11 +290,11 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
236
290
private getMatchingDir ( pathToDir : string , versionRange : string ) : string {
237
291
let selectedVersion : string ;
238
292
if ( this . fs . exists ( pathToDir ) ) {
239
- let subDirs = this . fs . readDirectory ( pathToDir ) ;
293
+ const subDirs = this . fs . readDirectory ( pathToDir ) ;
240
294
241
- let subDirsVersions = subDirs
295
+ const subDirsVersions = subDirs
242
296
. map ( dirName => {
243
- let dirNameGroups = dirName . match ( AndroidToolsInfo . VERSION_REGEX ) ;
297
+ const dirNameGroups = dirName . match ( AndroidToolsInfo . VERSION_REGEX ) ;
244
298
if ( dirNameGroups ) {
245
299
return dirNameGroups [ 1 ] ;
246
300
}
@@ -249,7 +303,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
249
303
} )
250
304
. filter ( dirName => ! ! dirName ) ;
251
305
252
- let version = semver . maxSatisfying ( subDirsVersions , versionRange ) ;
306
+ const version = semver . maxSatisfying ( subDirsVersions , versionRange ) ;
253
307
if ( version ) {
254
308
selectedVersion = subDirs . find ( dir => dir . indexOf ( version ) !== - 1 ) ;
255
309
}
@@ -258,37 +312,27 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
258
312
return selectedVersion ;
259
313
}
260
314
261
- private getBuildToolsRange ( ) : string {
262
- return `${ AndroidToolsInfo . REQUIRED_BUILD_TOOLS_RANGE_PREFIX } <=${ this . getMaxSupportedVersion ( ) } ` ;
315
+ private getBuildToolsRange ( projectDir : string ) : string {
316
+ return `${ AndroidToolsInfo . REQUIRED_BUILD_TOOLS_RANGE_PREFIX } <=${ this . getMaxSupportedVersion ( projectDir ) } ` ;
263
317
}
264
318
265
- private getBuildToolsVersion ( ) : string {
319
+ private getBuildToolsVersion ( projectDir : string ) : string {
266
320
let buildToolsVersion : string ;
267
321
if ( this . androidHome ) {
268
- let pathToBuildTools = path . join ( this . androidHome , "build-tools" ) ;
269
- let buildToolsRange = this . getBuildToolsRange ( ) ;
322
+ const pathToBuildTools = path . join ( this . androidHome , "build-tools" ) ;
323
+ const buildToolsRange = this . getBuildToolsRange ( projectDir ) ;
270
324
buildToolsVersion = this . getMatchingDir ( pathToBuildTools , buildToolsRange ) ;
271
325
}
272
326
273
327
return buildToolsVersion ;
274
328
}
275
329
276
- private getLatestValidAndroidTarget ( ) : string {
277
- const installedTargets = this . getInstalledTargets ( ) ;
278
- let latestValidAndroidTarget : string ;
279
- const sortedAndroidToolsInfo = AndroidToolsInfo . SUPPORTED_TARGETS . sort ( ) ;
280
-
281
- sortedAndroidToolsInfo . forEach ( s => {
282
- if ( installedTargets . indexOf ( s ) >= 0 ) {
283
- latestValidAndroidTarget = s ;
284
- }
285
- } ) ;
286
-
287
- return latestValidAndroidTarget ;
330
+ private getLatestValidAndroidTarget ( installedTargets : string [ ] , projectDir : string ) : string {
331
+ return _ . findLast ( this . getSupportedTargets ( projectDir ) . sort ( ) , supportedTarget => _ . includes ( installedTargets , supportedTarget ) ) ;
288
332
}
289
333
290
334
private parseAndroidSdkString ( androidSdkString : string ) : number {
291
- return parseInt ( androidSdkString . replace ( `${ AndroidToolsInfo . ANDROID_TARGET_PREFIX } -` , "" ) ) ;
335
+ return parseInt ( androidSdkString . replace ( `${ this . ANDROID_TARGET_PREFIX } -` , "" ) ) ;
292
336
}
293
337
294
338
private getInstalledTargets ( ) : string [ ] {
@@ -304,8 +348,9 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
304
348
}
305
349
}
306
350
307
- private getMaxSupportedVersion ( ) : number {
308
- return this . parseAndroidSdkString ( AndroidToolsInfo . SUPPORTED_TARGETS . sort ( ) [ AndroidToolsInfo . SUPPORTED_TARGETS . length - 1 ] ) ;
351
+ private getMaxSupportedVersion ( projectDir : string ) : number {
352
+ const supportedTargets = this . getSupportedTargets ( projectDir ) ;
353
+ return this . parseAndroidSdkString ( supportedTargets . sort ( ) [ supportedTargets . length - 1 ] ) ;
309
354
}
310
355
311
356
private getSystemRequirementsLink ( ) : string {
@@ -331,7 +376,8 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
331
376
return runtimeVersion ;
332
377
}
333
378
334
- private getRealRuntimeVersion ( runtimeVersion : string ) : string {
379
+ private getRuntimeVersion ( { runtimeVersion, projectDir } : { runtimeVersion ?: string , projectDir ?: string } ) : string {
380
+ runtimeVersion = runtimeVersion || this . getAndroidRuntimeVersionFromProjectDir ( projectDir ) ;
335
381
if ( runtimeVersion ) {
336
382
// Check if the version is not "next" or "rc", i.e. tag from npm
337
383
if ( ! semver . valid ( runtimeVersion ) ) {
0 commit comments