Unverified Commit c08a3c7a authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Add metadata to indicate if the host app contains a Flutter module (#37731)

parent 36b8725a
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter_devicelab/framework/apk_utils.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
......@@ -156,6 +157,8 @@ Future<void> main() async {
final File analyticsOutputFile = File(path.join(tempDir.path, 'analytics.log'));
section('Build debug host APK');
await inDirectory(hostApp, () async {
if (!Platform.isWindows) {
await exec('chmod', <String>['+x', 'gradlew']);
......@@ -169,7 +172,9 @@ Future<void> main() async {
);
});
final bool existingAppBuilt = exists(File(path.join(
section('Check debug APK exists');
final String debugHostApk = path.join(
hostApp.path,
'app',
'build',
......@@ -177,9 +182,29 @@ Future<void> main() async {
'apk',
'debug',
'app-debug.apk',
)));
if (!existingAppBuilt) {
return TaskResult.failure('Failed to build existing app .apk');
);
if (!exists(File(debugHostApk))) {
return TaskResult.failure('Failed to build debug host APK');
}
section('Check files in debug APK');
checkItContains<String>(<String>[
'AndroidManifest.xml',
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], await getFilesInApk(debugHostApk));
section('Check debug AndroidManifest.xml');
final String androidManifestDebug = await getAndroidManifest(debugHostApk);
if (!androidManifestDebug.contains('''
<meta-data
android:name="flutterProjectType"
android:value="module" />''')
) {
return TaskResult.failure('Debug host APK doesn\'t contain metadata: flutterProjectType = module ');
}
final String analyticsOutput = analyticsOutputFile.readAsStringSync();
......@@ -193,7 +218,54 @@ Future<void> main() async {
);
}
section('Build release host APK');
await inDirectory(hostApp, () async {
await exec(gradlewExecutable,
<String>['app:assembleRelease'],
environment: <String, String>{
'JAVA_HOME': javaHome,
'FLUTTER_ANALYTICS_LOG_FILE': analyticsOutputFile.path,
},
);
});
final String releaseHostApk = path.join(
hostApp.path,
'app',
'build',
'outputs',
'apk',
'release',
'app-release-unsigned.apk',
);
if (!exists(File(releaseHostApk))) {
return TaskResult.failure('Failed to build release host APK');
}
section('Check files in release APK');
checkItContains<String>(<String>[
'AndroidManifest.xml',
'lib/arm64-v8a/libapp.so',
'lib/arm64-v8a/libflutter.so',
'lib/armeabi-v7a/libapp.so',
'lib/armeabi-v7a/libflutter.so',
], await getFilesInApk(releaseHostApk));
section('Check release AndroidManifest.xml');
final String androidManifestRelease = await getAndroidManifest(debugHostApk);
if (!androidManifestRelease.contains('''
<meta-data
android:name="flutterProjectType"
android:value="module" />''')
) {
return TaskResult.failure('Release host APK doesn\'t contain metadata: flutterProjectType = module ');
}
return TaskResult.success(null);
} on TaskResult catch (taskResult) {
return taskResult;
} catch (e) {
return TaskResult.failure(e.toString());
} finally {
......
......@@ -89,6 +89,16 @@ bool hasMultipleOccurrences(String text, Pattern pattern) {
return text.indexOf(pattern) != text.lastIndexOf(pattern);
}
/// The Android home directory.
String get _androidHome {
final String androidHome = Platform.environment['ANDROID_HOME'] ??
Platform.environment['ANDROID_SDK_ROOT'];
if (androidHome == null || androidHome.isEmpty) {
throw Exception('Unset env flag: `ANDROID_HOME` or `ANDROID_SDK_ROOT`.');
}
return androidHome;
}
/// Utility class to analyze the content inside an APK using dexdump,
/// which is provided by the Android SDK.
/// https://android.googlesource.com/platform/art/+/master/dexdump/dexdump.cc
......@@ -117,18 +127,12 @@ class ApkExtractor {
/// Returns the full path to the [dexdump] tool.
Future<String> _findDexDump() async {
final String androidHome = Platform.environment['ANDROID_HOME'] ??
Platform.environment['ANDROID_SDK_ROOT'];
if (androidHome == null || androidHome.isEmpty) {
throw Exception('Unset env flag: `ANDROID_HOME` or `ANDROID_SDK_ROOT`.');
}
String dexdumps;
if (Platform.isWindows) {
dexdumps = await eval('dir', <String>['/s/b', 'dexdump.exe'],
workingDirectory: androidHome);
workingDirectory: _androidHome);
} else {
dexdumps = await eval('find', <String>[androidHome, '-name', 'dexdump']);
dexdumps = await eval('find', <String>[_androidHome, '-name', 'dexdump']);
}
if (dexdumps.isEmpty) {
throw Exception('Couldn\'t find a dexdump executable.');
......@@ -165,6 +169,13 @@ class ApkExtractor {
}
}
/// Gets the content of the `AndroidManifest.xml`.
Future<String> getAndroidManifest(String apk) {
final String apkAnalyzer = path.join(_androidHome, 'tools', 'bin', 'apkanalyzer');
return eval(apkAnalyzer, <String>['manifest', 'print', apk],
workingDirectory: _androidHome);
}
/// Checks that the classes are contained in the APK, throws otherwise.
Future<void> checkApkContainsClasses(File apk, List<String> classes) async {
final ApkExtractor extractor = ApkExtractor(apk);
......
<!-- Generated file. Do not edit. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{androidIdentifier}}">
package="{{androidIdentifier}}"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application tools:node="merge">
<meta-data
android:name="flutterProjectType"
android:value="module" />
</application>
</manifest>
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