Unverified Commit 30493a35 authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Test Gradle on Windows (#42709)

parent 898e6fe3
...@@ -722,11 +722,6 @@ Map<String, String> _initGradleEnvironment() { ...@@ -722,11 +722,6 @@ Map<String, String> _initGradleEnvironment() {
final Map<String, String> gradleEnvironment = _initGradleEnvironment(); final Map<String, String> gradleEnvironment = _initGradleEnvironment();
Future<void> _runHostOnlyDeviceLabTests() async { Future<void> _runHostOnlyDeviceLabTests() async {
if (Platform.isWindows) {
// TODO(ianh): remove when https://github.com/flutter/flutter/issues/36311 fixed by https://github.com/flutter/flutter/pull/42709
return;
}
// Please don't add more tests here. We should not be using the devicelab // Please don't add more tests here. We should not be using the devicelab
// logic to run tests outside devicelab, that's just confusing. // logic to run tests outside devicelab, that's just confusing.
// Instead, create tests that are not devicelab tests, and run those. // Instead, create tests that are not devicelab tests, and run those.
......
...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
/// Tests that AARs can be built on module projects. /// Tests that AARs can be built on module projects.
Future<void> main() async { Future<void> main() async {
...@@ -182,10 +182,7 @@ Future<void> main() async { ...@@ -182,10 +182,7 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
// JIT snapshots. ...debugAssets,
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], debugAar); ], debugAar);
return TaskResult.success(null); return TaskResult.success(null);
......
...@@ -10,7 +10,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -10,7 +10,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
/// Tests that AARs can be built on plugin projects. /// Tests that AARs can be built on plugin projects.
Future<void> main() async { Future<void> main() async {
......
...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
/// Tests that Jetifier can translate plugins that use support libraries. /// Tests that Jetifier can translate plugins that use support libraries.
Future<void> main() async { Future<void> main() async {
...@@ -56,6 +56,12 @@ Future<void> main() async { ...@@ -56,6 +56,12 @@ Future<void> main() async {
); );
}); });
section('Update proguard rules');
// Don't obfuscate the input class files, since the test is checking if some classes are in the DEX.
final File proguardRules = File(path.join(projectDir.path, 'android', 'app', 'proguard-rules.pro'));
proguardRules.writeAsStringSync('-dontobfuscate', flush: true);
section('Build release APK'); section('Build release APK');
await inDirectory(projectDir, () async { await inDirectory(projectDir, () async {
......
...@@ -10,7 +10,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -10,7 +10,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
/// Tests that [settings_aar.gradle] is created when possible. /// Tests that [settings_aar.gradle] is created when possible.
Future<void> main() async { Future<void> main() async {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter_devicelab/framework/apk_utils.dart'; import 'package:flutter_devicelab/framework/apk_utils.dart';
import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/framework.dart';
...@@ -10,6 +11,11 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -10,6 +11,11 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
Future<void> main() async { Future<void> main() async {
final Iterable<String> baseAabFiles = <String>[
'base/dex/classes.dex',
'base/manifest/AndroidManifest.xml',
];
final Iterable<String> flutterAabAssets = flutterAssets.map((String file) => 'base/$file');
await task(() async { await task(() async {
try { try {
await runProjectTest((FlutterProject project) async { await runProjectTest((FlutterProject project) async {
...@@ -26,8 +32,8 @@ Future<void> main() async { ...@@ -26,8 +32,8 @@ Future<void> main() async {
'app-release.aab', 'app-release.aab',
); );
checkItContains<String>(<String>[ checkItContains<String>(<String>[
'base/manifest/AndroidManifest.xml', ...baseAabFiles,
'base/dex/classes.dex', ...flutterAabAssets,
'base/lib/arm64-v8a/libapp.so', 'base/lib/arm64-v8a/libapp.so',
'base/lib/arm64-v8a/libflutter.so', 'base/lib/arm64-v8a/libflutter.so',
'base/lib/armeabi-v7a/libapp.so', 'base/lib/armeabi-v7a/libapp.so',
...@@ -36,6 +42,10 @@ Future<void> main() async { ...@@ -36,6 +42,10 @@ Future<void> main() async {
}); });
await runProjectTest((FlutterProject project) async { await runProjectTest((FlutterProject project) async {
if (Platform.isWindows) {
// https://github.com/flutter/flutter/issues/42985
return;
}
section('App bundle content using flavors without explicit target platform'); section('App bundle content using flavors without explicit target platform');
// Add a few flavors. // Add a few flavors.
await project.addProductFlavors(<String> [ await project.addProductFlavors(<String> [
...@@ -57,8 +67,8 @@ Future<void> main() async { ...@@ -57,8 +67,8 @@ Future<void> main() async {
'app-production-release.aab', 'app-production-release.aab',
); );
checkItContains<String>(<String>[ checkItContains<String>(<String>[
'base/manifest/AndroidManifest.xml', ...baseAabFiles,
'base/dex/classes.dex', ...flutterAabAssets,
'base/lib/arm64-v8a/libapp.so', 'base/lib/arm64-v8a/libapp.so',
'base/lib/arm64-v8a/libflutter.so', 'base/lib/arm64-v8a/libflutter.so',
'base/lib/armeabi-v7a/libapp.so', 'base/lib/armeabi-v7a/libapp.so',
...@@ -93,8 +103,8 @@ Future<void> main() async { ...@@ -93,8 +103,8 @@ Future<void> main() async {
'app-flavor_underscore-release.aab', 'app-flavor_underscore-release.aab',
); );
checkItContains<String>(<String>[ checkItContains<String>(<String>[
'base/manifest/AndroidManifest.xml', ...baseAabFiles,
'base/dex/classes.dex', ...flutterAabAssets,
'base/lib/arm64-v8a/libapp.so', 'base/lib/arm64-v8a/libapp.so',
'base/lib/arm64-v8a/libflutter.so', 'base/lib/arm64-v8a/libflutter.so',
'base/lib/armeabi-v7a/libapp.so', 'base/lib/armeabi-v7a/libapp.so',
...@@ -128,8 +138,8 @@ Future<void> main() async { ...@@ -128,8 +138,8 @@ Future<void> main() async {
'app-production-release.aab', 'app-production-release.aab',
); );
checkItContains<String>(<String>[ checkItContains<String>(<String>[
'base/manifest/AndroidManifest.xml', ...baseAabFiles,
'base/dex/classes.dex', ...flutterAabAssets,
'base/lib/arm64-v8a/libapp.so', 'base/lib/arm64-v8a/libapp.so',
'base/lib/arm64-v8a/libflutter.so', 'base/lib/arm64-v8a/libflutter.so',
'base/lib/armeabi-v7a/libapp.so', 'base/lib/armeabi-v7a/libapp.so',
...@@ -153,10 +163,9 @@ Future<void> main() async { ...@@ -153,10 +163,9 @@ Future<void> main() async {
); );
final Iterable<String> bundleFiles = await getFilesInAppBundle(releaseBundle); final Iterable<String> bundleFiles = await getFilesInAppBundle(releaseBundle);
checkItContains<String>(<String>[ checkItContains<String>(<String>[
'base/manifest/AndroidManifest.xml', ...baseAabFiles,
'base/dex/classes.dex', ...flutterAabAssets,
'base/lib/armeabi-v7a/libapp.so', 'base/lib/armeabi-v7a/libapp.so',
'base/lib/armeabi-v7a/libflutter.so', 'base/lib/armeabi-v7a/libflutter.so',
], bundleFiles); ], bundleFiles);
......
...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
/// Tests that projects can include plugins that have a transtive dependency in common. /// Tests that projects can include plugins that have a transtive dependency in common.
/// For more info see: https://github.com/flutter/flutter/issues/27254. /// For more info see: https://github.com/flutter/flutter/issues/27254.
......
...@@ -21,12 +21,10 @@ Future<void> main() async { ...@@ -21,12 +21,10 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...debugAssets,
'assets/flutter_assets/isolate_snapshot_data', ...baseApkFiles,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
'lib/arm64-v8a/libflutter.so',
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/arm64-v8a/libflutter.so',
// Debug mode intentionally includes `x86` and `x86_64`. // Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so', 'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so', 'lib/x86_64/libflutter.so',
...@@ -48,18 +46,14 @@ Future<void> main() async { ...@@ -48,18 +46,14 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...baseApkFiles,
'lib/arm64-v8a/libflutter.so',
'lib/arm64-v8a/libapp.so',
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
'lib/arm64-v8a/libflutter.so',
'lib/arm64-v8a/libapp.so',
], apkFiles); ], apkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(debugAssets, apkFiles);
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], apkFiles);
}); });
await runPluginProjectTest((FlutterPluginProject pluginProject) async { await runPluginProjectTest((FlutterPluginProject pluginProject) async {
...@@ -71,18 +65,14 @@ Future<void> main() async { ...@@ -71,18 +65,14 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...baseApkFiles,
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
'lib/arm64-v8a/libflutter.so', 'lib/arm64-v8a/libflutter.so',
'lib/arm64-v8a/libapp.so', 'lib/arm64-v8a/libapp.so',
], apkFiles); ], apkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(debugAssets, apkFiles);
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], apkFiles);
}); });
await runPluginProjectTest((FlutterPluginProject pluginProject) async { await runPluginProjectTest((FlutterPluginProject pluginProject) async {
...@@ -95,31 +85,23 @@ Future<void> main() async { ...@@ -95,31 +85,23 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...baseApkFiles,
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
], armApkFiles); ], armApkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(debugAssets, armApkFiles);
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], armApkFiles);
final Iterable<String> arm64ApkFiles = await getFilesInApk(pluginProject.releaseArm64ApkPath); final Iterable<String> arm64ApkFiles = await getFilesInApk(pluginProject.releaseArm64ApkPath);
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...baseApkFiles,
'lib/arm64-v8a/libflutter.so', 'lib/arm64-v8a/libflutter.so',
'lib/arm64-v8a/libapp.so', 'lib/arm64-v8a/libapp.so',
], arm64ApkFiles); ], arm64ApkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(debugAssets, arm64ApkFiles);
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], arm64ApkFiles);
}); });
await runProjectTest((FlutterProject project) async { await runProjectTest((FlutterProject project) async {
......
...@@ -21,10 +21,8 @@ Future<void> main() async { ...@@ -21,10 +21,8 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...debugAssets,
'assets/flutter_assets/isolate_snapshot_data', ...baseApkFiles,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
// Debug mode intentionally includes `x86` and `x86_64`. // Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so', 'lib/x86/libflutter.so',
...@@ -32,6 +30,7 @@ Future<void> main() async { ...@@ -32,6 +30,7 @@ Future<void> main() async {
], apkFiles); ], apkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(<String>[
'lib/arm64-v8a/libapp.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
'lib/x86/libapp.so', 'lib/x86/libapp.so',
'lib/x86_64/libapp.so', 'lib/x86_64/libapp.so',
...@@ -48,10 +47,8 @@ Future<void> main() async { ...@@ -48,10 +47,8 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...debugAssets,
'assets/flutter_assets/isolate_snapshot_data', ...baseApkFiles,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
// Debug mode intentionally includes `x86` and `x86_64`. // Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so', 'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so', 'lib/x86_64/libflutter.so',
...@@ -74,10 +71,8 @@ Future<void> main() async { ...@@ -74,10 +71,8 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...debugAssets,
'assets/flutter_assets/isolate_snapshot_data', ...baseApkFiles,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
// Debug mode intentionally includes `x86` and `x86_64`. // Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so', 'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so', 'lib/x86_64/libflutter.so',
...@@ -99,17 +94,15 @@ Future<void> main() async { ...@@ -99,17 +94,15 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...baseApkFiles,
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
], apkFiles); ], apkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(<String>[
...debugAssets,
'lib/arm64-v8a/libflutter.so', 'lib/arm64-v8a/libflutter.so',
'lib/arm64-v8a/libapp.so', 'lib/arm64-v8a/libapp.so',
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], apkFiles); ], apkFiles);
}); });
...@@ -122,17 +115,15 @@ Future<void> main() async { ...@@ -122,17 +115,15 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'classes.dex', ...baseApkFiles,
'lib/arm64-v8a/libflutter.so', 'lib/arm64-v8a/libflutter.so',
'lib/arm64-v8a/libapp.so', 'lib/arm64-v8a/libapp.so',
], apkFiles); ], apkFiles);
checkItDoesNotContain<String>(<String>[ checkItDoesNotContain<String>(<String>[
...debugAssets,
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], apkFiles); ], apkFiles);
}); });
......
...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
/// Tests that plugins that don't define a `androidx.annotation:annotation:+` or /// Tests that plugins that don't define a `androidx.annotation:annotation:+` or
/// `com.android.support:support-annotations:+` dependency can be built as AAR. /// `com.android.support:support-annotations:+` dependency can be built as AAR.
...@@ -60,6 +60,12 @@ Future<void> main() async { ...@@ -60,6 +60,12 @@ Future<void> main() async {
); );
}); });
section('Update proguard rules');
// Don't obfuscate the input class files, since the test is checking if some classes are in the DEX.
final File proguardRules = File(path.join(projectDir.path, 'android', 'app', 'proguard-rules.pro'));
proguardRules.writeAsStringSync('-dontobfuscate', flush: true);
section('Build release APK'); section('Build release APK');
await inDirectory(projectDir, () async { await inDirectory(projectDir, () async {
......
...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -11,7 +11,7 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
final bool useAndroidEmbeddingV2 = Platform.environment['ENABLE_ANDROID_EMBEDDING_V2'] == 'true'; final bool useAndroidEmbeddingV2 = Platform.environment['ENABLE_ANDROID_EMBEDDING_V2'] == 'true';
...@@ -125,9 +125,7 @@ Future<void> main() async { ...@@ -125,9 +125,7 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'assets/flutter_assets/isolate_snapshot_data', ...debugAssets,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], await getFilesInApk(demoDebugApk)); ], await getFilesInApk(demoDebugApk));
await clean(); await clean();
...@@ -170,9 +168,7 @@ Future<void> main() async { ...@@ -170,9 +168,7 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'assets/flutter_assets/isolate_snapshot_data', ...debugAssets,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], await getFilesInApk(demoDebugApk2)); ], await getFilesInApk(demoDebugApk2));
await clean(); await clean();
...@@ -207,9 +203,7 @@ Future<void> main() async { ...@@ -207,9 +203,7 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'assets/flutter_assets/isolate_snapshot_data', ...debugAssets,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], await getFilesInApk(demoStagingApk)); ], await getFilesInApk(demoStagingApk));
await clean(); await clean();
...@@ -246,10 +240,10 @@ Future<void> main() async { ...@@ -246,10 +240,10 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'lib/arm64-v8a/libapp.so',
'lib/arm64-v8a/libflutter.so', 'lib/arm64-v8a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/arm64-v8a/libapp.so',
'lib/armeabi-v7a/libflutter.so', 'lib/armeabi-v7a/libflutter.so',
'lib/armeabi-v7a/libapp.so',
], await getFilesInApk(demoReleaseApk)); ], await getFilesInApk(demoReleaseApk));
await clean(); await clean();
......
...@@ -11,14 +11,13 @@ import 'package:flutter_devicelab/framework/utils.dart'; ...@@ -11,14 +11,13 @@ import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew';
final bool useAndroidEmbeddingV2 = Platform.environment['ENABLE_ANDROID_EMBEDDING_V2'] == 'true'; final bool useAndroidEmbeddingV2 = Platform.environment['ENABLE_ANDROID_EMBEDDING_V2'] == 'true';
/// Tests that the Flutter module project template works and supports /// Tests that the Flutter module project template works and supports
/// adding Flutter to an existing Android app. /// adding Flutter to an existing Android app.
Future<void> main() async { Future<void> main() async {
print(useAndroidEmbeddingV2);
await task(() async { await task(() async {
section('Find Java'); section('Find Java');
...@@ -201,10 +200,8 @@ Future<void> main() async { ...@@ -201,10 +200,8 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'AndroidManifest.xml', ...debugAssets,
'assets/flutter_assets/isolate_snapshot_data', ...baseApkFiles,
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], await getFilesInApk(debugHostApk)); ], await getFilesInApk(debugHostApk));
section('Check debug AndroidManifest.xml'); section('Check debug AndroidManifest.xml');
...@@ -258,7 +255,7 @@ Future<void> main() async { ...@@ -258,7 +255,7 @@ Future<void> main() async {
checkItContains<String>(<String>[ checkItContains<String>(<String>[
...flutterAssets, ...flutterAssets,
'AndroidManifest.xml', ...baseApkFiles,
'lib/arm64-v8a/libapp.so', 'lib/arm64-v8a/libapp.so',
'lib/arm64-v8a/libflutter.so', 'lib/arm64-v8a/libflutter.so',
'lib/armeabi-v7a/libapp.so', 'lib/armeabi-v7a/libapp.so',
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
...@@ -17,6 +16,17 @@ final List<String> flutterAssets = <String>[ ...@@ -17,6 +16,17 @@ final List<String> flutterAssets = <String>[
'assets/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf', 'assets/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf',
]; ];
final List<String> debugAssets = <String>[
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
];
final List<String> baseApkFiles = <String> [
'classes.dex',
'AndroidManifest.xml',
];
/// Runs the given [testFunction] on a freshly generated Flutter project. /// Runs the given [testFunction] on a freshly generated Flutter project.
Future<void> runProjectTest(Future<void> testFunction(FlutterProject project)) async { Future<void> runProjectTest(Future<void> testFunction(FlutterProject project)) async {
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_devicelab_gradle_plugin_test.'); final Directory tempDir = Directory.systemTemp.createTempSync('flutter_devicelab_gradle_plugin_test.');
...@@ -43,20 +53,18 @@ Future<void> runPluginProjectTest(Future<void> testFunction(FlutterPluginProject ...@@ -43,20 +53,18 @@ Future<void> runPluginProjectTest(Future<void> testFunction(FlutterPluginProject
/// Returns the list of files inside an Android Package Kit. /// Returns the list of files inside an Android Package Kit.
Future<Iterable<String>> getFilesInApk(String apk) async { Future<Iterable<String>> getFilesInApk(String apk) async {
if (!File(apk).existsSync()) if (!File(apk).existsSync()) {
throw TaskResult.failure( throw TaskResult.failure(
'Gradle did not produce an output artifact file at: $apk'); 'Gradle did not produce an output artifact file at: $apk');
}
final Process unzip = await startProcess( final String files = await _evalApkAnalyzer(
'unzip', <String>[
<String>['-v', apk], 'files',
isBot: false, // we just want to test the output, not have any debugging info 'list',
apk,
]
); );
return unzip.stdout return files.split('\n').map((String file) => file.substring(1).trim());
.transform(utf8.decoder)
.transform(const LineSplitter())
.map((String line) => line.split(' ').last)
.toList();
} }
/// Returns the list of files inside an Android App Bundle. /// Returns the list of files inside an Android App Bundle.
Future<Iterable<String>> getFilesInAppBundle(String bundle) { Future<Iterable<String>> getFilesInAppBundle(String bundle) {
...@@ -71,7 +79,7 @@ Future<Iterable<String>> getFilesInAar(String aar) { ...@@ -71,7 +79,7 @@ Future<Iterable<String>> getFilesInAar(String aar) {
void checkItContains<T>(Iterable<T> values, Iterable<T> collection) { void checkItContains<T>(Iterable<T> values, Iterable<T> collection) {
for (T value in values) { for (T value in values) {
if (!collection.contains(value)) { if (!collection.contains(value)) {
throw TaskResult.failure('Expected to find `$value` in `$collection`.'); throw TaskResult.failure('Expected to find `$value` in `${collection.toString()}`.');
} }
} }
} }
...@@ -120,9 +128,36 @@ String get _androidHome { ...@@ -120,9 +128,36 @@ String get _androidHome {
return androidHome; return androidHome;
} }
/// Utility class to analyze the content inside an APK using dexdump, /// Executes an APK analyzer subcommand.
/// which is provided by the Android SDK. Future<String> _evalApkAnalyzer(
/// https://android.googlesource.com/platform/art/+/master/dexdump/dexdump.cc List<String> args, {
bool printStdout = true,
String workingDirectory,
}) async {
final String javaHome = await findJavaHome();
final String javaBinary = path.join(javaHome, 'bin', 'java');
assert(canRun(javaBinary));
final String androidTools = path.join(_androidHome, 'tools');
final String libs = path.join(androidTools, 'lib');
assert(Directory(libs).existsSync());
final String classSeparator = Platform.isWindows ? ';' : ':';
return eval(
javaBinary,
<String>[
'-Dcom.android.sdklib.toolsdir=$androidTools',
'-classpath',
'.$classSeparator$libs${Platform.pathSeparator}*',
'com.android.tools.apk.analyzer.ApkAnalyzerCli',
...args,
],
printStdout: printStdout,
workingDirectory: workingDirectory,
);
}
/// Utility class to analyze the content inside an APK using the APK analyzer.
class ApkExtractor { class ApkExtractor {
ApkExtractor(this.apkFile); ApkExtractor(this.apkFile);
...@@ -131,70 +166,56 @@ class ApkExtractor { ...@@ -131,70 +166,56 @@ class ApkExtractor {
bool _extracted = false; bool _extracted = false;
Directory _outputDir; Set<String> _classes = const <String>{};
Future<void> _extractApk() async { Future<void> _extractDex() async {
if (_extracted) { if (_extracted) {
return; return;
} }
_outputDir = apkFile.parent.createTempSync('apk'); final String packages = await _evalApkAnalyzer(
if (Platform.isWindows) { <String>[
await eval('7za', <String>['x', apkFile.path], workingDirectory: _outputDir.path); 'dex',
} else { 'packages',
await eval('unzip', <String>[apkFile.path], workingDirectory: _outputDir.path); apkFile.path,
} ],
printStdout: false,
);
_classes = Set<String>.from(
packages
.split('\n')
.where((String line) => line.startsWith('C'))
.map<String>((String line) => line.split('\t').last),
);
assert(_classes.isNotEmpty);
_extracted = true; _extracted = true;
} }
/// Returns the full path to the [dexdump] tool.
Future<String> _findDexDump() async {
String dexdumps;
if (Platform.isWindows) {
dexdumps = await eval('dir', <String>['/s/b', 'dexdump.exe'],
workingDirectory: _androidHome);
} else {
dexdumps = await eval('find', <String>[_androidHome, '-name', 'dexdump']);
}
if (dexdumps.isEmpty) {
throw Exception('Couldn\'t find a dexdump executable.');
}
return dexdumps.split('\n').first;
}
// Removes any temporary directory. // Removes any temporary directory.
void dispose() { void dispose() {
if (!_extracted) { if (!_extracted) {
return; return;
} }
rmTree(_outputDir); _classes = const <String>{};
_extracted = true; _extracted = true;
} }
/// Returns true if the APK contains a given class. /// Returns true if the APK contains a given class.
Future<bool> containsClass(String className) async { Future<bool> containsClass(String className) async {
await _extractApk(); await _extractDex();
return _classes.contains(className);
final String dexDump = await _findDexDump();
final String classesDex = path.join(_outputDir.path, 'classes.dex');
if (!File(classesDex).existsSync()) {
throw Exception('Couldn\'t find classes.dex in the APK.');
}
final String classDescriptors = await eval(dexDump,
<String>[classesDex], printStdout: false);
if (classDescriptors.isEmpty) {
throw Exception('No descriptors found in classes.dex.');
}
return classDescriptors.contains(className.replaceAll('.', '/'));
} }
} }
/// Gets the content of the `AndroidManifest.xml`. /// Gets the content of the `AndroidManifest.xml`.
Future<String> getAndroidManifest(String apk) { Future<String> getAndroidManifest(String apk) async {
final String apkAnalyzer = path.join(_androidHome, 'tools', 'bin', 'apkanalyzer'); return await _evalApkAnalyzer(
return eval(apkAnalyzer, <String>['manifest', 'print', apk], <String>[
workingDirectory: _androidHome); 'manifest',
'print',
apk,
],
workingDirectory: _androidHome,
);
} }
/// Checks that the classes are contained in the APK, throws otherwise. /// Checks that the classes are contained in the APK, throws otherwise.
...@@ -318,7 +339,7 @@ android { ...@@ -318,7 +339,7 @@ android {
Future<ProcessResult> resultOfFlutterCommand(String command, List<String> options) { Future<ProcessResult> resultOfFlutterCommand(String command, List<String> options) {
return Process.run( return Process.run(
path.join(flutterDirectory.path, 'bin', 'flutter'), path.join(flutterDirectory.path, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'),
<String>[command, ...options], <String>[command, ...options],
workingDirectory: rootPath, workingDirectory: rootPath,
); );
...@@ -401,39 +422,14 @@ Future<ProcessResult> _resultOfGradleTask({String workingDirectory, String task, ...@@ -401,39 +422,14 @@ Future<ProcessResult> _resultOfGradleTask({String workingDirectory, String task,
); );
} }
class _Dependencies {
_Dependencies(String depfilePath) {
// Depfile format:
// outfile1 outfile2 : file1.dart file2.dart file3.dart file\ 4.dart
final String contents = File(depfilePath).readAsStringSync();
final List<String> colonSeparated = contents.split(':');
targets = _processList(colonSeparated[0].trim());
dependencies = _processList(colonSeparated[1].trim());
}
final RegExp _separatorExpr = RegExp(r'([^\\]) ');
final RegExp _escapeExpr = RegExp(r'\\(.)');
Set<String> _processList(String rawText) {
return rawText
// Put every file on right-hand side on the separate line
.replaceAllMapped(_separatorExpr, (Match match) => '${match.group(1)}\n')
.split('\n')
// Expand escape sequences, so that '\ ', for example,ß becomes ' '
.map<String>((String path) => path.replaceAllMapped(_escapeExpr, (Match match) => match.group(1)).trim())
.where((String path) => path.isNotEmpty)
.toSet();
}
Set<String> targets;
Set<String> dependencies;
}
/// Returns [null] if target matches [expectedTarget], otherwise returns an error message. /// Returns [null] if target matches [expectedTarget], otherwise returns an error message.
String validateSnapshotDependency(FlutterProject project, String expectedTarget) { String validateSnapshotDependency(FlutterProject project, String expectedTarget) {
final _Dependencies deps = _Dependencies( final File snapshotBlob = File(
path.join(project.rootPath, 'build', 'app', 'intermediates', path.join(project.rootPath, 'build', 'app', 'intermediates',
'flutter', 'debug', 'android-arm', 'snapshot_blob.bin.d')); 'flutter', 'debug', 'android-arm', 'snapshot_blob.bin.d'));
return deps.targets.any((String target) => target.contains(expectedTarget)) ? null :
'Dependency file should have $expectedTarget as target. Instead has ${deps.targets}'; assert(snapshotBlob.existsSync());
final String contentSnapshot = snapshotBlob.readAsStringSync();
return contentSnapshot.contains('$expectedTarget ')
? null : 'Dependency file should have $expectedTarget as target. Instead found $contentSnapshot';
} }
...@@ -255,13 +255,14 @@ Future<Process> startProcess( ...@@ -255,13 +255,14 @@ Future<Process> startProcess(
}) async { }) async {
assert(isBot != null); assert(isBot != null);
final String command = '$executable ${arguments?.join(" ") ?? ""}'; final String command = '$executable ${arguments?.join(" ") ?? ""}';
print('\nExecuting: $command'); final String finalWorkingDirectory = workingDirectory ?? cwd;
print('\nExecuting: $command in $finalWorkingDirectory');
environment ??= <String, String>{}; environment ??= <String, String>{};
environment['BOT'] = isBot ? 'true' : 'false'; environment['BOT'] = isBot ? 'true' : 'false';
final Process process = await _processManager.start( final Process process = await _processManager.start(
<String>[executable, ...arguments], <String>[executable, ...arguments],
environment: environment, environment: environment,
workingDirectory: workingDirectory ?? cwd, workingDirectory: finalWorkingDirectory,
); );
final ProcessInfo processInfo = ProcessInfo(command, process); final ProcessInfo processInfo = ProcessInfo(command, process);
_runningProcesses.add(processInfo); _runningProcesses.add(processInfo);
...@@ -447,7 +448,7 @@ void cd(dynamic directory) { ...@@ -447,7 +448,7 @@ void cd(dynamic directory) {
throw 'Cannot cd into directory that does not exist: $directory'; throw 'Cannot cd into directory that does not exist: $directory';
} }
Directory get flutterDirectory => dir('../..').absolute; Directory get flutterDirectory => Directory.current.parent.parent;
String requireEnvVar(String name) { String requireEnvVar(String name) {
final String value = Platform.environment[name]; final String value = Platform.environment[name];
......
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