Commit a0f0c42f authored by Jakob Andersen's avatar Jakob Andersen Committed by GitHub

Update gradle example to support x86 in debug mode. (#7606)

* Update gradle example to support x86 in debug mode.

Changed the Flutter Gradle plugin a bit to better fit in with the
Android build.

Fixes #6136
Fixes #6864
Fixes #7539
parent 4cace66d
...@@ -2,8 +2,8 @@ apply plugin: 'com.android.application' ...@@ -2,8 +2,8 @@ apply plugin: 'com.android.application'
apply plugin: 'flutter' apply plugin: 'flutter'
android { android {
compileSdkVersion 22 compileSdkVersion 25
buildToolsVersion '22.0.1' buildToolsVersion '24.0.2'
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
...@@ -12,6 +12,14 @@ android { ...@@ -12,6 +12,14 @@ android {
defaultConfig { defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
} }
flutter { flutter {
...@@ -19,7 +27,7 @@ flutter { ...@@ -19,7 +27,7 @@ flutter {
} }
dependencies { dependencies {
androidTestCompile 'com.android.support:support-annotations:22.0.0' androidTestCompile 'com.android.support:support-annotations:25.0.0'
androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5' androidTestCompile 'com.android.support.test:rules:0.5'
} }
implementation-class=org.domokit.sky.gradle.FlutterPlugin implementation-class=io.flutter.gradle.FlutterPlugin
...@@ -274,6 +274,11 @@ class AndroidDevice extends Device { ...@@ -274,6 +274,11 @@ class AndroidDevice extends Device {
if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion()) if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
return new LaunchResult.failed(); return new LaunchResult.failed();
if (platform != TargetPlatform.android_arm && mode != BuildMode.debug) {
printError('Profile and release builds are only supported on ARM targets.');
return new LaunchResult.failed();
}
printTrace("Stopping app '${package.name}' on $name."); printTrace("Stopping app '${package.name}' on $name.");
await stopApp(package); await stopApp(package);
......
...@@ -18,12 +18,44 @@ import '../globals.dart'; ...@@ -18,12 +18,44 @@ import '../globals.dart';
import 'android_sdk.dart'; import 'android_sdk.dart';
const String gradleManifestPath = 'android/app/src/main/AndroidManifest.xml'; const String gradleManifestPath = 'android/app/src/main/AndroidManifest.xml';
const String gradleAppOut = 'android/app/build/outputs/apk/app-debug.apk'; const String gradleAppOutV1 = 'android/app/build/outputs/apk/app-debug.apk';
const String gradleAppOutV2 = 'android/app/build/outputs/apk/app.apk';
const String gradleAppOutDir = 'android/app/build/outputs/apk';
enum FlutterPluginVersion {
none,
v1,
v2,
}
bool isProjectUsingGradle() { bool isProjectUsingGradle() {
return fs.isFileSync('android/build.gradle'); return fs.isFileSync('android/build.gradle');
} }
FlutterPluginVersion get flutterPluginVersion {
File plugin = fs.file('android/buildSrc/src/main/groovy/FlutterPlugin.groovy');
if (!plugin.existsSync()) {
return FlutterPluginVersion.none;
}
String packageLine = plugin.readAsLinesSync().skip(4).first;
if (packageLine == "package io.flutter.gradle") {
return FlutterPluginVersion.v2;
}
return FlutterPluginVersion.v1;
}
String get gradleAppOut {
switch (flutterPluginVersion) {
case FlutterPluginVersion.none:
// Fall through. Pretend we're v1, and just go with it.
case FlutterPluginVersion.v1:
return gradleAppOutV1;
case FlutterPluginVersion.v2:
return gradleAppOutV2;
}
return null;
}
String locateSystemGradle({ bool ensureExecutable: true }) { String locateSystemGradle({ bool ensureExecutable: true }) {
String gradle = _locateSystemGradle(); String gradle = _locateSystemGradle();
if (ensureExecutable && gradle != null) { if (ensureExecutable && gradle != null) {
...@@ -91,29 +123,14 @@ String locateProjectGradlew({ bool ensureExecutable: true }) { ...@@ -91,29 +123,14 @@ String locateProjectGradlew({ bool ensureExecutable: true }) {
} }
} }
Future<Null> buildGradleProject(BuildMode buildMode) async { Future<String> ensureGradlew() async {
// Create android/local.properties.
File localProperties = fs.file('android/local.properties');
if (!localProperties.existsSync()) {
localProperties.writeAsStringSync(
'sdk.dir=${androidSdk.directory}\n'
'flutter.sdk=${Cache.flutterRoot}\n'
);
}
// Update the local.settings file with the build mode.
// TODO(devoncarew): It would be nicer if we could pass this information in via a cli flag.
SettingsFile settings = new SettingsFile.parseFromFile(localProperties);
settings.values['flutter.buildMode'] = getModeName(buildMode);
settings.writeContents(localProperties);
String gradlew = locateProjectGradlew(); String gradlew = locateProjectGradlew();
if (gradlew == null) { if (gradlew == null) {
String gradle = locateSystemGradle(); String gradle = locateSystemGradle();
if (gradle == null) { if (gradle == null) {
throwToolExit( throwToolExit(
'Unable to locate gradle. Please configure the path to gradle using \'flutter config --gradle-dir\'.' 'Unable to locate gradle. Please configure the path to gradle using \'flutter config --gradle-dir\'.'
); );
} else { } else {
printTrace('Using gradle from $gradle.'); printTrace('Using gradle from $gradle.');
...@@ -130,12 +147,15 @@ Future<Null> buildGradleProject(BuildMode buildMode) async { ...@@ -130,12 +147,15 @@ Future<Null> buildGradleProject(BuildMode buildMode) async {
} }
// Run 'gradle wrapper'. // Run 'gradle wrapper'.
List<String> command = logger.isVerbose
? <String>[gradle, 'wrapper']
: <String>[gradle, '-q', 'wrapper'];
try { try {
Status status = logger.startProgress('Running \'gradle wrapper\'...'); Status status = logger.startProgress('Running \'gradle wrapper\'...');
int exitcode = await runCommandAndStreamOutput( int exitcode = await runCommandAndStreamOutput(
<String>[gradle, 'wrapper'], command,
workingDirectory: 'android', workingDirectory: 'android',
allowReentrantFlutter: true allowReentrantFlutter: true
); );
status.stop(); status.stop();
if (exitcode != 0) if (exitcode != 0)
...@@ -149,10 +169,44 @@ Future<Null> buildGradleProject(BuildMode buildMode) async { ...@@ -149,10 +169,44 @@ Future<Null> buildGradleProject(BuildMode buildMode) async {
throwToolExit('Unable to build android/gradlew.'); throwToolExit('Unable to build android/gradlew.');
} }
return gradlew;
}
Future<Null> buildGradleProject(BuildMode buildMode) async {
// Create android/local.properties.
File localProperties = fs.file('android/local.properties');
if (!localProperties.existsSync()) {
localProperties.writeAsStringSync(
'sdk.dir=${androidSdk.directory}\n'
'flutter.sdk=${Cache.flutterRoot}\n'
);
}
// Update the local.properties file with the build mode.
// FlutterPlugin v1 reads local.properties to determine build mode. Plugin v2
// uses the standard Android way to determine what to build, but we still
// update local.properties, in case we want to use it in the future.
String buildModeName = getModeName(buildMode);
SettingsFile settings = new SettingsFile.parseFromFile(localProperties);
settings.values['flutter.buildMode'] = buildModeName;
settings.writeContents(localProperties);
String gradlew = await ensureGradlew();
switch (flutterPluginVersion) {
case FlutterPluginVersion.none:
// Fall through. Pretend it's v1, and just go for it.
case FlutterPluginVersion.v1:
return buildGradleProjectV1(gradlew);
case FlutterPluginVersion.v2:
return buildGradleProjectV2(gradlew, buildModeName);
}
}
Future<Null> buildGradleProjectV1(String gradlew) async {
// Run 'gradlew build'. // Run 'gradlew build'.
Status status = logger.startProgress('Running \'gradlew build\'...'); Status status = logger.startProgress('Running \'gradlew build\'...');
int exitcode = await runCommandAndStreamOutput( int exitcode = await runCommandAndStreamOutput(
<String>[fs.file('android/gradlew').absolute.path, 'build'], <String>[fs.file(gradlew).absolute.path, 'build'],
workingDirectory: 'android', workingDirectory: 'android',
allowReentrantFlutter: true allowReentrantFlutter: true
); );
...@@ -161,8 +215,34 @@ Future<Null> buildGradleProject(BuildMode buildMode) async { ...@@ -161,8 +215,34 @@ Future<Null> buildGradleProject(BuildMode buildMode) async {
if (exitcode != 0) if (exitcode != 0)
throwToolExit('Gradlew failed: $exitcode', exitCode: exitcode); throwToolExit('Gradlew failed: $exitcode', exitCode: exitcode);
File apkFile = fs.file(gradleAppOut); File apkFile = fs.file(gradleAppOutV1);
printStatus('Built $gradleAppOut (${getSizeAsMB(apkFile.lengthSync())}).'); printStatus('Built $gradleAppOutV1 (${getSizeAsMB(apkFile.lengthSync())}).');
}
Future<Null> buildGradleProjectV2(String gradlew, String buildModeName) async {
String assembleTask = "assemble${toTitleCase(buildModeName)}";
// Run 'gradlew assemble<BuildMode>'.
Status status = logger.startProgress('Running \'gradlew $assembleTask\'...');
String gradlewPath = fs.file(gradlew).absolute.path;
List<String> command = logger.isVerbose
? <String>[gradlewPath, assembleTask]
: <String>[gradlewPath, '-q', assembleTask];
int exitcode = await runCommandAndStreamOutput(
command,
workingDirectory: 'android',
allowReentrantFlutter: true
);
status.stop();
if (exitcode != 0)
throwToolExit('Gradlew failed: $exitcode', exitCode: exitcode);
String apkFilename = 'app-$buildModeName.apk';
File apkFile = fs.file('$gradleAppOutDir/$apkFilename');
// Copy the APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
apkFile.copySync('$gradleAppOutDir/app.apk');
printStatus('Built $apkFilename (${getSizeAsMB(apkFile.lengthSync())}).');
} }
class _GradleFile { class _GradleFile {
......
...@@ -227,21 +227,20 @@ class BuildApkCommand extends BuildSubCommand { ...@@ -227,21 +227,20 @@ class BuildApkCommand extends BuildSubCommand {
await super.runCommand(); await super.runCommand();
TargetPlatform targetPlatform = _getTargetPlatform(argResults['target-arch']); TargetPlatform targetPlatform = _getTargetPlatform(argResults['target-arch']);
if (targetPlatform != TargetPlatform.android_arm && getBuildMode() != BuildMode.debug) BuildMode buildMode = getBuildMode();
if (targetPlatform != TargetPlatform.android_arm && buildMode != BuildMode.debug)
throwToolExit('Profile and release builds are only supported on ARM targets.'); throwToolExit('Profile and release builds are only supported on ARM targets.');
if (isProjectUsingGradle()) { if (isProjectUsingGradle()) {
if (targetPlatform != TargetPlatform.android_arm)
throwToolExit('Gradle builds only support ARM targets.');
await buildAndroidWithGradle( await buildAndroidWithGradle(
TargetPlatform.android_arm, targetPlatform,
getBuildMode(), buildMode,
target: targetFile target: targetFile
); );
} else { } else {
await buildAndroid( await buildAndroid(
targetPlatform, targetPlatform,
getBuildMode(), buildMode,
force: true, force: true,
manifest: argResults['manifest'], manifest: argResults['manifest'],
resources: argResults['resources'], resources: argResults['resources'],
...@@ -595,6 +594,9 @@ Future<Null> buildAndroidWithGradle( ...@@ -595,6 +594,9 @@ Future<Null> buildAndroidWithGradle(
bool force: false, bool force: false,
String target String target
}) async { }) async {
if (platform != TargetPlatform.android_arm && buildMode != BuildMode.debug) {
throwToolExit('Profile and release builds are only supported on ARM targets.');
}
// Validate that we can find an android sdk. // Validate that we can find an android sdk.
if (androidSdk == null) if (androidSdk == null)
throwToolExit('No Android SDK found. Try setting the ANDROID_HOME environment variable.'); throwToolExit('No Android SDK found. Try setting the ANDROID_HOME environment variable.');
......
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