Unverified Commit 9f39cad4 authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Allow flavors and custom build types in host app (#36805)

Fixes these issues:
#30916
#34089
#36479
#29648
parent ef146f63
...@@ -965,5 +965,6 @@ Future<void> _androidGradleTests(String subShard) async { ...@@ -965,5 +965,6 @@ Future<void> _androidGradleTests(String subShard) async {
if (subShard == 'gradle2') { if (subShard == 'gradle2') {
await _runDevicelabTest('gradle_plugin_bundle_test', env: env); await _runDevicelabTest('gradle_plugin_bundle_test', env: env);
await _runDevicelabTest('module_test', env: env); await _runDevicelabTest('module_test', env: env);
await _runDevicelabTest('module_host_with_custom_build_test', env: env);
} }
} }
// 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);
}
});
}
# 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.
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'
}
<?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>
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"));
}
}
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
}
#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
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> { ...@@ -611,24 +611,7 @@ class FlutterPlugin implements Plugin<Project> {
with flutterTask.assets with flutterTask.assets
} }
} }
if (packageAssets) { variant.outputs.first().processResources.dependsOn(copyFlutterAssetsTask)
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)
}
} }
if (project.android.hasProperty("applicationVariants")) { if (project.android.hasProperty("applicationVariants")) {
project.android.applicationVariants.all addFlutterDeps project.android.applicationVariants.all addFlutterDeps
......
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