Unverified Commit f0e88198 authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Extract Android SDK version from named platform dirs. (#13056)

Previously, we were mapping certain named platforms
(e.g. `android-stable`) to their corresponding version.
this had two problems:

1. The version could become out of date. For instance, we had
   mapped `android-stable` to version 24, but the stable version
   is now 27.
2. The list of possible named versions wasn't comprehensive.
   Some Android SDKs just list the platform as `stable`, or
   `experimental`, etc.

This change updates the platform version detection to use
the `build.prop` file that exists in the platform directory
(only for cases where the version number is not encoded into
the directory name).
parent f6e6144d
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:convert';
import 'package:meta/meta.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
...@@ -29,11 +33,8 @@ const String kAndroidHome = 'ANDROID_HOME'; ...@@ -29,11 +33,8 @@ const String kAndroidHome = 'ANDROID_HOME';
// $ANDROID_HOME/platforms/android-23/android.jar // $ANDROID_HOME/platforms/android-23/android.jar
// $ANDROID_HOME/platforms/android-N/android.jar // $ANDROID_HOME/platforms/android-N/android.jar
// Special case some version names in the sdk. final RegExp _numberedAndroidPlatformRe = new RegExp(r'^android-([0-9]+)$');
const Map<String, int> _namedVersionMap = const <String, int> { final RegExp _sdkVersionRe = new RegExp(r'^ro.build.version.sdk=([0-9]+)$');
'android-N': 24,
'android-stable': 24,
};
/// The minimum Android SDK version we support. /// The minimum Android SDK version we support.
const int minimumAndroidSdkVersion = 25; const int minimumAndroidSdkVersion = 25;
...@@ -142,15 +143,17 @@ class AndroidSdk { ...@@ -142,15 +143,17 @@ class AndroidSdk {
} }
void _init() { void _init() {
List<String> platforms = <String>[]; // android-22, ... Iterable<Directory> platforms = <Directory>[]; // android-22, ...
final Directory platformsDir = fs.directory(fs.path.join(directory, 'platforms')); final Directory platformsDir = fs.directory(fs.path.join(directory, 'platforms'));
if (platformsDir.existsSync()) { if (platformsDir.existsSync()) {
platforms = platformsDir platforms = platformsDir
.listSync() .listSync()
.map<String>((FileSystemEntity entity) => fs.path.basename(entity.path)) .where((FileSystemEntity entity) => entity is Directory)
.where((String name) => name.startsWith('android-')) .map<Directory>((FileSystemEntity entity) {
.toList(); final Directory dir = entity;
return dir;
});
} }
List<Version> buildTools = <Version>[]; // 19.1.0, 22.0.1, ... List<Version> buildTools = <Version>[]; // 19.1.0, 22.0.1, ...
...@@ -161,7 +164,7 @@ class AndroidSdk { ...@@ -161,7 +164,7 @@ class AndroidSdk {
.listSync() .listSync()
.map((FileSystemEntity entity) { .map((FileSystemEntity entity) {
try { try {
return new Version.parse(fs.path.basename(entity.path)); return new Version.parse(entity.basename);
} catch (error) { } catch (error) {
return null; return null;
} }
...@@ -171,14 +174,23 @@ class AndroidSdk { ...@@ -171,14 +174,23 @@ class AndroidSdk {
} }
// Match up platforms with the best corresponding build-tools. // Match up platforms with the best corresponding build-tools.
_sdkVersions = platforms.map((String platformName) { _sdkVersions = platforms.map((Directory platformDir) {
final String platformName = platformDir.basename;
int platformVersion; int platformVersion;
try { try {
if (_namedVersionMap.containsKey(platformName)) final Match numberedVersion = _numberedAndroidPlatformRe.firstMatch(platformName);
platformVersion = _namedVersionMap[platformName]; if (numberedVersion != null) {
else platformVersion = int.parse(numberedVersion.group(1));
platformVersion = int.parse(platformName.substring('android-'.length)); } else {
final String buildProps = platformDir.childFile('build.prop').readAsStringSync();
final String versionString = const LineSplitter()
.convert(buildProps)
.map(_sdkVersionRe.firstMatch)
.firstWhere((Match match) => match != null)
.group(1);
platformVersion = int.parse(versionString);
}
} catch (error) { } catch (error) {
return null; return null;
} }
...@@ -192,10 +204,11 @@ class AndroidSdk { ...@@ -192,10 +204,11 @@ class AndroidSdk {
if (buildToolsVersion == null) if (buildToolsVersion == null)
return null; return null;
return new AndroidSdkVersion( return new AndroidSdkVersion._(
this, this,
platformVersionName: platformName, sdkLevel: platformVersion,
buildToolsVersion: buildToolsVersion platformName: platformName,
buildToolsVersion: buildToolsVersion,
); );
}).where((AndroidSdkVersion version) => version != null).toList(); }).where((AndroidSdkVersion version) => version != null).toList();
...@@ -209,22 +222,20 @@ class AndroidSdk { ...@@ -209,22 +222,20 @@ class AndroidSdk {
} }
class AndroidSdkVersion implements Comparable<AndroidSdkVersion> { class AndroidSdkVersion implements Comparable<AndroidSdkVersion> {
AndroidSdkVersion(this.sdk, { AndroidSdkVersion._(this.sdk, {
this.platformVersionName, @required this.sdkLevel,
this.buildToolsVersion, @required this.platformName,
}); @required this.buildToolsVersion,
}) : assert(sdkLevel != null),
assert(platformName != null),
assert(buildToolsVersion != null);
final AndroidSdk sdk; final AndroidSdk sdk;
final String platformVersionName; final int sdkLevel;
final String platformName;
final Version buildToolsVersion; final Version buildToolsVersion;
String get buildToolsVersionName => buildToolsVersion.toString();
int get sdkLevel { String get buildToolsVersionName => buildToolsVersion.toString();
if (_namedVersionMap.containsKey(platformVersionName))
return _namedVersionMap[platformVersionName];
else
return int.parse(platformVersionName.substring('android-'.length));
}
String get androidJarPath => getPlatformsPath('android.jar'); String get androidJarPath => getPlatformsPath('android.jar');
...@@ -241,7 +252,7 @@ class AndroidSdkVersion implements Comparable<AndroidSdkVersion> { ...@@ -241,7 +252,7 @@ class AndroidSdkVersion implements Comparable<AndroidSdkVersion> {
} }
String getPlatformsPath(String itemName) { String getPlatformsPath(String itemName) {
return fs.path.join(sdk.directory, 'platforms', platformVersionName, itemName); return fs.path.join(sdk.directory, 'platforms', platformName, itemName);
} }
String getBuildToolsPath(String binaryName) { String getBuildToolsPath(String binaryName) {
......
...@@ -124,7 +124,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { ...@@ -124,7 +124,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
sdkVersionText = 'Android SDK ${androidSdk.latestVersion.buildToolsVersionName}'; sdkVersionText = 'Android SDK ${androidSdk.latestVersion.buildToolsVersionName}';
messages.add(new ValidationMessage( messages.add(new ValidationMessage(
'Platform ${androidSdk.latestVersion.platformVersionName}, ' 'Platform ${androidSdk.latestVersion.platformName}, '
'build-tools ${androidSdk.latestVersion.buildToolsVersionName}' 'build-tools ${androidSdk.latestVersion.buildToolsVersionName}'
)); ));
} }
......
...@@ -2,14 +2,20 @@ ...@@ -2,14 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import '../src/context.dart'; import '../src/context.dart';
void main() { void main() {
MemoryFileSystem fs;
setUp(() {
fs = new MemoryFileSystem();
});
group('android_sdk AndroidSdk', () { group('android_sdk AndroidSdk', () {
Directory sdkDir; Directory sdkDir;
...@@ -23,6 +29,8 @@ void main() { ...@@ -23,6 +29,8 @@ void main() {
expect(sdk.latestVersion, isNotNull); expect(sdk.latestVersion, isNotNull);
expect(sdk.latestVersion.sdkLevel, 23); expect(sdk.latestVersion.sdkLevel, 23);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
}); });
testUsingContext('parse sdk N', () { testUsingContext('parse sdk N', () {
...@@ -31,22 +39,8 @@ void main() { ...@@ -31,22 +39,8 @@ void main() {
expect(sdk.latestVersion, isNotNull); expect(sdk.latestVersion, isNotNull);
expect(sdk.latestVersion.sdkLevel, 24); expect(sdk.latestVersion.sdkLevel, 24);
}); }, overrides: <Type, Generator>{
}); FileSystem: () => fs,
group('android_sdk AndroidSdkVersion', () {
testUsingContext('parse normal', () {
final AndroidSdk sdk = new AndroidSdk('.');
final AndroidSdkVersion ver = new AndroidSdkVersion(sdk,
platformVersionName: 'android-23', buildToolsVersion: new Version.parse('23.0.0'));
expect(ver.sdkLevel, 23);
});
testUsingContext('parse android n', () {
final AndroidSdk sdk = new AndroidSdk('.');
final AndroidSdkVersion ver = new AndroidSdkVersion(sdk,
platformVersionName: 'android-N', buildToolsVersion: new Version.parse('24.0.0'));
expect(ver.sdkLevel, 24);
}); });
}); });
} }
...@@ -64,13 +58,24 @@ Directory _createSdkDirectory({ bool withAndroidN: false }) { ...@@ -64,13 +58,24 @@ Directory _createSdkDirectory({ bool withAndroidN: false }) {
_createSdkFile(dir, 'platforms/android-22/android.jar'); _createSdkFile(dir, 'platforms/android-22/android.jar');
_createSdkFile(dir, 'platforms/android-23/android.jar'); _createSdkFile(dir, 'platforms/android-23/android.jar');
if (withAndroidN) if (withAndroidN) {
_createSdkFile(dir, 'platforms/android-N/android.jar'); _createSdkFile(dir, 'platforms/android-N/android.jar');
_createSdkFile(dir, 'platforms/android-N/build.prop', contents: _buildProp);
}
return dir; return dir;
} }
void _createSdkFile(Directory dir, String filePath) { void _createSdkFile(Directory dir, String filePath, { String contents }) {
final File file = fs.file(fs.path.join(dir.path, filePath)); final File file = dir.childFile(filePath);
file.createSync(recursive: true); file.createSync(recursive: true);
if (contents != null) {
file.writeAsStringSync(contents, flush: true);
}
} }
const String _buildProp = r'''
ro.build.version.incremental=1624448
ro.build.version.sdk=24
ro.build.version.codename=REL
''';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment