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
da90156f
Unverified
Commit
da90156f
authored
Jan 13, 2021
by
Emmanuel Garcia
Committed by
GitHub
Jan 13, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix plugin java class desugar (#73758)
parent
49667ba2
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
117 additions
and
63 deletions
+117
-63
gradle_desugar_classes_test.dart
dev/devicelab/bin/tasks/gradle_desugar_classes_test.dart
+44
-0
apk_utils.dart
dev/devicelab/lib/framework/apk_utils.dart
+32
-18
utils.dart
dev/devicelab/lib/framework/utils.dart
+2
-0
flutter.gradle
packages/flutter_tools/gradle/flutter.gradle
+39
-45
No files found.
dev/devicelab/bin/tasks/gradle_desugar_classes_test.dart
0 → 100644
View file @
da90156f
// Copyright 2014 The Flutter 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:io'
;
import
'package:flutter_devicelab/framework/apk_utils.dart'
;
import
'package:flutter_devicelab/framework/framework.dart'
;
import
'package:flutter_devicelab/framework/task_result.dart'
;
import
'package:flutter_devicelab/framework/utils.dart'
;
Future
<
void
>
main
()
async
{
await
task
(()
async
{
try
{
await
runProjectTest
((
FlutterProject
flutterProject
)
async
{
section
(
'APK contains plugin classes'
);
flutterProject
.
addPlugin
(
'google_maps_flutter'
,
value:
'^1.0.10'
);
await
inDirectory
(
flutterProject
.
rootPath
,
()
async
{
await
flutter
(
'build'
,
options:
<
String
>[
'apk'
,
'--debug'
,
'--target-platform=android-arm'
,
]);
final
File
apk
=
File
(
'
${flutterProject.rootPath}
/build/app/outputs/flutter-apk/app-debug.apk'
);
if
(!
apk
.
existsSync
())
{
throw
TaskResult
.
failure
(
'Expected
${apk.path}
to exist, but it doesn
\'
t'
);
}
// https://github.com/flutter/flutter/issues/72185
await
checkApkContainsMethods
(
apk
,
<
String
>[
'io.flutter.plugins.googlemaps.GoogleMapController void onFlutterViewAttached(android.view.View)'
,
'io.flutter.plugins.googlemaps.GoogleMapController void onFlutterViewDetached()'
,
]);
});
});
return
TaskResult
.
success
(
null
);
}
on
TaskResult
catch
(
taskResult
)
{
return
taskResult
;
}
catch
(
e
)
{
return
TaskResult
.
failure
(
e
.
toString
());
}
});
}
dev/devicelab/lib/framework/apk_utils.dart
View file @
da90156f
...
@@ -115,12 +115,14 @@ String get _androidHome {
...
@@ -115,12 +115,14 @@ String get _androidHome {
/// Executes an APK analyzer subcommand.
/// Executes an APK analyzer subcommand.
Future
<
String
>
_evalApkAnalyzer
(
Future
<
String
>
_evalApkAnalyzer
(
List
<
String
>
args
,
{
List
<
String
>
args
,
{
bool
printStdout
=
tru
e
,
bool
printStdout
=
fals
e
,
String
workingDirectory
,
String
workingDirectory
,
})
async
{
})
async
{
final
String
javaHome
=
await
findJavaHome
();
final
String
javaHome
=
await
findJavaHome
();
if
(
javaHome
==
null
||
javaHome
.
isEmpty
)
{
final
String
apkAnalyzer
=
path
throw
Exception
(
'No JAVA_HOME set.'
);
}
final
String
apkAnalyzer
=
path
.
join
(
_androidHome
,
'cmdline-tools'
,
'latest'
,
'bin'
,
Platform
.
isWindows
?
'apkanalyzer.bat'
:
'apkanalyzer'
);
.
join
(
_androidHome
,
'cmdline-tools'
,
'latest'
,
'bin'
,
Platform
.
isWindows
?
'apkanalyzer.bat'
:
'apkanalyzer'
);
if
(
canRun
(
apkAnalyzer
))
{
if
(
canRun
(
apkAnalyzer
))
{
return
eval
(
return
eval
(
...
@@ -165,6 +167,7 @@ class ApkExtractor {
...
@@ -165,6 +167,7 @@ class ApkExtractor {
bool
_extracted
=
false
;
bool
_extracted
=
false
;
Set
<
String
>
_classes
=
const
<
String
>{};
Set
<
String
>
_classes
=
const
<
String
>{};
Set
<
String
>
_methods
=
const
<
String
>{};
Future
<
void
>
_extractDex
()
async
{
Future
<
void
>
_extractDex
()
async
{
if
(
_extracted
)
{
if
(
_extracted
)
{
...
@@ -177,22 +180,17 @@ class ApkExtractor {
...
@@ -177,22 +180,17 @@ class ApkExtractor {
apkFile
.
path
,
apkFile
.
path
,
],
],
);
);
final
List
<
String
>
lines
=
packages
.
split
(
'
\n
'
);
_classes
=
Set
<
String
>.
from
(
_classes
=
Set
<
String
>.
from
(
packages
lines
.
where
((
String
line
)
=>
line
.
startsWith
(
'C'
))
.
split
(
'
\n
'
)
.
map
<
String
>((
String
line
)
=>
line
.
split
(
'
\t
'
).
last
),
.
where
((
String
line
)
=>
line
.
startsWith
(
'C'
))
.
map
<
String
>((
String
line
)
=>
line
.
split
(
'
\t
'
).
last
),
);
);
assert
(
_classes
.
isNotEmpty
);
assert
(
_classes
.
isNotEmpty
);
_extracted
=
true
;
_methods
=
Set
<
String
>.
from
(
}
lines
.
where
((
String
line
)
=>
line
.
startsWith
(
'M'
))
.
map
<
String
>((
String
line
)
=>
line
.
split
(
'
\t
'
).
last
)
// Removes any temporary directory.
);
void
dispose
()
{
assert
(
_methods
.
isNotEmpty
);
if
(!
_extracted
)
{
return
;
}
_classes
=
const
<
String
>{};
_extracted
=
true
;
_extracted
=
true
;
}
}
...
@@ -201,6 +199,13 @@ class ApkExtractor {
...
@@ -201,6 +199,13 @@ class ApkExtractor {
await
_extractDex
();
await
_extractDex
();
return
_classes
.
contains
(
className
);
return
_classes
.
contains
(
className
);
}
}
/// Returns true if the APK contains a given method.
/// For example: io.flutter.plugins.googlemaps.GoogleMapController void onFlutterViewAttached(android.view.View)
Future
<
bool
>
containsMethod
(
String
methodName
)
async
{
await
_extractDex
();
return
_methods
.
contains
(
methodName
);
}
}
}
/// Gets the content of the `AndroidManifest.xml`.
/// Gets the content of the `AndroidManifest.xml`.
...
@@ -223,7 +228,16 @@ Future<void> checkApkContainsClasses(File apk, List<String> classes) async {
...
@@ -223,7 +228,16 @@ Future<void> checkApkContainsClasses(File apk, List<String> classes) async {
throw
Exception
(
"APK doesn't contain class `
$className
`."
);
throw
Exception
(
"APK doesn't contain class `
$className
`."
);
}
}
}
}
extractor
.
dispose
();
}
/// Checks that the methods are defined in the APK, throws otherwise.
Future
<
void
>
checkApkContainsMethods
(
File
apk
,
List
<
String
>
methods
)
async
{
final
ApkExtractor
extractor
=
ApkExtractor
(
apk
);
for
(
final
String
method
in
methods
)
{
if
(!(
await
extractor
.
containsMethod
(
method
)))
{
throw
Exception
(
"APK doesn't contain method `
$method
`."
);
}
}
}
}
class
FlutterProject
{
class
FlutterProject
{
...
@@ -288,7 +302,7 @@ subprojects {
...
@@ -288,7 +302,7 @@ subprojects {
String
content
=
await
pubspec
.
readAsString
();
String
content
=
await
pubspec
.
readAsString
();
content
=
content
.
replaceFirst
(
content
=
content
.
replaceFirst
(
'
${platformLineSep}
dependencies:
$platformLineSep
'
,
'
${platformLineSep}
dependencies:
$platformLineSep
'
,
'
${platformLineSep}
dependencies:
$platformLineSep
$plugin
:
$value$platformLineSep
'
,
'
${platformLineSep}
dependencies:
$platformLineSep
$plugin
:
$value$platformLineSep
'
,
);
);
await
pubspec
.
writeAsString
(
content
,
flush:
true
);
await
pubspec
.
writeAsString
(
content
,
flush:
true
);
}
}
...
...
dev/devicelab/lib/framework/utils.dart
View file @
da90156f
...
@@ -456,6 +456,8 @@ List<String> flutterCommandArgs(String command, List<String> options) {
...
@@ -456,6 +456,8 @@ List<String> flutterCommandArgs(String command, List<String> options) {
];
];
}
}
/// Runs the flutter `command`, and returns the exit code.
/// If `canFail` is `false`, the future completes with an error.
Future
<
int
>
flutter
(
String
command
,
{
Future
<
int
>
flutter
(
String
command
,
{
List
<
String
>
options
=
const
<
String
>[],
List
<
String
>
options
=
const
<
String
>[],
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
...
...
packages/flutter_tools/gradle/flutter.gradle
View file @
da90156f
...
@@ -101,6 +101,19 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -101,6 +101,19 @@ class FlutterPlugin implements Plugin<Project> {
void
apply
(
Project
project
)
{
void
apply
(
Project
project
)
{
this
.
project
=
project
this
.
project
=
project
// Configure the Maven repository.
String
hostedRepository
=
System
.
env
.
FLUTTER_STORAGE_BASE_URL
?:
DEFAULT_MAVEN_HOST
String
repository
=
useLocalEngine
()
?
project
.
property
(
'local-engine-repo'
)
:
"$hostedRepository/download.flutter.io"
project
.
rootProject
.
allprojects
{
repositories
{
maven
{
url
repository
}
}
}
project
.
extensions
.
create
(
"flutter"
,
FlutterExtension
)
project
.
extensions
.
create
(
"flutter"
,
FlutterExtension
)
this
.
addFlutterTasks
(
project
)
this
.
addFlutterTasks
(
project
)
...
@@ -184,8 +197,7 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -184,8 +197,7 @@ class FlutterPlugin implements Plugin<Project> {
localEngine
=
engineOut
.
name
localEngine
=
engineOut
.
name
localEngineSrcPath
=
engineOut
.
parentFile
.
parent
localEngineSrcPath
=
engineOut
.
parentFile
.
parent
}
}
project
.
android
.
buildTypes
.
each
this
.&
addFlutterDependencies
project
.
android
.
buildTypes
.
all
this
.&
addFlutterDependencies
project
.
android
.
buildTypes
.
whenObjectAdded
this
.&
addFlutterDependencies
}
}
/**
/**
...
@@ -199,21 +211,16 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -199,21 +211,16 @@ class FlutterPlugin implements Plugin<Project> {
if
(!
supportsBuildMode
(
flutterBuildMode
))
{
if
(!
supportsBuildMode
(
flutterBuildMode
))
{
return
return
}
}
String
hostedRepository
=
System
.
env
.
FLUTTER_STORAGE_BASE_URL
?:
DEFAULT_MAVEN_HOST
// The embedding is set as an API dependency in a Flutter plugin.
String
repository
=
useLocalEngine
()
// Therefore, don't make the app project depend on the embedding if there are Flutter
?
project
.
property
(
'local-engine-repo'
)
// plugins.
:
"$hostedRepository/download.flutter.io"
// This prevents duplicated classes when using custom build types. That is, a custom build
project
.
rootProject
.
allprojects
{
// type like profile is used, and the plugin and app projects have API dependencies on the
repositories
{
// embedding.
maven
{
if
(!
isFlutterAppProject
()
||
getPluginList
().
size
()
==
0
)
{
url
repository
addApiDependencies
(
project
,
buildType
.
name
,
}
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
)
}
}
}
// Add the embedding dependency.
addApiDependencies
(
project
,
buildType
.
name
,
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
)
List
<
String
>
platforms
=
getTargetPlatforms
().
collect
()
List
<
String
>
platforms
=
getTargetPlatforms
().
collect
()
// Debug mode includes x86 and x64, which are commonly used in emulators.
// Debug mode includes x86 and x64, which are commonly used in emulators.
if
(
flutterBuildMode
==
"debug"
&&
!
useLocalEngine
())
{
if
(
flutterBuildMode
==
"debug"
&&
!
useLocalEngine
())
{
...
@@ -303,7 +310,7 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -303,7 +310,7 @@ class FlutterPlugin implements Plugin<Project> {
}
}
// Add plugin dependency to the app project.
// Add plugin dependency to the app project.
project
.
dependencies
{
project
.
dependencies
{
implementation
pluginProject
api
pluginProject
}
}
Closure
addEmbeddingDependencyToPlugin
=
{
buildType
->
Closure
addEmbeddingDependencyToPlugin
=
{
buildType
->
String
flutterBuildMode
=
buildModeFor
(
buildType
)
String
flutterBuildMode
=
buildModeFor
(
buildType
)
...
@@ -318,39 +325,23 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -318,39 +325,23 @@ class FlutterPlugin implements Plugin<Project> {
pluginProject
.
android
.
buildTypes
{
pluginProject
.
android
.
buildTypes
{
"${buildType.name}"
{}
"${buildType.name}"
{}
}
}
// The embedding is
a compileOnly dependency of a Flutter plugin,
// The embedding is
API dependency of the plugin, so the AGP is able to desugar
//
however prior to Gradle 6.0.0, it must be an API dependency
.
//
default method implementations when the interface is implemented by a plugin
.
//
//
// Not doing so, causes transitive dependency resolution conflicts.
// See https://issuetracker.google.com/139821726, and
// That is, the embedding dependencies resolved in the plugin are
// https://github.com/flutter/flutter/issues/72185 for more details.
// different than the ones resolved in the app.
addApiDependencies
(
if
(
isGradleVersionGraterOrEqualThan
(
'6.0.0'
))
{
pluginProject
,
addCompileOnlyDependency
(
buildType
.
name
,
pluginProject
,
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
buildType
.
name
,
)
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
)
}
else
{
addApiDependencies
(
pluginProject
,
buildType
.
name
,
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
)
}
}
}
// Wait until the Android plugin loaded.
// Wait until the Android plugin loaded.
pluginProject
.
afterEvaluate
{
pluginProject
.
afterEvaluate
{
project
.
android
.
buildTypes
.
each
addEmbeddingDependencyToPlugin
project
.
android
.
buildTypes
.
all
addEmbeddingDependencyToPlugin
project
.
android
.
buildTypes
.
whenObjectAdded
addEmbeddingDependencyToPlugin
}
}
}
}
// Returns `true` if the current Gradle version is greater or equal to the given version.
private
isGradleVersionGraterOrEqualThan
(
String
version
)
{
return
VersionNumber
.
parse
(
project
.
gradle
.
gradleVersion
)
.
compareTo
(
VersionNumber
.
parse
(
version
))
>=
0
}
// Returns `true` if the given path contains an `android/build.gradle` file.
// Returns `true` if the given path contains an `android/build.gradle` file.
//
//
// TODO(egarciad): Fix https://github.com/flutter/flutter/issues/39657.
// TODO(egarciad): Fix https://github.com/flutter/flutter/issues/39657.
...
@@ -659,6 +650,10 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -659,6 +650,10 @@ class FlutterPlugin implements Plugin<Project> {
return
variant
.
hasProperty
(
"assembleProvider"
)
?
variant
.
assembleProvider
.
get
()
:
variant
.
assemble
return
variant
.
hasProperty
(
"assembleProvider"
)
?
variant
.
assembleProvider
.
get
()
:
variant
.
assemble
}
}
private
boolean
isFlutterAppProject
()
{
return
project
.
android
.
hasProperty
(
"applicationVariants"
)
}
private
void
addFlutterTasks
(
Project
project
)
{
private
void
addFlutterTasks
(
Project
project
)
{
if
(
project
.
state
.
failure
)
{
if
(
project
.
state
.
failure
)
{
return
return
...
@@ -816,8 +811,7 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -816,8 +811,7 @@ class FlutterPlugin implements Plugin<Project> {
}
}
return
copyFlutterAssetsTask
return
copyFlutterAssetsTask
}
}
boolean
isFlutterAppProject
=
project
.
android
.
hasProperty
(
"applicationVariants"
)
if
(
isFlutterAppProject
())
{
if
(
isFlutterAppProject
)
{
project
.
android
.
applicationVariants
.
all
{
variant
->
project
.
android
.
applicationVariants
.
all
{
variant
->
Task
assembleTask
=
getAssembleTask
(
variant
)
Task
assembleTask
=
getAssembleTask
(
variant
)
if
(!
shouldConfigureFlutterTask
(
assembleTask
))
{
if
(!
shouldConfigureFlutterTask
(
assembleTask
))
{
...
...
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