diff --git a/packages/flutter_tools/lib/src/android/android_sdk.dart b/packages/flutter_tools/lib/src/android/android_sdk.dart index 0e605f47c4..67881352ec 100644 --- a/packages/flutter_tools/lib/src/android/android_sdk.dart +++ b/packages/flutter_tools/lib/src/android/android_sdk.dart @@ -11,16 +11,22 @@ import '../base/os.dart'; import '../globals.dart'; // Android SDK layout: -// + // $ANDROID_HOME/platform-tools/adb + // $ANDROID_HOME/build-tools/19.1.0/aapt, dx, zipalign // $ANDROID_HOME/build-tools/22.0.1/aapt // $ANDROID_HOME/build-tools/23.0.2/aapt +// $ANDROID_HOME/build-tools/24.0.0-preview/aapt + // $ANDROID_HOME/platforms/android-22/android.jar // $ANDROID_HOME/platforms/android-23/android.jar +// $ANDROID_HOME/platforms/android-N/android.jar -// TODO(devoncarew): We need a way to locate the Android SDK w/o using an environment variable. -// Perhaps something like `flutter config --android-home=foo/bar`. +// Special case some version names in the sdk. +const Map _namedVersionMap = const { + 'android-N': 24 +}; /// Locate ADB. Prefer to use one from an Android SDK, if we can locate that. String getAdbPath([AndroidSdk existingSdk]) { @@ -47,8 +53,6 @@ class AndroidSdk { AndroidSdkVersion _latestVersion; static AndroidSdk locateAndroidSdk() { - // TODO: Use explicit configuration information from a metadata file? - String androidHomeDir; if (Platform.environment.containsKey('ANDROID_HOME')) { androidHomeDir = Platform.environment['ANDROID_HOME']; @@ -130,11 +134,11 @@ class AndroidSdk { .toList(); } - List buildToolsVersions = []; // 19.1.0, 22.0.1, ... + List buildTools = []; // 19.1.0, 22.0.1, ... Directory buildToolsDir = new Directory(path.join(directory, 'build-tools')); if (buildToolsDir.existsSync()) { - buildToolsVersions = buildToolsDir + buildTools = buildToolsDir .listSync() .map((FileSystemEntity entity) { try { @@ -149,25 +153,32 @@ class AndroidSdk { // Here we match up platforms with cooresponding build-tools. If we don't // have a match, we don't return anything for that platform version. So if - // the user only have 'android-22' and 'build-tools/19.0.0', we don't find + // the user only has 'android-22' and 'build-tools/19.0.0', we don't find // an Android sdk. - _sdkVersions = platforms.map((String platform) { - int sdkVersion; + _sdkVersions = platforms.map((String platformName) { + int platformVersion; try { - sdkVersion = int.parse(platform.substring('android-'.length)); + if (_namedVersionMap.containsKey(platformName)) + platformVersion = _namedVersionMap[platformName]; + else + platformVersion = int.parse(platformName.substring('android-'.length)); } catch (error) { return null; } - Version buildToolsVersion = Version.primary(buildToolsVersions.where((Version version) { - return version.major == sdkVersion; + Version buildToolsVersion = Version.primary(buildTools.where((Version version) { + return version.major == platformVersion; }).toList()); if (buildToolsVersion == null) return null; - return new AndroidSdkVersion(this, platform, buildToolsVersion.toString()); + return new AndroidSdkVersion( + this, + platformVersionName: platformName, + buildToolsVersionName: buildToolsVersion.toString() + ); }).where((AndroidSdkVersion version) => version != null).toList(); _sdkVersions.sort(); @@ -180,13 +191,21 @@ class AndroidSdk { } class AndroidSdkVersion implements Comparable { - AndroidSdkVersion(this.sdk, this.androidVersion, this.buildToolsVersion); + AndroidSdkVersion(this.sdk, { + this.platformVersionName, + this.buildToolsVersionName + }); final AndroidSdk sdk; - final String androidVersion; - final String buildToolsVersion; + final String platformVersionName; + final String buildToolsVersionName; - int get sdkLevel => int.parse(androidVersion.substring('android-'.length)); + int get sdkLevel { + if (_namedVersionMap.containsKey(platformVersionName)) + return _namedVersionMap[platformVersionName]; + else + return int.parse(platformVersionName.substring('android-'.length)); + } String get androidJarPath => getPlatformsPath('android.jar'); @@ -205,20 +224,18 @@ class AndroidSdkVersion implements Comparable { } String getPlatformsPath(String itemName) { - return path.join(sdk.directory, 'platforms', androidVersion, itemName); + return path.join(sdk.directory, 'platforms', platformVersionName, itemName); } String getBuildToolsPath(String binaryName) { - return path.join(sdk.directory, 'build-tools', buildToolsVersion, binaryName); + return path.join(sdk.directory, 'build-tools', buildToolsVersionName, binaryName); } @override - int compareTo(AndroidSdkVersion other) { - return sdkLevel - other.sdkLevel; - } + int compareTo(AndroidSdkVersion other) => sdkLevel - other.sdkLevel; @override - String toString() => '[${sdk.directory}, SDK version $sdkLevel, build-tools $buildToolsVersion]'; + String toString() => '[${sdk.directory}, SDK version $sdkLevel, build-tools $buildToolsVersionName]'; bool _exists(String path, { bool complain: false }) { if (!FileSystemEntity.isFileSync(path)) { diff --git a/packages/flutter_tools/test/android_sdk_test.dart b/packages/flutter_tools/test/android_sdk_test.dart new file mode 100644 index 0000000000..805731885a --- /dev/null +++ b/packages/flutter_tools/test/android_sdk_test.dart @@ -0,0 +1,77 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:flutter_tools/src/android/android_sdk.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; + +import 'src/context.dart'; + +void main() { + group('android_sdk AndroidSdk', () { + Directory sdkDir; + + tearDown(() { + sdkDir?.deleteSync(recursive: true); + }); + + testUsingContext('parse sdk', () { + sdkDir = _createSdkDirectory(); + AndroidSdk sdk = new AndroidSdk(sdkDir.path); + + expect(sdk.latestVersion, isNotNull); + expect(sdk.latestVersion.sdkLevel, 23); + }); + + testUsingContext('parse sdk N', () { + sdkDir = _createSdkDirectory(withAndroidN: true); + AndroidSdk sdk = new AndroidSdk(sdkDir.path); + + expect(sdk.latestVersion, isNotNull); + expect(sdk.latestVersion.sdkLevel, 24); + }); + }); + + group('android_sdk AndroidSdkVersion', () { + testUsingContext('parse normal', () { + AndroidSdk sdk = new AndroidSdk('.'); + AndroidSdkVersion ver = new AndroidSdkVersion(sdk, + platformVersionName: 'android-23', buildToolsVersionName: '23.0.0'); + expect(ver.sdkLevel, 23); + }); + + testUsingContext('parse android n', () { + AndroidSdk sdk = new AndroidSdk('.'); + AndroidSdkVersion ver = new AndroidSdkVersion(sdk, + platformVersionName: 'android-N', buildToolsVersionName: '24.0.0'); + expect(ver.sdkLevel, 24); + }); + }); +} + +Directory _createSdkDirectory({ bool withAndroidN: false }) { + Directory dir = Directory.systemTemp.createTempSync('android-sdk'); + + _createSdkFile(dir, 'platform-tools/adb'); + + _createSdkFile(dir, 'build-tools/19.1.0/aapt'); + _createSdkFile(dir, 'build-tools/22.0.1/aapt'); + _createSdkFile(dir, 'build-tools/23.0.2/aapt'); + if (withAndroidN) + _createSdkFile(dir, 'build-tools/24.0.0-preview/aapt'); + + _createSdkFile(dir, 'platforms/android-22/android.jar'); + _createSdkFile(dir, 'platforms/android-23/android.jar'); + if (withAndroidN) + _createSdkFile(dir, 'platforms/android-N/android.jar'); + + return dir; +} + +void _createSdkFile(Directory dir, String filePath) { + File file = new File(path.join(dir.path, filePath)); + file.createSync(recursive: true); +}