Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
2c8813c8
Unverified
Commit
2c8813c8
authored
Sep 23, 2019
by
Emmanuel Garcia
Committed by
GitHub
Sep 23, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Re-enable AAR plugins when an AndroidX failure occurred (#40810)" (#41042)
This reverts commit
96482eeb
.
parent
919cc97f
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
247 additions
and
401 deletions
+247
-401
test.dart
dev/bots/test.dart
+0
-1
gradle_jetifier_test.dart
dev/devicelab/bin/tasks/gradle_jetifier_test.dart
+1
-4
aar_init_script.gradle
packages/flutter_tools/gradle/aar_init_script.gradle
+10
-27
flutter.gradle
packages/flutter_tools/gradle/flutter.gradle
+156
-54
gradle.dart
packages/flutter_tools/lib/src/android/gradle.dart
+53
-149
features.dart
packages/flutter_tools/lib/src/features.dart
+3
-0
events.dart
packages/flutter_tools/lib/src/reporting/events.dart
+0
-4
usage.dart
packages/flutter_tools/lib/src/reporting/usage.dart
+0
-1
gradle_test.dart
...flutter_tools/test/general.shard/android/gradle_test.dart
+5
-161
features_test.dart
packages/flutter_tools/test/general.shard/features_test.dart
+15
-0
testbed.dart
packages/flutter_tools/test/src/testbed.dart
+4
-0
No files found.
dev/bots/test.dart
View file @
2c8813c8
...
...
@@ -1022,7 +1022,6 @@ Future<void> _androidGradleTests(String subShard) async {
await
_runDevicelabTest
(
'gradle_plugin_fat_apk_test'
,
env:
env
);
await
_runDevicelabTest
(
'gradle_r8_test'
,
env:
env
);
await
_runDevicelabTest
(
'gradle_non_android_plugin_test'
,
env:
env
);
await
_runDevicelabTest
(
'gradle_jetifier_test'
,
env:
env
);
}
if
(
subShard
==
'gradle2'
)
{
await
_runDevicelabTest
(
'gradle_plugin_bundle_test'
,
env:
env
);
...
...
dev/devicelab/bin/tasks/gradle_jetifier_test.dart
View file @
2c8813c8
...
...
@@ -64,7 +64,6 @@ Future<void> main() async {
options:
<
String
>[
'apk'
,
'--target-platform'
,
'android-arm'
,
'--no-shrink'
,
'--verbose'
,
],
);
...
...
@@ -101,9 +100,7 @@ Future<void> main() async {
options:
<
String
>[
'apk'
,
'--target-platform'
,
'android-arm'
,
'--debug'
,
'--no-shrink'
,
'--verbose'
,
'--debug'
,
'--verbose'
,
],
);
});
...
...
packages/flutter_tools/gradle/aar_init_script.gradle
View file @
2c8813c8
...
...
@@ -7,7 +7,6 @@
// destination of the local repository.
// The local repository will contain the AAR and POM files.
import
java.nio.file.Paths
import
org.gradle.api.Project
import
org.gradle.api.artifacts.Configuration
import
org.gradle.api.artifacts.maven.MavenDeployer
...
...
@@ -40,32 +39,16 @@ void configureProject(Project project, File outputDir) {
}
}
}
if
(!
project
.
property
(
"is-plugin"
).
toBoolean
())
{
return
}
if
(
project
.
hasProperty
(
'localEngineOut'
))
{
// TODO(egarciad): Support local engine.
// This most likely requires refactoring `flutter.gradle`, so the logic can be reused.
throw
new
GradleException
(
"Local engine isn't supported when building the plugins as AAR. "
+
"See: https://github.com/flutter/flutter/issues/40866"
)
}
// This is a Flutter plugin project. Plugin projects don't apply the Flutter Gradle plugin,
// as a result, add the dependency on the embedding.
project
.
repositories
{
maven
{
url
"http://download.flutter.io"
}
}
String
engineVersion
=
Paths
.
get
(
getFlutterRoot
(
project
),
"bin"
,
"internal"
,
"engine.version"
)
.
toFile
().
text
.
trim
()
project
.
dependencies
{
// Add the embedding dependency.
compileOnly
(
"io.flutter:flutter_embedding_release:1.0.0-$engineVersion"
)
{
// We only need to expose io.flutter.plugin.*
// No need for the embedding transitive dependencies.
transitive
=
false
// Check if the project uses the Flutter plugin (defined in flutter.gradle).
Boolean
usesFlutterPlugin
=
project
.
plugins
.
find
{
it
.
class
.
name
==
"FlutterPlugin"
}
!=
null
if
(!
usesFlutterPlugin
)
{
project
.
dependencies
{
// Some plugins don't include `annotations` and they don't set
// `android.useAndroidX=true` in `gradle.properties`.
compileOnly
"androidx.annotation:annotation:+"
compileOnly
"com.android.support:support-annotations:+"
// The Flutter plugin already adds `flutter.jar`.
compileOnly
project
.
files
(
"${getFlutterRoot(project)}/bin/cache/artifacts/engine/android-arm-release/flutter.jar"
)
}
}
}
...
...
packages/flutter_tools/gradle/flutter.gradle
View file @
2c8813c8
...
...
@@ -8,8 +8,6 @@ import com.android.builder.model.AndroidProject
import
com.android.build.OutputFile
import
java.nio.file.Path
import
java.nio.file.Paths
import
java.util.regex.Matcher
import
java.util.regex.Pattern
import
org.apache.tools.ant.taskdefs.condition.Os
import
org.gradle.api.DefaultTask
import
org.gradle.api.GradleException
...
...
@@ -258,65 +256,29 @@ class FlutterPlugin implements Plugin<Project> {
*/
private
void
configurePlugins
()
{
if
(!
buildPluginAsAar
())
{
getPluginList
().
each
this
.&
configurePlugin
Project
getPluginList
().
each
this
.&
configurePlugin
return
}
if
(
useLocalEngine
())
{
throw
new
GradleException
(
"Local engine isn't supported when building the plugins as AAR"
)
}
List
<
Project
>
projects
=
[
project
]
// Module projects set the `hostProjects` extra property in `include_flutter.groovy`.
// This is required to set the local repository in each host app project.
if
(
project
.
ext
.
has
(
"hostProjects"
))
{
projects
.
addAll
(
project
.
ext
.
get
(
"hostProjects"
))
}
// Configure the repository for the plugins.
projects
.
each
{
hostProject
->
hostProject
.
repositories
{
maven
{
url
"${getPluginBuildDir()}/outputs/repo"
}
addPluginTasks
()
List
<
String
>
tasksToExecute
=
project
.
gradle
.
startParameter
.
taskNames
Set
buildTypes
=
getBuildTypesForTasks
(
tasksToExecute
)
if
(
tasksToExecute
.
contains
(
"clean"
))
{
// Because the plugins are built during configuration, the task "clean"
// cannot run in conjunction with an assembly task.
if
(!
buildTypes
.
empty
)
{
throw
new
GradleException
(
"Can't run the clean task along with other assemble tasks"
)
}
}
getPluginList
().
each
{
pluginName
,
pluginPath
->
configurePluginAar
(
pluginName
,
pluginPath
,
project
)
// Build plugins when a task "assembly*" will be called later.
if
(!
buildTypes
.
empty
)
{
// Build the plugin during configuration.
// This is required when Jetifier is enabled, otherwise the implementation dependency
// cannot be added.
buildAarPlugins
(
buildTypes
)
}
}
private
static
final
Pattern
GROUP_PATTERN
=
~
/group\s+\'(.+)\'/
private
static
final
Pattern
PROJECT_NAME_PATTERN
=
~
/rootProject\.name\s+=\s+\'(.+)\'/
// Adds the plugin AAR dependency to the app project.
private
void
configurePluginAar
(
String
pluginName
,
String
pluginPath
,
Project
project
)
{
// Extract the group id from the plugin's build.gradle.
// This is `group '<group-id>'`
File
pluginBuildFile
=
project
.
file
(
Paths
.
get
(
pluginPath
,
"android"
,
"build.gradle"
));
if
(!
pluginBuildFile
.
exists
())
{
throw
new
GradleException
(
"Plugin $pluginName doesn't have the required file $pluginBuildFile."
)
}
Matcher
groupParts
=
GROUP_PATTERN
.
matcher
(
pluginBuildFile
.
text
)
assert
groupParts
.
count
==
1
assert
groupParts
.
hasGroup
()
String
groupId
=
groupParts
[
0
][
1
]
// Extract the artifact name from the plugin's settings.gradle.
// This is `rootProject.name = '<artifact-name>'`
File
pluginSettings
=
project
.
file
(
Paths
.
get
(
pluginPath
,
"android"
,
"settings.gradle"
));
if
(!
pluginSettings
.
exists
())
{
throw
new
GradleException
(
"Plugin $pluginName doesn't have the required file $pluginSettings."
)
}
Matcher
projectNameParts
=
PROJECT_NAME_PATTERN
.
matcher
(
pluginSettings
.
text
)
assert
projectNameParts
.
count
==
1
assert
projectNameParts
.
hasGroup
()
String
artifactId
=
"${projectNameParts[0][1]}_release"
assert
!
groupId
.
empty
project
.
dependencies
.
add
(
"api"
,
"$groupId:$artifactId:+"
)
}
// Adds the plugin project dependency to the app project .
private
void
configurePluginProject
(
String
name
,
String
_
)
{
private
void
configurePlugin
(
String
name
,
String
_
)
{
Project
pluginProject
=
project
.
rootProject
.
findProject
(
":$name"
)
if
(
pluginProject
==
null
)
{
project
.
logger
.
error
(
"Plugin project :$name not found. Please update settings.gradle."
)
...
...
@@ -381,6 +343,93 @@ class FlutterPlugin implements Plugin<Project> {
return
androidPlugins
}
private
void
addPluginTasks
()
{
Properties
plugins
=
getPluginList
()
project
.
android
.
buildTypes
.
each
{
buildType
->
plugins
.
each
{
name
,
path
->
String
buildModeValue
=
buildType
.
debuggable
?
"debug"
:
"release"
List
<
String
>
taskNameParts
=
[
"build"
,
"plugin"
,
buildModeValue
]
taskNameParts
.
addAll
(
name
.
split
(
"_"
))
String
taskName
=
toCammelCase
(
taskNameParts
)
// Build types can be extended. For example, a build type can extend the `debug` mode.
// In such cases, prevent creating the same task.
if
(
project
.
tasks
.
findByName
(
taskName
)
==
null
)
{
project
.
tasks
.
create
(
name:
taskName
,
type:
FlutterPluginTask
)
{
flutterExecutable
this
.
flutterExecutable
buildMode
buildModeValue
verbose
isVerbose
()
pluginDir
project
.
file
(
path
)
sourceDir
project
.
file
(
project
.
flutter
.
source
)
intermediateDir
getPluginBuildDir
()
}
}
}
}
}
private
void
buildAarPlugins
(
Set
buildTypes
)
{
List
<
Project
>
projects
=
[
project
]
// Module projects set the `hostProjects` extra property in `include_flutter.groovy`.
// This is required to set the local repository in each host app project.
if
(
project
.
ext
.
has
(
"hostProjects"
))
{
projects
.
addAll
(
project
.
ext
.
get
(
"hostProjects"
))
}
projects
.
each
{
hostProject
->
hostProject
.
repositories
{
maven
{
url
"${getPluginBuildDir()}/outputs/repo"
}
}
}
buildTypes
.
each
{
buildType
->
project
.
tasks
.
withType
(
FlutterPluginTask
).
all
{
pluginTask
->
String
buildMode
=
buildType
.
debuggable
?
"debug"
:
"release"
if
(
pluginTask
.
buildMode
!=
buildMode
)
{
return
}
pluginTask
.
execute
()
pluginTask
.
intermediateDir
.
eachFileRecurse
(
FILES
)
{
file
->
if
(
file
.
name
!=
"maven-metadata.xml"
)
{
return
}
def
mavenMetadata
=
new
XmlParser
().
parse
(
file
)
String
groupId
=
mavenMetadata
.
groupId
.
text
()
String
artifactId
=
mavenMetadata
.
artifactId
.
text
()
if
(!
artifactId
.
endsWith
(
buildMode
))
{
return
}
// Add the plugin dependency based on the Maven metadata.
addApiDependencies
(
project
,
buildType
.
name
,
"$groupId:$artifactId:+@aar"
,
{
transitive
=
true
})
}
}
}
}
/**
* Returns a set with the build type names that apply to the given list of tasks
* required to configure the plugin dependencies.
*/
private
Set
getBuildTypesForTasks
(
List
<
String
>
tasksToExecute
)
{
Set
buildTypes
=
[]
tasksToExecute
.
each
{
task
->
project
.
android
.
buildTypes
.
each
{
buildType
->
if
(
task
==
"androidDependencies"
||
task
.
endsWith
(
"dependencies"
))
{
// The tasks to query the dependencies includes all the build types.
buildTypes
.
add
(
buildType
)
}
else
if
(
task
.
endsWith
(
"assemble"
))
{
// The `assemble` task includes all the build types.
buildTypes
.
add
(
buildType
)
}
else
if
(
task
.
endsWith
(
buildType
.
name
.
capitalize
()))
{
buildTypes
.
add
(
buildType
)
}
}
}
return
buildTypes
}
private
static
String
toCammelCase
(
List
<
String
>
parts
)
{
if
(
parts
.
empty
)
{
return
""
...
...
@@ -878,3 +927,56 @@ class FlutterTask extends BaseFlutterTask {
buildBundle
()
}
}
class
FlutterPluginTask
extends
DefaultTask
{
File
flutterExecutable
@Optional
@Input
Boolean
verbose
@Input
String
buildMode
@Input
File
pluginDir
@Input
File
intermediateDir
File
sourceDir
@InputFiles
FileCollection
getSourceFiles
()
{
return
project
.
fileTree
(
dir:
sourceDir
,
exclude:
[
"android"
,
"ios"
],
include:
[
"pubspec.yaml"
]
)
}
@OutputDirectory
File
getOutputDirectory
()
{
return
intermediateDir
}
@TaskAction
void
build
()
{
intermediateDir
.
mkdirs
()
project
.
exec
{
executable
flutterExecutable
.
absolutePath
workingDir
pluginDir
args
"build"
,
"aar"
args
"--quiet"
args
"--suppress-analytics"
args
"--output-dir"
,
"${intermediateDir}"
switch
(
buildMode
)
{
case
'release'
:
args
"--release"
break
case
'debug'
:
args
"--debug"
break
default:
assert
false
}
if
(
verbose
)
{
args
"--verbose"
}
}
}
}
packages/flutter_tools/lib/src/android/gradle.dart
View file @
2c8813c8
...
...
@@ -22,6 +22,7 @@ import '../base/utils.dart';
import
'../base/version.dart'
;
import
'../build_info.dart'
;
import
'../cache.dart'
;
import
'../features.dart'
;
import
'../flutter_manifest.dart'
;
import
'../globals.dart'
;
import
'../project.dart'
;
...
...
@@ -46,20 +47,18 @@ class GradleUtils {
return
_cachedExecutable
;
}
final
Map
<
FlutterProject
,
GradleProject
>
_cachedAppProject
=
<
FlutterProject
,
GradleProject
>{};
/// Gets the [GradleProject] for the [project] if built as an app.
Future
<
GradleProject
>
getAppProject
(
FlutterProject
project
)
async
{
_cachedAppProject
[
project
]
??=
await
_readGradleProject
(
project
,
isLibrary:
false
);
return
_cachedAppProject
[
project
];
GradleProject
_cachedAppProject
;
/// Gets the [GradleProject] for the current [FlutterProject] if built as an app.
Future
<
GradleProject
>
get
appProject
async
{
_cachedAppProject
??=
await
_readGradleProject
(
isLibrary:
false
);
return
_cachedAppProject
;
}
final
Map
<
FlutterProject
,
GradleProject
>
_cachedLibraryProject
=
<
FlutterProject
,
GradleProject
>{};
/// Gets the [GradleProject] for the [project] if built as a library.
Future
<
GradleProject
>
getLibraryProject
(
FlutterProject
project
)
async
{
_cachedLibraryProject
[
project
]
??=
await
_readGradleProject
(
project
,
isLibrary:
true
);
return
_cachedLibraryProject
[
project
];
GradleProject
_cachedLibraryProject
;
/// Gets the [GradleProject] for the current [FlutterProject] if built as a library.
Future
<
GradleProject
>
get
libraryProject
async
{
_cachedLibraryProject
??=
await
_readGradleProject
(
isLibrary:
true
);
return
_cachedLibraryProject
;
}
}
...
...
@@ -134,8 +133,7 @@ Future<File> getGradleAppOut(AndroidProject androidProject) async {
case
FlutterPluginVersion
.
managed
:
// Fall through. The managed plugin matches plugin v2 for now.
case
FlutterPluginVersion
.
v2
:
final
GradleProject
gradleProject
=
await
gradleUtils
.
getAppProject
(
FlutterProject
.
current
());
final
GradleProject
gradleProject
=
await
gradleUtils
.
appProject
;
return
fs
.
file
(
gradleProject
.
apkDirectory
.
childFile
(
'app.apk'
));
}
return
null
;
...
...
@@ -211,10 +209,8 @@ void createSettingsAarGradle(Directory androidDirectory) {
// Note: Dependencies are resolved and possibly downloaded as a side-effect
// of calculating the app properties using Gradle. This may take minutes.
Future
<
GradleProject
>
_readGradleProject
(
FlutterProject
flutterProject
,
{
bool
isLibrary
=
false
,
})
async
{
Future
<
GradleProject
>
_readGradleProject
({
bool
isLibrary
=
false
})
async
{
final
FlutterProject
flutterProject
=
FlutterProject
.
current
();
final
String
gradlew
=
await
gradleUtils
.
getExecutable
(
flutterProject
);
updateLocalProperties
(
project:
flutterProject
);
...
...
@@ -222,6 +218,10 @@ Future<GradleProject> _readGradleProject(
final
FlutterManifest
manifest
=
flutterProject
.
manifest
;
final
Directory
hostAppGradleRoot
=
flutterProject
.
android
.
hostAppGradleRoot
;
if
(
featureFlags
.
isPluginAsAarEnabled
&&
!
manifest
.
isPlugin
&&
!
manifest
.
isModule
)
{
createSettingsAarGradle
(
hostAppGradleRoot
);
}
if
(
manifest
.
isPlugin
)
{
assert
(
isLibrary
);
return
GradleProject
(
...
...
@@ -581,9 +581,9 @@ Future<void> buildGradleAar({
GradleProject
gradleProject
;
if
(
manifest
.
isModule
)
{
gradleProject
=
await
gradleUtils
.
getAppProject
(
project
)
;
gradleProject
=
await
gradleUtils
.
appProject
;
}
else
if
(
manifest
.
isPlugin
)
{
gradleProject
=
await
gradleUtils
.
getLibraryProject
(
project
)
;
gradleProject
=
await
gradleUtils
.
libraryProject
;
}
else
{
throwToolExit
(
'AARs can only be built for plugin or module projects.'
);
}
...
...
@@ -612,11 +612,13 @@ Future<void> buildGradleAar({
'-Pflutter-root=
$flutterRoot
'
,
'-Poutput-dir=
${gradleProject.buildDirectory}
'
,
'-Pis-plugin=
${manifest.isPlugin}
'
,
'-Dbuild-plugins-as-aars=true'
,
];
if
(
target
!=
null
&&
target
.
isNotEmpty
)
{
command
.
add
(
'-Ptarget=
$target
'
);
}
if
(
androidBuildInfo
.
targetArchs
.
isNotEmpty
)
{
final
String
targetPlatforms
=
androidBuildInfo
.
targetArchs
.
map
(
getPlatformNameForAndroidArch
).
join
(
','
);
...
...
@@ -631,30 +633,34 @@ Future<void> buildGradleAar({
command
.
add
(
aarTask
);
final
Stopwatch
sw
=
Stopwatch
()..
start
();
RunResult
result
;
int
exitCode
=
1
;
try
{
result
=
await
processUtils
.
run
(
exitCode
=
await
processUtils
.
stream
(
command
,
workingDirectory:
project
.
android
.
hostAppGradleRoot
.
path
,
allowReentrantFlutter:
true
,
environment:
gradleEnv
,
mapFunction:
(
String
line
)
{
// Always print the full line in verbose mode.
if
(
logger
.
isVerbose
)
{
return
line
;
}
return
null
;
},
);
}
finally
{
status
.
stop
();
}
flutterUsage
.
sendTiming
(
'build'
,
'gradle-aar'
,
sw
.
elapsed
);
flutterUsage
.
sendTiming
(
'build'
,
'gradle-aar'
,
Duration
(
milliseconds:
sw
.
elapsedMilliseconds
)
);
if
(
result
.
exitCode
!=
0
)
{
printStatus
(
result
.
stdout
,
wrap:
false
);
printError
(
result
.
stderr
,
wrap:
false
);
throwToolExit
(
'Gradle task
$aarTask
failed with exit code
$exitCode
.'
,
exitCode:
exitCode
);
if
(
exitCode
!=
0
)
{
throwToolExit
(
'Gradle task
$aarTask
failed with exit code
$exitCode
'
,
exitCode:
exitCode
);
}
final
Directory
repoDirectory
=
gradleProject
.
repoDirectory
;
if
(!
repoDirectory
.
existsSync
())
{
printStatus
(
result
.
stdout
,
wrap:
false
);
printError
(
result
.
stderr
,
wrap:
false
);
throwToolExit
(
'Gradle task
$aarTask
failed to produce
$repoDirectory
.'
,
exitCode:
exitCode
);
throwToolExit
(
'Gradle task
$aarTask
failed to produce
$repoDirectory
'
,
exitCode:
exitCode
);
}
printStatus
(
'Built
${fs.path.relative(repoDirectory.path)}
.'
,
color:
TerminalColor
.
green
);
}
...
...
@@ -724,33 +730,21 @@ Future<void> _buildGradleProjectV2(
FlutterProject
flutterProject
,
AndroidBuildInfo
androidBuildInfo
,
String
target
,
bool
isBuildingBundle
,
{
bool
shouldBuildPluginAsAar
=
false
,
})
async
{
bool
isBuildingBundle
,
)
async
{
final
String
gradlew
=
await
gradleUtils
.
getExecutable
(
flutterProject
);
final
GradleProject
gradleProject
=
await
gradleUtils
.
getAppProject
(
flutterProject
);
if
(
shouldBuildPluginAsAar
)
{
// Create a settings.gradle that doesn't import the plugins as subprojects.
createSettingsAarGradle
(
flutterProject
.
android
.
hostAppGradleRoot
);
await
buildPluginsAsAar
(
flutterProject
,
androidBuildInfo
,
buildDirectory:
gradleProject
.
buildDirectory
,
);
}
final
GradleProject
project
=
await
gradleUtils
.
appProject
;
final
BuildInfo
buildInfo
=
androidBuildInfo
.
buildInfo
;
String
assembleTask
;
if
(
isBuildingBundle
)
{
assembleTask
=
gradleP
roject
.
bundleTaskFor
(
buildInfo
);
assembleTask
=
p
roject
.
bundleTaskFor
(
buildInfo
);
}
else
{
assembleTask
=
gradleP
roject
.
assembleTaskFor
(
buildInfo
);
assembleTask
=
p
roject
.
assembleTaskFor
(
buildInfo
);
}
if
(
assembleTask
==
null
)
{
printUndefinedTask
(
gradleP
roject
,
buildInfo
);
printUndefinedTask
(
p
roject
,
buildInfo
);
throwToolExit
(
'Gradle build aborted.'
);
}
final
Status
status
=
logger
.
startProgress
(
...
...
@@ -797,12 +791,13 @@ Future<void> _buildGradleProjectV2(
.
map
(
getPlatformNameForAndroidArch
).
join
(
','
);
command
.
add
(
'-Ptarget-platform=
$targetPlatforms
'
);
}
if
(
shouldBuildPluginAsAar
)
{
if
(
featureFlags
.
isPluginAsAarEnabled
)
{
// Pass a system flag instead of a project flag, so this flag can be
// read from include_flutter.groovy.
command
.
add
(
'-Dbuild-plugins-as-aars=true'
);
// Don't use settings.gradle from the current project since it includes the plugins as subprojects.
command
.
add
(
'--settings-file=settings_aar.gradle'
);
if
(!
flutterProject
.
manifest
.
isModule
)
{
command
.
add
(
'--settings-file=settings_aar.gradle'
);
}
}
command
.
add
(
assembleTask
);
bool
potentialAndroidXFailure
=
false
;
...
...
@@ -849,60 +844,24 @@ Future<void> _buildGradleProjectV2(
printStatus
(
'To learn more, see: https://developer.android.com/studio/build/shrink-code'
,
indent:
4
);
BuildEvent
(
'r8-failure'
).
send
();
}
else
if
(
potentialAndroidXFailure
)
{
final
bool
hasPlugins
=
flutterProject
.
flutterPluginsFile
.
existsSync
();
final
bool
usesAndroidX
=
isAppUsingAndroidX
(
flutterProject
.
android
.
hostAppGradleRoot
);
if
(!
hasPlugins
)
{
// If the app doesn't use any plugin, then it's unclear where the incompatibility is coming from.
BuildEvent
(
'android-x-failure'
,
eventError:
'app-not-using-plugins'
).
send
();
}
if
(
hasPlugins
&&
!
usesAndroidX
)
{
// If the app isn't using AndroidX, then the app is likely using a plugin already migrated to AndroidX.
printStatus
(
'AndroidX incompatibilities may have caused this build to fail. '
);
printStatus
(
'Please migrate your app to AndroidX. See https://goo.gl/CP92wY.'
);
BuildEvent
(
'android-x-failure'
,
eventError:
'app-not-using-androidx'
).
send
();
}
if
(
hasPlugins
&&
usesAndroidX
&&
shouldBuildPluginAsAar
)
{
// This is a dependency conflict instead of an AndroidX failure since by this point
// the app is using AndroidX, the plugins are built as AARs, Jetifier translated
// Support libraries for AndroidX equivalents.
BuildEvent
(
'android-x-failure'
,
eventError:
'using-jetifier'
).
send
();
}
if
(
hasPlugins
&&
usesAndroidX
&&
!
shouldBuildPluginAsAar
)
{
printStatus
(
'The built failed likely due to AndroidX incompatibilities in a plugin. '
'The tool is about to try using Jetfier to solve the incompatibility.'
);
BuildEvent
(
'android-x-failure'
,
eventError:
'not-using-jetifier'
).
send
();
// The app is using Androidx, but Jetifier hasn't run yet.
// Call the current method again, build the plugins as AAR, so Jetifier can translate
// the dependencies.
// NOTE: Don't build the plugins as AARs by default since this drastically increases
// the build time.
await
_buildGradleProjectV2
(
flutterProject
,
androidBuildInfo
,
target
,
isBuildingBundle
,
shouldBuildPluginAsAar:
true
,
);
return
;
}
printStatus
(
'AndroidX incompatibilities may have caused this build to fail. See https://goo.gl/CP92wY.'
);
BuildEvent
(
'android-x-failure'
).
send
();
}
throwToolExit
(
'Gradle task
$assembleTask
failed with exit code
$exitCode
'
,
exitCode:
exitCode
);
}
flutterUsage
.
sendTiming
(
'build'
,
'gradle-v2'
,
Duration
(
milliseconds:
sw
.
elapsedMilliseconds
));
if
(!
isBuildingBundle
)
{
final
Iterable
<
File
>
apkFiles
=
findApkFiles
(
gradleP
roject
,
androidBuildInfo
);
final
Iterable
<
File
>
apkFiles
=
findApkFiles
(
p
roject
,
androidBuildInfo
);
if
(
apkFiles
.
isEmpty
)
{
throwToolExit
(
'Gradle build failed to produce an Android package.'
);
}
// Copy the first APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
// TODO(blasten): Handle multiple APKs.
apkFiles
.
first
.
copySync
(
gradleP
roject
.
apkDirectory
.
childFile
(
'app.apk'
).
path
);
apkFiles
.
first
.
copySync
(
p
roject
.
apkDirectory
.
childFile
(
'app.apk'
).
path
);
printTrace
(
'calculateSha:
${
gradleP
roject.apkDirectory}
/app.apk'
);
final
File
apkShaFile
=
gradleP
roject
.
apkDirectory
.
childFile
(
'app.apk.sha1'
);
printTrace
(
'calculateSha:
${
p
roject.apkDirectory}
/app.apk'
);
final
File
apkShaFile
=
p
roject
.
apkDirectory
.
childFile
(
'app.apk.sha1'
);
apkShaFile
.
writeAsStringSync
(
_calculateSha
(
apkFiles
.
first
));
for
(
File
apkFile
in
apkFiles
)
{
...
...
@@ -916,7 +875,7 @@ Future<void> _buildGradleProjectV2(
color:
TerminalColor
.
green
);
}
}
else
{
final
File
bundleFile
=
findBundleFile
(
gradleP
roject
,
buildInfo
);
final
File
bundleFile
=
findBundleFile
(
p
roject
,
buildInfo
);
if
(
bundleFile
==
null
)
{
throwToolExit
(
'Gradle build failed to produce an Android bundle package.'
);
}
...
...
@@ -932,61 +891,6 @@ Future<void> _buildGradleProjectV2(
}
}
/// Returns [true] if the current app uses AndroidX.
// TODO(egarciad): https://github.com/flutter/flutter/issues/40800
// Remove `FlutterManifest.usesAndroidX` and provide a unified `AndroidProject.usesAndroidX`.
@visibleForTesting
bool
isAppUsingAndroidX
(
Directory
androidDirectory
)
{
final
File
properties
=
androidDirectory
.
childFile
(
'gradle.properties'
);
if
(!
properties
.
existsSync
())
{
return
false
;
}
return
properties
.
readAsStringSync
().
contains
(
'android.useAndroidX=true'
);
}
/// Builds the plugins as AARs.
@visibleForTesting
Future
<
void
>
buildPluginsAsAar
(
FlutterProject
flutterProject
,
AndroidBuildInfo
androidBuildInfo
,
{
String
buildDirectory
,
})
async
{
final
File
flutterPluginFile
=
flutterProject
.
flutterPluginsFile
;
if
(!
flutterPluginFile
.
existsSync
())
{
return
;
}
final
List
<
String
>
plugins
=
flutterPluginFile
.
readAsStringSync
().
split
(
'
\n
'
);
for
(
String
plugin
in
plugins
)
{
final
List
<
String
>
pluginParts
=
plugin
.
split
(
'='
);
if
(
pluginParts
.
length
!=
2
)
{
continue
;
}
final
Directory
pluginDirectory
=
fs
.
directory
(
pluginParts
.
last
);
assert
(
pluginDirectory
.
existsSync
());
final
String
pluginName
=
pluginParts
.
first
;
logger
.
printStatus
(
'Building plugin
$pluginName
...'
);
try
{
await
buildGradleAar
(
project:
FlutterProject
.
fromDirectory
(
pluginDirectory
),
androidBuildInfo:
const
AndroidBuildInfo
(
BuildInfo
(
BuildMode
.
release
,
// Plugins are built as release.
null
,
// Plugins don't define flavors.
),
),
target:
''
,
outputDir:
buildDirectory
,
);
}
on
ToolExit
{
// Log the entire plugin entry in `.flutter-plugins` since it
// includes the plugin name and the version.
BuildEvent
(
'plugin-aar-failure'
,
eventError:
plugin
).
send
();
throwToolExit
(
'The plugin
$pluginName
could not be built due to the issue above. '
);
}
}
}
@visibleForTesting
Iterable
<
File
>
findApkFiles
(
GradleProject
project
,
AndroidBuildInfo
androidBuildInfo
)
{
final
Iterable
<
String
>
apkFileNames
=
project
.
apkFilesFor
(
androidBuildInfo
);
...
...
packages/flutter_tools/lib/src/features.dart
View file @
2c8813c8
...
...
@@ -36,6 +36,9 @@ class FeatureFlags {
/// Whether flutter desktop for Windows is enabled.
bool
get
isWindowsEnabled
=>
_isEnabled
(
flutterWindowsDesktopFeature
);
/// Whether plugins are built as AARs in app projects.
bool
get
isPluginAsAarEnabled
=>
_isEnabled
(
flutterBuildPluginAsAarFeature
);
// Calculate whether a particular feature is enabled for the current channel.
static
bool
_isEnabled
(
Feature
feature
)
{
final
String
currentChannel
=
FlutterVersion
.
instance
.
channel
;
...
...
packages/flutter_tools/lib/src/reporting/events.dart
View file @
2c8813c8
...
...
@@ -125,7 +125,6 @@ class BuildEvent extends UsageEvent {
BuildEvent
(
String
parameter
,
{
this
.
command
,
this
.
settings
,
this
.
eventError
,
})
:
super
(
'build'
+
(
FlutterCommand
.
current
==
null
?
''
:
'-
${FlutterCommand.current.name}
'
),
...
...
@@ -133,7 +132,6 @@ class BuildEvent extends UsageEvent {
final
String
command
;
final
String
settings
;
final
String
eventError
;
@override
void
send
()
{
...
...
@@ -142,8 +140,6 @@ class BuildEvent extends UsageEvent {
CustomDimensions
.
buildEventCommand
:
command
,
if
(
settings
!=
null
)
CustomDimensions
.
buildEventSettings
:
settings
,
if
(
eventError
!=
null
)
CustomDimensions
.
buildEventError
:
eventError
,
});
flutterUsage
.
sendEvent
(
category
,
parameter
,
parameters:
parameters
);
}
...
...
packages/flutter_tools/lib/src/reporting/usage.dart
View file @
2c8813c8
...
...
@@ -53,7 +53,6 @@ enum CustomDimensions {
commandBuildApkSplitPerAbi
,
// cd40
commandBuildAppBundleTargetPlatform
,
// cd41
commandBuildAppBundleBuildMode
,
// cd42
buildEventError
,
// cd43
}
String
cdKey
(
CustomDimensions
cd
)
=>
'cd
${cd.index + 1}
'
;
...
...
packages/flutter_tools/test/general.shard/android/gradle_test.dart
View file @
2c8813c8
...
...
@@ -25,6 +25,7 @@ import 'package:process/process.dart';
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/mocks.dart'
;
import
'../../src/pubspec_schema.dart'
;
void
main
(
)
{
...
...
@@ -1154,153 +1155,6 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
});
});
group
(
'isAppUsingAndroidX'
,
()
{
FileSystem
fs
;
setUp
(()
{
fs
=
MemoryFileSystem
();
});
testUsingContext
(
'returns true when the project is using AndroidX'
,
()
async
{
final
Directory
androidDirectory
=
fs
.
systemTempDirectory
.
createTempSync
(
'android.'
);
androidDirectory
.
childFile
(
'gradle.properties'
)
.
writeAsStringSync
(
'android.useAndroidX=true'
);
expect
(
isAppUsingAndroidX
(
androidDirectory
),
isTrue
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
});
testUsingContext
(
'returns false when the project is not using AndroidX'
,
()
async
{
final
Directory
androidDirectory
=
fs
.
systemTempDirectory
.
createTempSync
(
'android.'
);
androidDirectory
.
childFile
(
'gradle.properties'
)
.
writeAsStringSync
(
'android.useAndroidX=false'
);
expect
(
isAppUsingAndroidX
(
androidDirectory
),
isFalse
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
});
testUsingContext
(
'returns false when gradle.properties does not exist'
,
()
async
{
final
Directory
androidDirectory
=
fs
.
systemTempDirectory
.
createTempSync
(
'android.'
);
expect
(
isAppUsingAndroidX
(
androidDirectory
),
isFalse
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
});
});
group
(
'buildPluginsAsAar'
,
()
{
FileSystem
fs
;
MockProcessManager
mockProcessManager
;
MockAndroidSdk
mockAndroidSdk
;
setUp
(()
{
fs
=
MemoryFileSystem
();
mockProcessManager
=
MockProcessManager
();
when
(
mockProcessManager
.
run
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenAnswer
((
_
)
async
=>
ProcessResult
(
1
,
0
,
''
,
''
));
mockAndroidSdk
=
MockAndroidSdk
();
when
(
mockAndroidSdk
.
directory
).
thenReturn
(
'irrelevant'
);
});
testUsingContext
(
'calls gradle'
,
()
async
{
final
Directory
androidDirectory
=
fs
.
directory
(
'android.'
);
androidDirectory
.
createSync
();
androidDirectory
.
childFile
(
'pubspec.yaml'
)
.
writeAsStringSync
(
'name: irrelevant'
);
final
Directory
plugin1
=
fs
.
directory
(
'plugin1.'
);
plugin1
..
createSync
()
..
childFile
(
'pubspec.yaml'
)
.
writeAsStringSync
(
'''
name: irrelevant
flutter:
plugin:
androidPackage: irrelevant
'''
);
final
Directory
plugin2
=
fs
.
directory
(
'plugin2.'
);
plugin2
..
createSync
()
..
childFile
(
'pubspec.yaml'
)
.
writeAsStringSync
(
'''
name: irrelevant
flutter:
plugin:
androidPackage: irrelevant
'''
);
androidDirectory
.
childFile
(
'.flutter-plugins'
)
.
writeAsStringSync
(
'''
plugin1=
${plugin1.path}
plugin2=
${plugin2.path}
'''
);
final
Directory
buildDirectory
=
androidDirectory
.
childDirectory
(
'build'
);
buildDirectory
.
childDirectory
(
'outputs'
)
.
childDirectory
(
'repo'
)
.
createSync
(
recursive:
true
);
await
buildPluginsAsAar
(
FlutterProject
.
fromPath
(
androidDirectory
.
path
),
const
AndroidBuildInfo
(
BuildInfo
.
release
),
buildDirectory:
buildDirectory
.
path
,
);
final
String
flutterRoot
=
fs
.
path
.
absolute
(
Cache
.
flutterRoot
);
final
String
initScript
=
fs
.
path
.
join
(
flutterRoot
,
'packages'
,
'flutter_tools'
,
'gradle'
,
'aar_init_script.gradle'
);
verify
(
mockProcessManager
.
run
(
<
String
>[
'gradlew'
,
'-I=
$initScript
'
,
'-Pflutter-root=
$flutterRoot
'
,
'-Poutput-dir=
${buildDirectory.path}
'
,
'-Pis-plugin=true'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'assembleAarRelease'
,
],
environment:
anyNamed
(
'environment'
),
workingDirectory:
plugin1
.
childDirectory
(
'android'
).
path
),
).
called
(
1
);
verify
(
mockProcessManager
.
run
(
<
String
>[
'gradlew'
,
'-I=
$initScript
'
,
'-Pflutter-root=
$flutterRoot
'
,
'-Poutput-dir=
${buildDirectory.path}
'
,
'-Pis-plugin=true'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'assembleAarRelease'
,
],
environment:
anyNamed
(
'environment'
),
workingDirectory:
plugin2
.
childDirectory
(
'android'
).
path
),
).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
FileSystem:
()
=>
fs
,
GradleUtils:
()
=>
FakeGradleUtils
(),
ProcessManager:
()
=>
mockProcessManager
,
});
});
group
(
'gradle build'
,
()
{
MockAndroidSdk
mockAndroidSdk
;
MockAndroidStudio
mockAndroidStudio
;
...
...
@@ -1381,13 +1235,11 @@ plugin2=${plugin2.path}
fs
.
currentDirectory
=
'path/to/project'
;
// Let any process start. Assert after.
when
(
mockProcessManager
.
run
(
when
(
mockProcessManager
.
start
(
any
,
environment:
anyNamed
(
'environment'
),
workingDirectory:
anyNamed
(
'workingDirectory'
))
).
thenAnswer
(
(
_
)
async
=>
ProcessResult
(
1
,
0
,
''
,
''
),
);
).
thenAnswer
((
Invocation
invocation
)
=>
Future
<
Process
>.
value
(
MockProcess
()));
fs
.
directory
(
'build/outputs/repo'
).
createSync
(
recursive:
true
);
await
buildGradleAar
(
...
...
@@ -1397,11 +1249,11 @@ plugin2=${plugin2.path}
target:
''
);
final
List
<
String
>
actualGradlewCall
=
verify
(
mockProcessManager
.
run
(
final
List
<
String
>
actualGradlewCall
=
verify
(
mockProcessManager
.
start
(
captureAny
,
environment:
anyNamed
(
'environment'
),
workingDirectory:
anyNamed
(
'workingDirectory'
)),
).
captured
.
last
;
).
captured
.
single
;
expect
(
actualGradlewCall
,
contains
(
'/path/to/project/.android/gradlew'
));
expect
(
actualGradlewCall
,
contains
(
'-PlocalEngineOut=out/android_arm'
));
...
...
@@ -1432,14 +1284,6 @@ Platform fakePlatform(String name) {
return
FakePlatform
.
fromPlatform
(
const
LocalPlatform
())..
operatingSystem
=
name
;
}
class
FakeGradleUtils
extends
GradleUtils
{
@override
Future
<
String
>
getExecutable
(
FlutterProject
project
)
async
{
return
'gradlew'
;
}
}
class
MockAndroidSdk
extends
Mock
implements
AndroidSdk
{}
class
MockAndroidStudio
extends
Mock
implements
AndroidStudio
{}
class
MockDirectory
extends
Mock
implements
Directory
{}
class
MockFile
extends
Mock
implements
File
{}
...
...
packages/flutter_tools/test/general.shard/features_test.dart
View file @
2c8813c8
...
...
@@ -432,6 +432,21 @@ void main() {
expect
(
featureFlags
.
isWindowsEnabled
,
false
);
}));
/// Plugins as AARS
test
(
'plugins built as AARs with config on master'
,
()
=>
testbed
.
run
(()
{
when
(
mockFlutterVerion
.
channel
).
thenReturn
(
'master'
);
when
<
bool
>(
mockFlutterConfig
.
getValue
(
'enable-build-plugin-as-aar'
)).
thenReturn
(
false
);
expect
(
featureFlags
.
isPluginAsAarEnabled
,
false
);
}));
test
(
'plugins built as AARs with config on dev'
,
()
=>
testbed
.
run
(()
{
when
(
mockFlutterVerion
.
channel
).
thenReturn
(
'dev'
);
when
<
bool
>(
mockFlutterConfig
.
getValue
(
'enable-build-plugin-as-aar'
)).
thenReturn
(
false
);
expect
(
featureFlags
.
isPluginAsAarEnabled
,
false
);
}));
});
}
...
...
packages/flutter_tools/test/src/testbed.dart
View file @
2c8813c8
...
...
@@ -693,6 +693,7 @@ class TestFeatureFlags implements FeatureFlags {
this
.
isMacOSEnabled
=
false
,
this
.
isWebEnabled
=
false
,
this
.
isWindowsEnabled
=
false
,
this
.
isPluginAsAarEnabled
=
false
,
});
@override
...
...
@@ -706,4 +707,7 @@ class TestFeatureFlags implements FeatureFlags {
@override
final
bool
isWindowsEnabled
;
@override
final
bool
isPluginAsAarEnabled
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment