Allow flavors and custom build types in host app (#36805)
Fixes these issues: #30916 #34089 #36479 #29648
This commit is contained in:
parent
ef146f63bb
commit
9f39cad4ed
@ -965,5 +965,6 @@ Future<void> _androidGradleTests(String subShard) async {
|
||||
if (subShard == 'gradle2') {
|
||||
await _runDevicelabTest('gradle_plugin_bundle_test', env: env);
|
||||
await _runDevicelabTest('module_test', env: env);
|
||||
await _runDevicelabTest('module_host_with_custom_build_test', env: env);
|
||||
}
|
||||
}
|
||||
|
268
dev/devicelab/bin/tasks/module_host_with_custom_build_test.dart
Normal file
268
dev/devicelab/bin/tasks/module_host_with_custom_build_test.dart
Normal file
@ -0,0 +1,268 @@
|
||||
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
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;
|
||||
|
||||
final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew';
|
||||
final String gradlewExecutable = Platform.isWindows ? gradlew : './$gradlew';
|
||||
|
||||
/// Tests that the Android app containing a Flutter module can be built when
|
||||
/// it has custom build types and flavors.
|
||||
Future<void> main() async {
|
||||
await task(() async {
|
||||
|
||||
section('Find Java');
|
||||
|
||||
final String javaHome = await findJavaHome();
|
||||
if (javaHome == null) {
|
||||
return TaskResult.failure('Could not find Java');
|
||||
}
|
||||
|
||||
print('\nUsing JAVA_HOME=$javaHome');
|
||||
|
||||
section('Create Flutter module project');
|
||||
|
||||
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
|
||||
final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
|
||||
try {
|
||||
await inDirectory(tempDir, () async {
|
||||
await flutter(
|
||||
'create',
|
||||
options: <String>['--org', 'io.flutter.devicelab', '--template=module', 'hello'],
|
||||
);
|
||||
});
|
||||
|
||||
section('Run flutter pub get');
|
||||
|
||||
await inDirectory(projectDir, () async {
|
||||
await flutter(
|
||||
'pub',
|
||||
options: <String>['get'],
|
||||
);
|
||||
});
|
||||
|
||||
section('Add to existing Android app');
|
||||
|
||||
final Directory hostAppDir = Directory(path.join(tempDir.path, 'hello_host_app_with_custom_build'));
|
||||
mkdir(hostAppDir);
|
||||
recursiveCopy(
|
||||
Directory(path.join(flutterDirectory.path, 'dev', 'integration_tests', 'module_host_with_custom_build')),
|
||||
hostAppDir,
|
||||
);
|
||||
copy(
|
||||
File(path.join(projectDir.path, '.android', gradlew)),
|
||||
hostAppDir,
|
||||
);
|
||||
copy(
|
||||
File(path.join(projectDir.path, '.android', 'gradle', 'wrapper', 'gradle-wrapper.jar')),
|
||||
Directory(path.join(hostAppDir.path, 'gradle', 'wrapper')),
|
||||
);
|
||||
|
||||
section('Build debug APKs');
|
||||
|
||||
section('Run app:assembleDemoDebug');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
if (!Platform.isWindows) {
|
||||
await exec('chmod', <String>['+x', 'gradlew']);
|
||||
}
|
||||
await exec(gradlewExecutable,
|
||||
<String>['app:assembleDemoDebug'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
final String demoDebugApk = path.join(
|
||||
hostAppDir.path,
|
||||
'app',
|
||||
'build',
|
||||
'outputs',
|
||||
'apk',
|
||||
'demo',
|
||||
'debug',
|
||||
'app-demo-debug.apk',
|
||||
);
|
||||
|
||||
if (!exists(File(demoDebugApk))) {
|
||||
return TaskResult.failure('Failed to build app-demo-debug.apk');
|
||||
}
|
||||
|
||||
section('Verify snapshots in app-demo-debug.apk');
|
||||
|
||||
final Iterable<String> demoDebugFiles = await getFilesInApk(demoDebugApk);
|
||||
checkItContains<String>(<String>[
|
||||
'assets/flutter_assets/isolate_snapshot_data',
|
||||
'assets/flutter_assets/kernel_blob.bin',
|
||||
'assets/flutter_assets/vm_snapshot_data',
|
||||
], demoDebugFiles);
|
||||
|
||||
section('Clean');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
await exec(gradlewExecutable,
|
||||
<String>['clean'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
section('Run app:assembleDemoStaging');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
if (!Platform.isWindows) {
|
||||
await exec('chmod', <String>['+x', 'gradlew']);
|
||||
}
|
||||
await exec(gradlewExecutable,
|
||||
<String>['app:assembleDemoStaging'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
final String demoStagingApk = path.join(
|
||||
hostAppDir.path,
|
||||
'app',
|
||||
'build',
|
||||
'outputs',
|
||||
'apk',
|
||||
'demo',
|
||||
'staging',
|
||||
'app-demo-staging.apk',
|
||||
);
|
||||
|
||||
if (!exists(File(demoStagingApk))) {
|
||||
return TaskResult.failure('Failed to build app-demo-staging.apk');
|
||||
}
|
||||
|
||||
section('Verify snapshots in app-demo-staging.apk');
|
||||
|
||||
final Iterable<String> demoStagingFiles = await getFilesInApk(demoStagingApk);
|
||||
checkItContains<String>(<String>[
|
||||
'assets/flutter_assets/isolate_snapshot_data',
|
||||
'assets/flutter_assets/kernel_blob.bin',
|
||||
'assets/flutter_assets/vm_snapshot_data',
|
||||
], demoStagingFiles);
|
||||
|
||||
section('Clean');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
await exec(gradlewExecutable,
|
||||
<String>['clean'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
section('Build release APKs');
|
||||
|
||||
section('Run app:assembleDemoRelease');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
if (!Platform.isWindows) {
|
||||
await exec('chmod', <String>['+x', 'gradlew']);
|
||||
}
|
||||
await exec(gradlewExecutable,
|
||||
<String>['app:assembleDemoRelease'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
final String demoReleaseApk = path.join(
|
||||
hostAppDir.path,
|
||||
'app',
|
||||
'build',
|
||||
'outputs',
|
||||
'apk',
|
||||
'demo',
|
||||
'release',
|
||||
'app-demo-release-unsigned.apk',
|
||||
);
|
||||
|
||||
if (!exists(File(demoReleaseApk))) {
|
||||
return TaskResult.failure('Failed to build app-demo-release-unsigned.apk');
|
||||
}
|
||||
|
||||
section('Verify AOT blobs in app-demo-release-unsigned.apk');
|
||||
|
||||
final Iterable<String> demoReleaseFiles = await getFilesInApk(demoReleaseApk);
|
||||
checkItContains<String>(<String>[
|
||||
'lib/arm64-v8a/libapp.so',
|
||||
'lib/arm64-v8a/libflutter.so',
|
||||
'lib/armeabi-v7a/libapp.so',
|
||||
'lib/armeabi-v7a/libflutter.so',
|
||||
], demoReleaseFiles);
|
||||
|
||||
section('Clean');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
await exec(gradlewExecutable,
|
||||
<String>['clean'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
section('Run app:assembleDemoProd');
|
||||
|
||||
await inDirectory(hostAppDir, () async {
|
||||
if (!Platform.isWindows) {
|
||||
await exec('chmod', <String>['+x', 'gradlew']);
|
||||
}
|
||||
await exec(gradlewExecutable,
|
||||
<String>['app:assembleDemoProd'],
|
||||
environment: <String, String>{
|
||||
'JAVA_HOME': javaHome,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
final String demoProdApk = path.join(
|
||||
hostAppDir.path,
|
||||
'app',
|
||||
'build',
|
||||
'outputs',
|
||||
'apk',
|
||||
'demo',
|
||||
'prod',
|
||||
'app-demo-prod-unsigned.apk',
|
||||
);
|
||||
|
||||
if (!exists(File(demoProdApk))) {
|
||||
return TaskResult.failure('Failed to build app-demo-prod-unsigned.apk');
|
||||
}
|
||||
|
||||
section('Verify AOT blobs in app-demo-prod-unsigned.apk');
|
||||
|
||||
final Iterable<String> demoProdFiles = await getFilesInApk(demoProdApk);
|
||||
checkItContains<String>(<String>[
|
||||
'lib/arm64-v8a/libapp.so',
|
||||
'lib/arm64-v8a/libflutter.so',
|
||||
'lib/armeabi-v7a/libapp.so',
|
||||
'lib/armeabi-v7a/libflutter.so',
|
||||
], demoProdFiles);
|
||||
|
||||
return TaskResult.success(null);
|
||||
} on TaskResult catch (taskResult) {
|
||||
return taskResult;
|
||||
} catch (e) {
|
||||
return TaskResult.failure(e.toString());
|
||||
} finally {
|
||||
rmTree(tempDir);
|
||||
}
|
||||
});
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
# Android host app
|
||||
|
||||
Android host app for a Flutter module created using
|
||||
```
|
||||
$ flutter create -t module hello
|
||||
```
|
||||
and placed in a sibling folder to (a clone of) the host app.
|
||||
Used by the `module_host_with_custom_build_test.dart` device lab test.
|
@ -0,0 +1,43 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileOptions {
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility 1.8
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId "io.flutter.addtoapp"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
// Test build types.
|
||||
buildTypes {
|
||||
staging {
|
||||
initWith debug
|
||||
// This is required because the `:flutter` project doesn't define this custom build type.
|
||||
// Without the fallback, the Android plugin will make Gradle exit with the following error:
|
||||
// `Unable to find a matching variant of project :flutter`
|
||||
matchingFallbacks = ['debug']
|
||||
}
|
||||
prod {
|
||||
initWith release
|
||||
matchingFallbacks = ['release']
|
||||
}
|
||||
}
|
||||
// Test flavors.
|
||||
flavorDimensions "version"
|
||||
productFlavors {
|
||||
demo {
|
||||
dimension "version"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':flutter')
|
||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.flutter.addtoapp">
|
||||
|
||||
<application android:allowBackup="false"
|
||||
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
|
||||
<activity android:name=".MainActivity" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,14 @@
|
||||
package io.flutter.addtoapp;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import io.flutter.facade.Flutter;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(Flutter.createView(this, getLifecycle(), "route1"));
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.gradle.jvmargs=-Xmx1536m
|
6
dev/integration_tests/module_host_with_custom_build/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
dev/integration_tests/module_host_with_custom_build/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#Mon Jun 25 14:13:36 CEST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
|
@ -0,0 +1,3 @@
|
||||
include ':app'
|
||||
setBinding(new Binding([gradle: this]))
|
||||
evaluate(new File(settingsDir.parentFile, 'hello/.android/include_flutter.groovy'))
|
@ -611,24 +611,7 @@ class FlutterPlugin implements Plugin<Project> {
|
||||
with flutterTask.assets
|
||||
}
|
||||
}
|
||||
if (packageAssets) {
|
||||
String mainModuleName = "app"
|
||||
try {
|
||||
String tmpModuleName = project.rootProject.ext.mainModuleName
|
||||
if (tmpModuleName != null && !tmpModuleName.empty) {
|
||||
mainModuleName = tmpModuleName
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
// Only include configurations that exist in parent project.
|
||||
Task mergeAssets = project.tasks.findByPath(":${mainModuleName}:merge${variant.name.capitalize()}Assets")
|
||||
if (mergeAssets) {
|
||||
mergeAssets.dependsOn(copyFlutterAssetsTask)
|
||||
}
|
||||
} else {
|
||||
def processResources = variant.outputs.first().processResources
|
||||
processResources.dependsOn(copyFlutterAssetsTask)
|
||||
}
|
||||
variant.outputs.first().processResources.dependsOn(copyFlutterAssetsTask)
|
||||
}
|
||||
if (project.android.hasProperty("applicationVariants")) {
|
||||
project.android.applicationVariants.all addFlutterDeps
|
||||
|
Loading…
x
Reference in New Issue
Block a user