@@ -6,52 +6,68 @@ import { Helpers } from './helpers';
66import { EOL } from "os" ;
77import * as semver from "semver" ;
88import * as path from "path" ;
9+ import * as _ from "lodash" ;
910
1011export 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+ }
2538 private static MIN_REQUIRED_COMPILE_TARGET = 28 ;
2639 private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=23" ;
2740 private static VERSION_REGEX = / ( ( \d + \. ) { 2 } \d + ) / ;
2841 private static MIN_JAVA_VERSION = "1.8.0" ;
2942
3043 private toolsInfo : NativeScriptDoctor . IAndroidToolsInfoData ;
31- private androidHome = process . env [ "ANDROID_HOME" ] ;
44+ public get androidHome ( ) : string {
45+ return process . env [ "ANDROID_HOME" ] ;
46+ }
3247 private pathToEmulatorExecutable : string ;
3348
3449 constructor ( private childProcess : ChildProcess ,
3550 private fs : FileSystem ,
3651 private hostInfo : HostInfo ,
3752 private helpers : Helpers ) { }
3853
39- public getToolsInfo ( ) : NativeScriptDoctor . IAndroidToolsInfoData {
54+ public getToolsInfo ( config : Partial < NativeScriptDoctor . IProjectDir > = { } ) : NativeScriptDoctor . IAndroidToolsInfoData {
4055 if ( ! this . toolsInfo ) {
4156 const infoData : NativeScriptDoctor . IAndroidToolsInfoData = Object . create ( null ) ;
4257 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 ) ;
4561
4662 this . toolsInfo = infoData ;
4763 }
4864
4965 return this . toolsInfo ;
5066 }
5167
52- public validateInfo ( ) : NativeScriptDoctor . IWarning [ ] {
68+ public validateInfo ( config : Partial < NativeScriptDoctor . IProjectDir > = { } ) : NativeScriptDoctor . IWarning [ ] {
5369 const errors : NativeScriptDoctor . IWarning [ ] = [ ] ;
54- const toolsInfoData = this . getToolsInfo ( ) ;
70+ const toolsInfoData = this . getToolsInfo ( config ) ;
5571 const isAndroidHomeValid = this . isAndroidHomeValid ( ) ;
5672 if ( ! toolsInfoData . compileSdkVersion ) {
5773 errors . push ( {
@@ -62,7 +78,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
6278 }
6379
6480 if ( ! toolsInfoData . buildToolsVersion ) {
65- const buildToolsRange = this . getBuildToolsRange ( ) ;
81+ const buildToolsRange = this . getBuildToolsRange ( config . projectDir ) ;
6682 const versionRangeMatches = buildToolsRange . match ( / ^ .* ?( [ \d \. ] + ) \s + .* ?( [ \d \. ] + ) $ / ) ;
6783 let message = `You can install any version in the following range: '${ buildToolsRange } '.` ;
6884
@@ -105,7 +121,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
105121 if ( semver . lt ( installedJavaCompilerSemverVersion , AndroidToolsInfo . MIN_JAVA_VERSION ) ) {
106122 warning = `Javac version ${ installedJavaCompilerVersion } is not supported. You have to install at least ${ AndroidToolsInfo . MIN_JAVA_VERSION } .` ;
107123 } else {
108- runtimeVersion = this . getRealRuntimeVersion ( runtimeVersion || this . getAndroidRuntimeVersionFromProjectDir ( projectDir ) ) ;
124+ runtimeVersion = this . getRuntimeVersion ( { runtimeVersion, projectDir} ) ;
109125 if ( runtimeVersion ) {
110126 // get the item from the dictionary that corresponds to our current Javac version:
111127 let runtimeMinVersion : string = null ;
@@ -145,7 +161,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
145161
146162 public async getPathToAdbFromAndroidHome ( ) : Promise < string > {
147163 if ( this . androidHome ) {
148- let pathToAdb = path . join ( this . androidHome , "platform-tools" , "adb" ) ;
164+ const pathToAdb = path . join ( this . androidHome , "platform-tools" , "adb" ) ;
149165 try {
150166 await this . childProcess . execFile ( pathToAdb , [ "help" ] ) ;
151167 return pathToAdb ;
@@ -179,6 +195,44 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
179195 return errors ;
180196 }
181197
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+
182236 public getPathToEmulatorExecutable ( ) : string {
183237 if ( ! this . pathToEmulatorExecutable ) {
184238 const emulatorExecutableName = "emulator" ;
@@ -222,10 +276,10 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
222276 return sdkManagementToolPath ;
223277 }
224278
225- private getCompileSdk ( ) : number {
226- let latestValidAndroidTarget = this . getLatestValidAndroidTarget ( ) ;
279+ private getCompileSdk ( installedTargets : string [ ] , projectDir : string ) : number {
280+ const latestValidAndroidTarget = this . getLatestValidAndroidTarget ( installedTargets , projectDir ) ;
227281 if ( latestValidAndroidTarget ) {
228- let integerVersion = this . parseAndroidSdkString ( latestValidAndroidTarget ) ;
282+ const integerVersion = this . parseAndroidSdkString ( latestValidAndroidTarget ) ;
229283
230284 if ( integerVersion && integerVersion >= AndroidToolsInfo . MIN_REQUIRED_COMPILE_TARGET ) {
231285 return integerVersion ;
@@ -236,11 +290,11 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
236290 private getMatchingDir ( pathToDir : string , versionRange : string ) : string {
237291 let selectedVersion : string ;
238292 if ( this . fs . exists ( pathToDir ) ) {
239- let subDirs = this . fs . readDirectory ( pathToDir ) ;
293+ const subDirs = this . fs . readDirectory ( pathToDir ) ;
240294
241- let subDirsVersions = subDirs
295+ const subDirsVersions = subDirs
242296 . map ( dirName => {
243- let dirNameGroups = dirName . match ( AndroidToolsInfo . VERSION_REGEX ) ;
297+ const dirNameGroups = dirName . match ( AndroidToolsInfo . VERSION_REGEX ) ;
244298 if ( dirNameGroups ) {
245299 return dirNameGroups [ 1 ] ;
246300 }
@@ -249,7 +303,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
249303 } )
250304 . filter ( dirName => ! ! dirName ) ;
251305
252- let version = semver . maxSatisfying ( subDirsVersions , versionRange ) ;
306+ const version = semver . maxSatisfying ( subDirsVersions , versionRange ) ;
253307 if ( version ) {
254308 selectedVersion = subDirs . find ( dir => dir . indexOf ( version ) !== - 1 ) ;
255309 }
@@ -258,37 +312,27 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
258312 return selectedVersion ;
259313 }
260314
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 ) } ` ;
263317 }
264318
265- private getBuildToolsVersion ( ) : string {
319+ private getBuildToolsVersion ( projectDir : string ) : string {
266320 let buildToolsVersion : string ;
267321 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 ) ;
270324 buildToolsVersion = this . getMatchingDir ( pathToBuildTools , buildToolsRange ) ;
271325 }
272326
273327 return buildToolsVersion ;
274328 }
275329
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 ) ) ;
288332 }
289333
290334 private parseAndroidSdkString ( androidSdkString : string ) : number {
291- return parseInt ( androidSdkString . replace ( `${ AndroidToolsInfo . ANDROID_TARGET_PREFIX } -` , "" ) ) ;
335+ return parseInt ( androidSdkString . replace ( `${ this . ANDROID_TARGET_PREFIX } -` , "" ) ) ;
292336 }
293337
294338 private getInstalledTargets ( ) : string [ ] {
@@ -304,8 +348,9 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
304348 }
305349 }
306350
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 ] ) ;
309354 }
310355
311356 private getSystemRequirementsLink ( ) : string {
@@ -331,7 +376,8 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo {
331376 return runtimeVersion ;
332377 }
333378
334- private getRealRuntimeVersion ( runtimeVersion : string ) : string {
379+ private getRuntimeVersion ( { runtimeVersion, projectDir } : { runtimeVersion ?: string , projectDir ?: string } ) : string {
380+ runtimeVersion = runtimeVersion || this . getAndroidRuntimeVersionFromProjectDir ( projectDir ) ;
335381 if ( runtimeVersion ) {
336382 // Check if the version is not "next" or "rc", i.e. tag from npm
337383 if ( ! semver . valid ( runtimeVersion ) ) {
0 commit comments