forked from firka/flutter
Add metadata to indicate if the host app contains a Flutter module (#37731)
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<!-- 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>
|
||||
|
||||
Reference in New Issue
Block a user