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
b7d48062
Unverified
Commit
b7d48062
authored
Feb 19, 2021
by
Emmanuel Garcia
Committed by
GitHub
Feb 19, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement dartPluginClass support for plugins (#74469)
parent
d9fca66a
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1466 additions
and
21 deletions
+1466
-21
dart_plugin_registry_test.dart
dev/devicelab/bin/tasks/dart_plugin_registry_test.dart
+10
-0
dart_plugin_registry_tests.dart
dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart
+181
-0
build_system.dart
...ages/flutter_tools/lib/src/build_system/build_system.dart
+10
-0
common.dart
...es/flutter_tools/lib/src/build_system/targets/common.dart
+2
-0
bundle.dart
packages/flutter_tools/lib/src/bundle.dart
+1
-0
assemble.dart
packages/flutter_tools/lib/src/commands/assemble.dart
+2
-1
build_ios_framework.dart
...s/flutter_tools/lib/src/commands/build_ios_framework.dart
+1
-0
packages.dart
packages/flutter_tools/lib/src/commands/packages.dart
+2
-0
compile.dart
packages/flutter_tools/lib/src/compile.dart
+21
-2
devfs.dart
packages/flutter_tools/lib/src/devfs.dart
+14
-0
flutter_manifest.dart
packages/flutter_tools/lib/src/flutter_manifest.dart
+7
-0
platform_plugins.dart
packages/flutter_tools/lib/src/platform_plugins.dart
+29
-8
plugins.dart
packages/flutter_tools/lib/src/plugins.dart
+344
-9
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+1
-0
run_hot.dart
packages/flutter_tools/lib/src/run_hot.dart
+11
-1
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+1
-0
compile.dart
packages/flutter_tools/lib/src/web/compile.dart
+2
-0
deferred_components_setup_validator_test.dart
...ard/android/deferred_components_setup_validator_test.dart
+1
-0
plugin_parsing_test.dart
...flutter_tools/test/general.shard/plugin_parsing_test.dart
+33
-0
plugins_test.dart
packages/flutter_tools/test/general.shard/plugins_test.dart
+772
-0
project_test.dart
packages/flutter_tools/test/general.shard/project_test.dart
+21
-0
No files found.
dev/devicelab/bin/tasks/dart_plugin_registry_test.dart
0 → 100644
View file @
b7d48062
// 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
'package:flutter_devicelab/tasks/dart_plugin_registry_tests.dart'
;
import
'package:flutter_devicelab/framework/framework.dart'
;
Future
<
void
>
main
()
async
{
await
task
(
dartPluginRegistryTest
());
}
dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart
0 → 100644
View file @
b7d48062
// 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:async'
;
import
'dart:convert'
;
import
'dart:io'
;
import
'package:path/path.dart'
as
path
;
import
'package:flutter_devicelab/framework/framework.dart'
;
import
'package:flutter_devicelab/framework/task_result.dart'
;
import
'package:flutter_devicelab/framework/utils.dart'
;
TaskFunction
dartPluginRegistryTest
(
{
String
deviceIdOverride
,
Map
<
String
,
String
>
environment
,
})
{
final
Directory
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_devicelab_dart_plugin_test.'
);
return
()
async
{
try
{
section
(
'Create implementation plugin'
);
await
inDirectory
(
tempDir
,
()
async
{
await
flutter
(
'create'
,
options:
<
String
>[
'--template=plugin'
,
'--org'
,
'io.flutter.devicelab'
,
'--platforms'
,
'macos'
,
'plugin_platform_implementation'
,
],
environment:
environment
,
);
});
final
File
pluginMain
=
File
(
path
.
join
(
tempDir
.
absolute
.
path
,
'plugin_platform_implementation'
,
'lib'
,
'plugin_platform_implementation.dart'
,
));
if
(!
pluginMain
.
existsSync
())
{
return
TaskResult
.
failure
(
'
${pluginMain.path}
does not exist'
);
}
// Patch plugin main dart file.
await
pluginMain
.
writeAsString
(
'''
class PluginPlatformInterfaceMacOS {
static void registerWith() {
print('
PluginPlatformInterfaceMacOS
.
registerWith
()
was
called
');
}
}
'''
,
flush:
true
);
// Patch plugin main pubspec file.
final
File
pluginImplPubspec
=
File
(
path
.
join
(
tempDir
.
absolute
.
path
,
'plugin_platform_implementation'
,
'pubspec.yaml'
,
));
String
pluginImplPubspecContent
=
await
pluginImplPubspec
.
readAsString
();
pluginImplPubspecContent
=
pluginImplPubspecContent
.
replaceFirst
(
' pluginClass: PluginPlatformImplementationPlugin'
,
' pluginClass: PluginPlatformImplementationPlugin
\n
'
' dartPluginClass: PluginPlatformInterfaceMacOS
\n
'
,
);
pluginImplPubspecContent
=
pluginImplPubspecContent
.
replaceFirst
(
' platforms:
\n
'
,
' implements: plugin_platform_interface
\n
'
' platforms:
\n
'
);
await
pluginImplPubspec
.
writeAsString
(
pluginImplPubspecContent
,
flush:
true
);
section
(
'Create interface plugin'
);
await
inDirectory
(
tempDir
,
()
async
{
await
flutter
(
'create'
,
options:
<
String
>[
'--template=plugin'
,
'--org'
,
'io.flutter.devicelab'
,
'--platforms'
,
'macos'
,
'plugin_platform_interface'
,
],
environment:
environment
,
);
});
final
File
pluginInterfacePubspec
=
File
(
path
.
join
(
tempDir
.
absolute
.
path
,
'plugin_platform_interface'
,
'pubspec.yaml'
,
));
String
pluginInterfacePubspecContent
=
await
pluginInterfacePubspec
.
readAsString
();
pluginInterfacePubspecContent
=
pluginInterfacePubspecContent
.
replaceFirst
(
' pluginClass: PluginPlatformInterfacePlugin'
,
' default_package: plugin_platform_implementation
\n
'
);
pluginInterfacePubspecContent
=
pluginInterfacePubspecContent
.
replaceFirst
(
'dependencies:'
,
'dependencies:
\n
'
' plugin_platform_implementation:
\n
'
' path: ../plugin_platform_implementation
\n
'
);
await
pluginInterfacePubspec
.
writeAsString
(
pluginInterfacePubspecContent
,
flush:
true
);
section
(
'Create app'
);
await
inDirectory
(
tempDir
,
()
async
{
await
flutter
(
'create'
,
options:
<
String
>[
'--template=app'
,
'--org'
,
'io.flutter.devicelab'
,
'--platforms'
,
'macos'
,
'app'
,
],
environment:
environment
,
);
});
final
File
appPubspec
=
File
(
path
.
join
(
tempDir
.
absolute
.
path
,
'app'
,
'pubspec.yaml'
,
));
String
appPubspecContent
=
await
appPubspec
.
readAsString
();
appPubspecContent
=
appPubspecContent
.
replaceFirst
(
'dependencies:'
,
'dependencies:
\n
'
' plugin_platform_interface:
\n
'
' path: ../plugin_platform_interface
\n
'
);
await
appPubspec
.
writeAsString
(
appPubspecContent
,
flush:
true
);
section
(
'Flutter run for macos'
);
await
inDirectory
(
path
.
join
(
tempDir
.
path
,
'app'
),
()
async
{
final
Process
run
=
await
startProcess
(
path
.
join
(
flutterDirectory
.
path
,
'bin'
,
'flutter'
),
flutterCommandArgs
(
'run'
,
<
String
>[
'-d'
,
'macos'
,
'-v'
]),
environment:
null
,
);
Completer
<
void
>
registryExecutedCompleter
=
Completer
<
void
>();
final
StreamSubscription
<
void
>
subscription
=
run
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
if
(
line
.
contains
(
'PluginPlatformInterfaceMacOS.registerWith() was called'
))
{
registryExecutedCompleter
.
complete
();
}
print
(
'stdout:
$line
'
);
});
section
(
'Wait for registry execution'
);
await
registryExecutedCompleter
.
future
.
timeout
(
const
Duration
(
minutes:
1
));
// Hot restart.
run
.
stdin
.
write
(
'R'
);
registryExecutedCompleter
=
Completer
<
void
>();
section
(
'Wait for registry execution after hot restart'
);
await
registryExecutedCompleter
.
future
.
timeout
(
const
Duration
(
minutes:
1
));
subscription
.
cancel
();
run
.
kill
();
});
return
TaskResult
.
success
(
null
);
}
finally
{
rmTree
(
tempDir
);
}
};
}
packages/flutter_tools/lib/src/build_system/build_system.dart
View file @
b7d48062
...
...
@@ -308,6 +308,7 @@ class Environment {
@required
Artifacts
artifacts
,
@required
ProcessManager
processManager
,
@required
String
engineVersion
,
@required
bool
generateDartPluginRegistry
,
Directory
buildDir
,
Map
<
String
,
String
>
defines
=
const
<
String
,
String
>{},
Map
<
String
,
String
>
inputs
=
const
<
String
,
String
>{},
...
...
@@ -347,6 +348,7 @@ class Environment {
processManager:
processManager
,
engineVersion:
engineVersion
,
inputs:
inputs
,
generateDartPluginRegistry:
generateDartPluginRegistry
,
);
}
...
...
@@ -363,6 +365,7 @@ class Environment {
Map
<
String
,
String
>
defines
=
const
<
String
,
String
>{},
Map
<
String
,
String
>
inputs
=
const
<
String
,
String
>{},
String
engineVersion
,
bool
generateDartPluginRegistry
=
false
,
@required
FileSystem
fileSystem
,
@required
Logger
logger
,
@required
Artifacts
artifacts
,
...
...
@@ -381,6 +384,7 @@ class Environment {
artifacts:
artifacts
,
processManager:
processManager
,
engineVersion:
engineVersion
,
generateDartPluginRegistry:
generateDartPluginRegistry
,
);
}
...
...
@@ -398,6 +402,7 @@ class Environment {
@required
this
.
artifacts
,
@required
this
.
engineVersion
,
@required
this
.
inputs
,
@required
this
.
generateDartPluginRegistry
,
});
/// The [Source] value which is substituted with the path to [projectDir].
...
...
@@ -475,6 +480,11 @@ class Environment {
/// The version of the current engine, or `null` if built with a local engine.
final
String
engineVersion
;
/// Whether to generate the Dart plugin registry.
/// When [true], the main entrypoint is wrapped and the wrapper becomes
/// the new entrypoint.
final
bool
generateDartPluginRegistry
;
}
/// The result information from the build system.
...
...
packages/flutter_tools/lib/src/build_system/targets/common.dart
View file @
b7d48062
...
...
@@ -279,6 +279,8 @@ class KernelSnapshot extends Target {
fileSystemScheme:
fileSystemScheme
,
dartDefines:
decodeDartDefines
(
environment
.
defines
,
kDartDefines
),
packageConfig:
packageConfig
,
buildDir:
environment
.
buildDir
,
generateDartPluginRegistry:
environment
.
generateDartPluginRegistry
,
);
if
(
output
==
null
||
output
.
errorCount
!=
0
)
{
throw
Exception
();
...
...
packages/flutter_tools/lib/src/bundle.dart
View file @
b7d48062
...
...
@@ -160,6 +160,7 @@ Future<void> buildWithAssemble({
fileSystem:
globals
.
fs
,
logger:
globals
.
logger
,
processManager:
globals
.
processManager
,
generateDartPluginRegistry:
true
,
);
final
Target
target
=
buildMode
==
BuildMode
.
debug
?
const
CopyFlutterBundle
()
...
...
packages/flutter_tools/lib/src/commands/assemble.dart
View file @
b7d48062
...
...
@@ -195,7 +195,8 @@ class AssembleCommand extends FlutterCommand {
processManager:
globals
.
processManager
,
engineVersion:
globals
.
artifacts
.
isLocalEngine
?
null
:
globals
.
flutterVersion
.
engineRevision
:
globals
.
flutterVersion
.
engineRevision
,
generateDartPluginRegistry:
true
,
);
return
result
;
}
...
...
packages/flutter_tools/lib/src/commands/build_ios_framework.dart
View file @
b7d48062
...
...
@@ -385,6 +385,7 @@ end
engineVersion: globals.artifacts.isLocalEngine
? null
: globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true,
);
Target target;
// Always build debug for simulator.
...
...
packages/flutter_tools/lib/src/commands/packages.dart
View file @
b7d48062
...
...
@@ -119,6 +119,7 @@ class PackagesGetCommand extends FlutterCommand {
outputDir:
globals
.
fs
.
directory
(
getBuildDirectory
()),
processManager:
globals
.
processManager
,
projectDir:
flutterProject
.
directory
,
generateDartPluginRegistry:
true
,
);
await
generateLocalizationsSyntheticPackage
(
...
...
@@ -324,6 +325,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand {
outputDir:
globals
.
fs
.
directory
(
getBuildDirectory
()),
processManager:
globals
.
processManager
,
projectDir:
flutterProject
.
directory
,
generateDartPluginRegistry:
true
,
);
await
generateLocalizationsSyntheticPackage
(
...
...
packages/flutter_tools/lib/src/compile.dart
View file @
b7d48062
...
...
@@ -19,6 +19,8 @@ import 'base/logger.dart';
import
'base/platform.dart'
;
import
'build_info.dart'
;
import
'convert.dart'
;
import
'plugins.dart'
;
import
'project.dart'
;
/// The target model describes the set of core libraries that are available within
/// the SDK.
...
...
@@ -209,6 +211,8 @@ class KernelCompiler {
String
fileSystemScheme
,
String
initializeFromDill
,
String
platformDill
,
Directory
buildDir
,
bool
generateDartPluginRegistry
=
false
,
@required
String
packagesPath
,
@required
BuildMode
buildMode
,
@required
bool
trackWidgetCreation
,
...
...
@@ -227,7 +231,8 @@ class KernelCompiler {
throwToolExit
(
'Unable to find Dart binary at
$engineDartPath
'
);
}
String
mainUri
;
final
Uri
mainFileUri
=
_fileSystem
.
file
(
mainPath
).
uri
;
final
File
mainFile
=
_fileSystem
.
file
(
mainPath
);
final
Uri
mainFileUri
=
mainFile
.
uri
;
if
(
packagesPath
!=
null
)
{
mainUri
=
packageConfig
.
toPackageUri
(
mainFileUri
)?.
toString
();
}
...
...
@@ -235,6 +240,21 @@ class KernelCompiler {
if
(
outputFilePath
!=
null
&&
!
_fileSystem
.
isFileSync
(
outputFilePath
))
{
_fileSystem
.
file
(
outputFilePath
).
createSync
(
recursive:
true
);
}
if
(
buildDir
!=
null
&&
generateDartPluginRegistry
)
{
// `generated_main.dart` is under `.dart_tools/flutter_build/`,
// so the resident compiler can find it.
final
File
newMainDart
=
buildDir
.
parent
.
childFile
(
'generated_main.dart'
);
if
(
await
generateMainDartWithPluginRegistrant
(
FlutterProject
.
current
(),
packageConfig
,
mainUri
,
newMainDart
,
mainFile
,
))
{
mainUri
=
newMainDart
.
path
;
}
}
final
List
<
String
>
command
=
<
String
>[
engineDartPath
,
'--disable-dart-dev'
,
...
...
@@ -579,7 +599,6 @@ class DefaultResidentCompiler implements ResidentCompiler {
if
(!
_controller
.
hasListener
)
{
_controller
.
stream
.
listen
(
_handleCompilationRequest
);
}
final
Completer
<
CompilerOutput
>
completer
=
Completer
<
CompilerOutput
>();
_controller
.
add
(
_RecompileRequest
(
completer
,
mainUri
,
invalidatedFiles
,
outputPath
,
packageConfig
,
suppressErrors
)
...
...
packages/flutter_tools/lib/src/devfs.dart
View file @
b7d48062
...
...
@@ -518,6 +518,20 @@ class DevFS {
// dill files that depend on the invalidated files.
_logger
.
printTrace
(
'Compiling dart to kernel with
${invalidatedFiles.length}
updated files'
);
// `generated_main.dart` contains the Dart plugin registry.
if
(
projectRootPath
!=
null
)
{
final
File
generatedMainDart
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
projectRootPath
,
'.dart_tool'
,
'flutter_build'
,
'generated_main.dart'
,
),
);
if
(
generatedMainDart
!=
null
&&
generatedMainDart
.
existsSync
())
{
mainUri
=
generatedMainDart
.
uri
;
}
}
// Await the compiler response after checking if the bundle is updated. This allows the file
// stating to be done while waiting for the frontend_server response.
final
Future
<
CompilerOutput
>
pendingCompilerOutput
=
generator
.
recompile
(
...
...
packages/flutter_tools/lib/src/flutter_manifest.dart
View file @
b7d48062
...
...
@@ -86,6 +86,13 @@ class FlutterManifest {
/// The string value of the top-level `name` property in the `pubspec.yaml` file.
String
get
appName
=>
_descriptor
[
'name'
]
as
String
??
''
;
/// Contains the name of the dependencies.
/// These are the keys specified in the `dependency` map.
Set
<
String
>
get
dependencies
{
final
YamlMap
dependencies
=
_descriptor
[
'dependencies'
]
as
YamlMap
;
return
dependencies
!=
null
?
<
String
>{...
dependencies
.
keys
.
cast
<
String
>()}
:
<
String
>{};
}
// Flag to avoid printing multiple invalid version messages.
bool
_hasShowInvalidVersionMsg
=
false
;
...
...
packages/flutter_tools/lib/src/platform_plugins.dart
View file @
b7d48062
...
...
@@ -16,6 +16,9 @@ const String kPluginClass = 'pluginClass';
/// Constant for 'pluginClass' key in plugin maps.
const
String
kDartPluginClass
=
'dartPluginClass'
;
// Constant for 'defaultPackage' key in plugin maps.
const
String
kDefaultPackage
=
'default_package'
;
/// Marker interface for all platform specific plugin config implementations.
abstract
class
PluginPlatform
{
const
PluginPlatform
();
...
...
@@ -207,6 +210,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
@required
this
.
name
,
this
.
pluginClass
,
this
.
dartPluginClass
,
this
.
defaultPackage
,
});
factory
MacOSPlugin
.
fromYaml
(
String
name
,
YamlMap
yaml
)
{
...
...
@@ -220,6 +224,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
name:
name
,
pluginClass:
pluginClass
,
dartPluginClass:
yaml
[
kDartPluginClass
]
as
String
,
defaultPackage:
yaml
[
kDefaultPackage
]
as
String
,
);
}
...
...
@@ -227,7 +232,9 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
if
(
yaml
==
null
)
{
return
false
;
}
return
yaml
[
kPluginClass
]
is
String
||
yaml
[
kDartPluginClass
]
is
String
;
return
yaml
[
kPluginClass
]
is
String
||
yaml
[
kDartPluginClass
]
is
String
||
yaml
[
kDefaultPackage
]
is
String
;
}
static
const
String
kConfigKey
=
'macos'
;
...
...
@@ -235,6 +242,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
final
String
name
;
final
String
pluginClass
;
final
String
dartPluginClass
;
final
String
defaultPackage
;
@override
bool
isNative
()
=>
pluginClass
!=
null
;
...
...
@@ -244,7 +252,8 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
return
<
String
,
dynamic
>{
'name'
:
name
,
if
(
pluginClass
!=
null
)
'class'
:
pluginClass
,
if
(
dartPluginClass
!=
null
)
'dartPluginClass'
:
dartPluginClass
,
if
(
dartPluginClass
!=
null
)
kDartPluginClass
:
dartPluginClass
,
if
(
defaultPackage
!=
null
)
kDefaultPackage
:
defaultPackage
,
};
}
}
...
...
@@ -258,7 +267,8 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
@required
this
.
name
,
this
.
pluginClass
,
this
.
dartPluginClass
,
})
:
assert
(
pluginClass
!=
null
||
dartPluginClass
!=
null
);
this
.
defaultPackage
,
})
:
assert
(
pluginClass
!=
null
||
dartPluginClass
!=
null
||
defaultPackage
!=
null
);
factory
WindowsPlugin
.
fromYaml
(
String
name
,
YamlMap
yaml
)
{
assert
(
validate
(
yaml
));
...
...
@@ -271,6 +281,7 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
name:
name
,
pluginClass:
pluginClass
,
dartPluginClass:
yaml
[
kDartPluginClass
]
as
String
,
defaultPackage:
yaml
[
kDefaultPackage
]
as
String
,
);
}
...
...
@@ -278,7 +289,9 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
if
(
yaml
==
null
)
{
return
false
;
}
return
yaml
[
kDartPluginClass
]
is
String
||
yaml
[
kPluginClass
]
is
String
;
return
yaml
[
kPluginClass
]
is
String
||
yaml
[
kDartPluginClass
]
is
String
||
yaml
[
kDefaultPackage
]
is
String
;
}
static
const
String
kConfigKey
=
'windows'
;
...
...
@@ -286,6 +299,7 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
final
String
name
;
final
String
pluginClass
;
final
String
dartPluginClass
;
final
String
defaultPackage
;
@override
bool
isNative
()
=>
pluginClass
!=
null
;
...
...
@@ -296,7 +310,8 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
'name'
:
name
,
if
(
pluginClass
!=
null
)
'class'
:
pluginClass
,
if
(
pluginClass
!=
null
)
'filename'
:
_filenameForCppClass
(
pluginClass
),
if
(
dartPluginClass
!=
null
)
'dartPluginClass'
:
dartPluginClass
,
if
(
dartPluginClass
!=
null
)
kDartPluginClass:
dartPluginClass
,
if
(
defaultPackage
!=
null
)
kDefaultPackage:
defaultPackage
,
};
}
}
...
...
@@ -310,7 +325,8 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
@required
this
.
name
,
this
.
pluginClass
,
this
.
dartPluginClass
,
})
:
assert
(
pluginClass
!=
null
||
dartPluginClass
!=
null
);
this
.
defaultPackage
,
})
:
assert
(
pluginClass
!=
null
||
dartPluginClass
!=
null
||
defaultPackage
!=
null
);
factory
LinuxPlugin
.
fromYaml
(
String
name
,
YamlMap
yaml
)
{
assert
(
validate
(
yaml
));
...
...
@@ -323,6 +339,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
name:
name
,
pluginClass:
pluginClass
,
dartPluginClass:
yaml
[
kDartPluginClass
]
as
String
,
defaultPackage:
yaml
[
kDefaultPackage
]
as
String
,
);
}
...
...
@@ -330,7 +347,9 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
if
(
yaml
==
null
)
{
return
false
;
}
return
yaml
[
kPluginClass
]
is
String
||
yaml
[
kDartPluginClass
]
is
String
;
return
yaml
[
kPluginClass
]
is
String
||
yaml
[
kDartPluginClass
]
is
String
||
yaml
[
kDefaultPackage
]
is
String
;
}
static
const
String
kConfigKey
=
'linux'
;
...
...
@@ -338,6 +357,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
final
String
name
;
final
String
pluginClass
;
final
String
dartPluginClass
;
final
String
defaultPackage
;
@override
bool
isNative
()
=>
pluginClass
!=
null
;
...
...
@@ -348,7 +368,8 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
'name'
:
name
,
if
(
pluginClass
!=
null
)
'class'
:
pluginClass
,
if
(
pluginClass
!=
null
)
'filename'
:
_filenameForCppClass
(
pluginClass
),
if
(
dartPluginClass
!=
null
)
'dartPluginClass'
:
dartPluginClass
,
if
(
dartPluginClass
!=
null
)
kDartPluginClass:
dartPluginClass
,
if
(
defaultPackage
!=
null
)
kDefaultPackage:
defaultPackage
,
};
}
}
...
...
packages/flutter_tools/lib/src/plugins.dart
View file @
b7d48062
...
...
@@ -17,6 +17,7 @@ import 'base/os.dart';
import
'base/platform.dart'
;
import
'base/version.dart'
;
import
'convert.dart'
;
import
'dart/language_version.dart'
;
import
'dart/package_map.dart'
;
import
'features.dart'
;
import
'globals.dart'
as
globals
;
...
...
@@ -36,11 +37,18 @@ class Plugin {
@required
this
.
name
,
@required
this
.
path
,
@required
this
.
platforms
,
@required
this
.
defaultPackagePlatforms
,
@required
this
.
pluginDartClassPlatforms
,
@required
this
.
dependencies
,
@required
this
.
isDirectDependency
,
this
.
implementsPackage
,
})
:
assert
(
name
!=
null
),
assert
(
path
!=
null
),
assert
(
platforms
!=
null
),
assert
(
dependencies
!=
null
);
assert
(
defaultPackagePlatforms
!=
null
),
assert
(
pluginDartClassPlatforms
!=
null
),
assert
(
dependencies
!=
null
),
assert
(
isDirectDependency
!=
null
);
/// Parses [Plugin] specification from the provided pluginYaml.
///
...
...
@@ -76,15 +84,30 @@ class Plugin {
YamlMap
pluginYaml
,
List
<
String
>
dependencies
,
{
@required
FileSystem
fileSystem
,
Set
<
String
>
appDependencies
,
})
{
final
List
<
String
>
errors
=
validatePluginYaml
(
pluginYaml
);
if
(
errors
.
isNotEmpty
)
{
throwToolExit
(
'Invalid plugin specification
$name
.
\n
${errors.join('\n')}
'
);
}
if
(
pluginYaml
!=
null
&&
pluginYaml
[
'platforms'
]
!=
null
)
{
return
Plugin
.
_fromMultiPlatformYaml
(
name
,
path
,
pluginYaml
,
dependencies
,
fileSystem
);
return
Plugin
.
_fromMultiPlatformYaml
(
name
,
path
,
pluginYaml
,
dependencies
,
fileSystem
,
appDependencies
!=
null
&&
appDependencies
.
contains
(
name
),
);
}
return
Plugin
.
_fromLegacyYaml
(
name
,
path
,
pluginYaml
,
dependencies
,
fileSystem
);
return
Plugin
.
_fromLegacyYaml
(
name
,
path
,
pluginYaml
,
dependencies
,
fileSystem
,
appDependencies
!=
null
&&
appDependencies
.
contains
(
name
),
);
}
factory
Plugin
.
_fromMultiPlatformYaml
(
...
...
@@ -93,6 +116,7 @@ class Plugin {
dynamic
pluginYaml
,
List
<
String
>
dependencies
,
FileSystem
fileSystem
,
bool
isDirectDependency
,
)
{
assert
(
pluginYaml
!=
null
&&
pluginYaml
[
'platforms'
]
!=
null
,
'Invalid multi-platform plugin specification
$name
.'
);
...
...
@@ -137,11 +161,47 @@ class Plugin {
WindowsPlugin
.
fromYaml
(
name
,
platformsYaml
[
WindowsPlugin
.
kConfigKey
]
as
YamlMap
);
}
final
String
defaultPackageForLinux
=
_getDefaultPackageForPlatform
(
platformsYaml
,
LinuxPlugin
.
kConfigKey
);
final
String
defaultPackageForMacOS
=
_getDefaultPackageForPlatform
(
platformsYaml
,
MacOSPlugin
.
kConfigKey
);
final
String
defaultPackageForWindows
=
_getDefaultPackageForPlatform
(
platformsYaml
,
WindowsPlugin
.
kConfigKey
);
final
String
defaultPluginDartClassForLinux
=
_getPluginDartClassForPlatform
(
platformsYaml
,
LinuxPlugin
.
kConfigKey
);
final
String
defaultPluginDartClassForMacOS
=
_getPluginDartClassForPlatform
(
platformsYaml
,
MacOSPlugin
.
kConfigKey
);
final
String
defaultPluginDartClassForWindows
=
_getPluginDartClassForPlatform
(
platformsYaml
,
WindowsPlugin
.
kConfigKey
);
return
Plugin
(
name:
name
,
path:
path
,
platforms:
platforms
,
defaultPackagePlatforms:
<
String
,
String
>{
if
(
defaultPackageForLinux
!=
null
)
LinuxPlugin
.
kConfigKey
:
defaultPackageForLinux
,
if
(
defaultPackageForMacOS
!=
null
)
MacOSPlugin
.
kConfigKey
:
defaultPackageForMacOS
,
if
(
defaultPackageForWindows
!=
null
)
WindowsPlugin
.
kConfigKey
:
defaultPackageForWindows
,
},
pluginDartClassPlatforms:
<
String
,
String
>{
if
(
defaultPluginDartClassForLinux
!=
null
)
LinuxPlugin
.
kConfigKey
:
defaultPluginDartClassForLinux
,
if
(
defaultPluginDartClassForMacOS
!=
null
)
MacOSPlugin
.
kConfigKey
:
defaultPluginDartClassForMacOS
,
if
(
defaultPluginDartClassForWindows
!=
null
)
WindowsPlugin
.
kConfigKey
:
defaultPluginDartClassForWindows
,
},
dependencies:
dependencies
,
isDirectDependency:
isDirectDependency
,
implementsPackage:
pluginYaml
[
'implements'
]
!=
null
?
pluginYaml
[
'implements'
]
as
String
:
''
,
);
}
...
...
@@ -151,6 +211,7 @@ class Plugin {
dynamic
pluginYaml
,
List
<
String
>
dependencies
,
FileSystem
fileSystem
,
bool
isDirectDependency
,
)
{
final
Map
<
String
,
PluginPlatform
>
platforms
=
<
String
,
PluginPlatform
>{};
final
String
pluginClass
=
pluginYaml
[
'pluginClass'
]
as
String
;
...
...
@@ -178,7 +239,10 @@ class Plugin {
name:
name
,
path:
path
,
platforms:
platforms
,
defaultPackagePlatforms:
<
String
,
String
>{},
pluginDartClassPlatforms:
<
String
,
String
>{},
dependencies:
dependencies
,
isDirectDependency:
isDirectDependency
,
);
}
...
...
@@ -295,11 +359,41 @@ class Plugin {
return
errors
;
}
static
bool
_
providesImplementationFor
Platform
(
YamlMap
platformsYaml
,
String
platformKey
)
{
static
bool
_
supports
Platform
(
YamlMap
platformsYaml
,
String
platformKey
)
{
if
(!
platformsYaml
.
containsKey
(
platformKey
))
{
return
false
;
}
if
((
platformsYaml
[
platformKey
]
as
YamlMap
).
containsKey
(
'default_package'
))
{
if
(
platformsYaml
[
platformKey
]
is
YamlMap
)
{
return
true
;
}
return
false
;
}
static
String
_getDefaultPackageForPlatform
(
YamlMap
platformsYaml
,
String
platformKey
)
{
if
(!
_supportsPlatform
(
platformsYaml
,
platformKey
))
{
return
null
;
}
if
((
platformsYaml
[
platformKey
]
as
YamlMap
).
containsKey
(
kDefaultPackage
))
{
return
(
platformsYaml
[
platformKey
]
as
YamlMap
)[
kDefaultPackage
]
as
String
;
}
return
null
;
}
static
String
_getPluginDartClassForPlatform
(
YamlMap
platformsYaml
,
String
platformKey
)
{
if
(!
_supportsPlatform
(
platformsYaml
,
platformKey
))
{
return
null
;
}
if
((
platformsYaml
[
platformKey
]
as
YamlMap
).
containsKey
(
kDartPluginClass
))
{
return
(
platformsYaml
[
platformKey
]
as
YamlMap
)[
kDartPluginClass
]
as
String
;
}
return
null
;
}
static
bool
_providesImplementationForPlatform
(
YamlMap
platformsYaml
,
String
platformKey
)
{
if
(!
_supportsPlatform
(
platformsYaml
,
platformKey
))
{
return
false
;
}
if
((
platformsYaml
[
platformKey
]
as
YamlMap
).
containsKey
(
kDefaultPackage
))
{
return
false
;
}
return
true
;
...
...
@@ -308,14 +402,28 @@ class Plugin {
final
String
name
;
final
String
path
;
/// The name of the interface package that this plugin implements.
/// If [null], this plugin doesn't implement an interface.
final
String
implementsPackage
;
/// The name of the packages this plugin depends on.
final
List
<
String
>
dependencies
;
/// This is a mapping from platform config key to the plugin platform spec.
final
Map
<
String
,
PluginPlatform
>
platforms
;
/// This is a mapping from platform config key to the default package implementation.
final
Map
<
String
,
String
>
defaultPackagePlatforms
;
/// This is a mapping from platform config key to the plugin class for the given platform.
final
Map
<
String
,
String
>
pluginDartClassPlatforms
;
/// Whether this plugin is a direct dependency of the app.
/// If [false], the plugin is a dependency of another plugin.
final
bool
isDirectDependency
;
}
Plugin
_pluginFromPackage
(
String
name
,
Uri
packageRoot
)
{
Plugin
_pluginFromPackage
(
String
name
,
Uri
packageRoot
,
Set
<
String
>
appDependencies
)
{
final
String
pubspecPath
=
globals
.
fs
.
path
.
fromUri
(
packageRoot
.
resolve
(
'pubspec.yaml'
));
if
(!
globals
.
fs
.
isFileSync
(
pubspecPath
))
{
return
null
;
...
...
@@ -344,6 +452,7 @@ Plugin _pluginFromPackage(String name, Uri packageRoot) {
flutterConfig
[
'plugin'
]
as
YamlMap
,
dependencies
==
null
?
<
String
>[]
:
<
String
>[...
dependencies
.
keys
.
cast
<
String
>()],
fileSystem:
globals
.
fs
,
appDependencies:
appDependencies
,
);
}
...
...
@@ -360,7 +469,11 @@ Future<List<Plugin>> findPlugins(FlutterProject project, { bool throwOnError = t
);
for
(
final
Package
package
in
packageConfig
.
packages
)
{
final
Uri
packageRoot
=
package
.
packageUriRoot
.
resolve
(
'..'
);
final
Plugin
plugin
=
_pluginFromPackage
(
package
.
name
,
packageRoot
);
final
Plugin
plugin
=
_pluginFromPackage
(
package
.
name
,
packageRoot
,
project
.
manifest
.
dependencies
,
);
if
(
plugin
!=
null
)
{
plugins
.
add
(
plugin
);
}
...
...
@@ -368,6 +481,130 @@ Future<List<Plugin>> findPlugins(FlutterProject project, { bool throwOnError = t
return
plugins
;
}
/// Metadata associated with the resolution of a platform interface of a plugin.
class
PluginInterfaceResolution
{
PluginInterfaceResolution
({
@required
this
.
plugin
,
this
.
platform
,
})
:
assert
(
plugin
!=
null
);
/// The plugin.
final
Plugin
plugin
;
// The name of the platform that this plugin implements.
final
String
platform
;
Map
<
String
,
String
>
toMap
()
{
return
<
String
,
String
>
{
'pluginName'
:
plugin
.
name
,
'platform'
:
platform
,
'dartClass'
:
plugin
.
pluginDartClassPlatforms
[
platform
],
};
}
}
/// Resolves the platform implementation for Dart-only plugins.
///
/// * If there are multiple direct pub dependencies on packages that implement the
/// frontend plugin for the current platform, fail.
/// * If there is a single direct dependency on a package that implements the
/// frontend plugin for the target platform, this package is the selected implementation.
/// * If there is no direct dependency on a package that implements the frontend
/// plugin for the target platform, and the frontend plugin has a default implementation
/// for the target platform the default implementation is selected.
/// * Else fail.
///
/// For more details, https://flutter.dev/go/federated-plugins.
List
<
PluginInterfaceResolution
>
resolvePlatformImplementation
(
List
<
Plugin
>
plugins
,
{
bool
throwOnPluginPubspecError
=
true
,
})
{
final
List
<
String
>
platforms
=
<
String
>[
LinuxPlugin
.
kConfigKey
,
MacOSPlugin
.
kConfigKey
,
WindowsPlugin
.
kConfigKey
,
];
final
Map
<
String
,
PluginInterfaceResolution
>
directDependencyResolutions
=
<
String
,
PluginInterfaceResolution
>{};
final
Map
<
String
,
String
>
defaultImplementations
=
<
String
,
String
>{};
bool
didFindError
=
false
;
for
(
final
Plugin
plugin
in
plugins
)
{
for
(
final
String
platform
in
platforms
)
{
// The plugin doesn't implement this platform.
if
(
plugin
.
platforms
[
platform
]
==
null
&&
plugin
.
defaultPackagePlatforms
[
platform
]
==
null
)
{
continue
;
}
// The plugin doesn't implement an interface, verify that it has a default implementation.
if
(
plugin
.
implementsPackage
==
null
||
plugin
.
implementsPackage
.
isEmpty
)
{
final
String
defaultImplementation
=
plugin
.
defaultPackagePlatforms
[
platform
];
if
(
defaultImplementation
==
null
)
{
globals
.
printError
(
'Plugin `
${plugin.name}
` doesn
\'
t implement a plugin interface, nor sets '
'a default implementation in pubspec.yaml.
\n\n
'
'To set a default implementation, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' platforms:
\n
'
'
$platform
:
\n
'
'
$kDefaultPackage
: <plugin-implementation>
\n
'
'
\n
'
'To implement an interface, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' implements: <plugin-interface>'
'
\n
'
);
didFindError
=
true
;
continue
;
}
defaultImplementations
[
'
$platform
/
${plugin.name}
'
]
=
defaultImplementation
;
continue
;
}
if
(
plugin
.
pluginDartClassPlatforms
[
platform
]
==
null
||
plugin
.
pluginDartClassPlatforms
[
platform
]
==
'none'
)
{
continue
;
}
final
String
resolutionKey
=
'
$platform
/
${plugin.implementsPackage}
'
;
if
(
directDependencyResolutions
.
containsKey
(
resolutionKey
))
{
final
PluginInterfaceResolution
currResolution
=
directDependencyResolutions
[
resolutionKey
];
if
(
currResolution
.
plugin
.
isDirectDependency
&&
plugin
.
isDirectDependency
)
{
globals
.
printError
(
'Plugin `
${plugin.name}
` implements an interface for `
$platform
`, which was already '
'implemented by plugin `
${currResolution.plugin.name}
`.
\n
'
'To fix this issue, remove either dependency from pubspec.yaml.'
'
\n\n
'
);
didFindError
=
true
;
}
if
(
currResolution
.
plugin
.
isDirectDependency
)
{
// Use the plugin implementation added by the user as a direct dependency.
continue
;
}
}
directDependencyResolutions
[
resolutionKey
]
=
PluginInterfaceResolution
(
plugin:
plugin
,
platform:
platform
,
);
}
}
if
(
didFindError
&&
throwOnPluginPubspecError
)
{
throwToolExit
(
'Please resolve the errors'
);
}
final
List
<
PluginInterfaceResolution
>
finalResolution
=
<
PluginInterfaceResolution
>[];
for
(
final
MapEntry
<
String
,
PluginInterfaceResolution
>
resolution
in
directDependencyResolutions
.
entries
)
{
if
(
resolution
.
value
.
plugin
.
isDirectDependency
)
{
finalResolution
.
add
(
resolution
.
value
);
}
else
if
(
defaultImplementations
.
containsKey
(
resolution
.
key
))
{
// Pick the default implementation.
if
(
defaultImplementations
[
resolution
.
key
]
==
resolution
.
value
.
plugin
.
name
)
{
finalResolution
.
add
(
resolution
.
value
);
}
}
}
return
finalResolution
;
}
// Key strings for the .flutter-plugins-dependencies file.
const
String
_kFlutterPluginsPluginListKey
=
'plugins'
;
const
String
_kFlutterPluginsNameKey
=
'name'
;
...
...
@@ -684,6 +921,63 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin>
);
}
/// Generates the Dart plugin registrant, which allows to bind a platform
/// implementation of a Dart only plugin to its interface.
/// The new entrypoint wraps [currentMainUri], adds a [_registerPlugins] function,
/// and writes the file to [newMainDart].
///
/// [mainFile] is the main entrypoint file. e.g. /<app>/lib/main.dart.
///
/// Returns [true] if it's necessary to create a plugin registrant, and
/// if the new entrypoint was written to disk.
///
/// For more details, see https://flutter.dev/go/federated-plugins.
Future
<
bool
>
generateMainDartWithPluginRegistrant
(
FlutterProject
rootProject
,
PackageConfig
packageConfig
,
String
currentMainUri
,
File
newMainDart
,
File
mainFile
,
)
async
{
final
List
<
Plugin
>
plugins
=
await
findPlugins
(
rootProject
);
final
List
<
PluginInterfaceResolution
>
resolutions
=
resolvePlatformImplementation
(
plugins
,
// TODO(egarciad): Turn this on after fixing the pubspec.yaml of the plugins used in tests.
throwOnPluginPubspecError:
false
,
);
final
LanguageVersion
entrypointVersion
=
determineLanguageVersion
(
mainFile
,
packageConfig
.
packageOf
(
mainFile
.
absolute
.
uri
),
);
final
Map
<
String
,
dynamic
>
templateContext
=
<
String
,
dynamic
>{
'mainEntrypoint'
:
currentMainUri
,
'dartLanguageVersion'
:
entrypointVersion
.
toString
(),
LinuxPlugin
.
kConfigKey
:
<
dynamic
>[],
MacOSPlugin
.
kConfigKey
:
<
dynamic
>[],
WindowsPlugin
.
kConfigKey
:
<
dynamic
>[],
};
bool
didFindPlugin
=
false
;
for
(
final
PluginInterfaceResolution
resolution
in
resolutions
)
{
assert
(
templateContext
.
containsKey
(
resolution
.
platform
));
(
templateContext
[
resolution
.
platform
]
as
List
<
dynamic
>).
add
(
resolution
.
toMap
());
didFindPlugin
=
true
;
}
if
(!
didFindPlugin
)
{
return
false
;
}
try
{
_renderTemplateToFile
(
_dartPluginRegistryForDesktopTemplate
,
templateContext
,
newMainDart
.
path
,
);
return
true
;
}
on
FileSystemException
catch
(
error
)
{
throwToolExit
(
'Unable to write
${newMainDart.path}
, received error:
$error
'
);
return
false
;
}
}
const
String
_objcPluginRegistryHeaderTemplate
=
'''
//
// Generated file. Do not edit.
...
...
@@ -777,7 +1071,7 @@ Depends on all your plugins, and provides a function to register them.
end
''';
const String _dartPluginRegistryTemplate = '''
const String _dartPluginRegistry
ForWeb
Template = '''
//
// Generated file. Do not edit.
//
...
...
@@ -799,6 +1093,47 @@ void registerPlugins(Registrar registrar) {
}
''';
// TODO(egarciad): Evaluate merging the web and desktop plugin registry templates.
const String _dartPluginRegistryForDesktopTemplate = '''
//
// Generated file. Do not edit.
//
// @dart = {{dartLanguageVersion}}
import
'{{mainEntrypoint}}'
as
entrypoint
;
import
'dart:io'
;
// ignore: dart_io_import.
{{
#linux
}}
import
'package:{{pluginName}}/{{pluginName}}.dart'
;
{{/
linux
}}
{{
#macos
}}
import
'package:{{pluginName}}/{{pluginName}}.dart'
;
{{/
macos
}}
{{
#windows
}}
import
'package:{{pluginName}}/{{pluginName}}.dart'
;
{{/
windows
}}
@pragma
(
'vm:entry-point'
)
void
_registerPlugins
(
)
{
if
(
Platform
.
isLinux
)
{
{{
#linux
}}
{{
dartClass
}}.
registerWith
();
{{/
linux
}}
}
else
if
(
Platform
.
isMacOS
)
{
{{
#macos
}}
{{
dartClass
}}.
registerWith
();
{{/
macos
}}
}
else
if
(
Platform
.
isWindows
)
{
{{
#windows
}}
{{
dartClass
}}.
registerWith
();
{{/
windows
}}
}
}
void
main
(
)
{
entrypoint
.
main
();
}
''';
const String _cppPluginRegistryHeaderTemplate = '''
//
// Generated file. Do not edit.
...
...
@@ -1040,7 +1375,7 @@ Future<void> _writeWebPluginRegistrant(FlutterProject project, List<Plugin> plug
return
ErrorHandlingFileSystem
.
deleteIfExists
(
file
);
}
else
{
_renderTemplateToFile
(
_dartPluginRegistryTemplate
,
_dartPluginRegistry
ForWeb
Template
,
context
,
filePath
,
);
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
b7d48062
...
...
@@ -920,6 +920,7 @@ abstract class ResidentRunner {
outputDir:
globals
.
fs
.
directory
(
getBuildDirectory
()),
processManager:
globals
.
processManager
,
projectDir:
globals
.
fs
.
currentDirectory
,
generateDartPluginRegistry:
true
,
);
_lastBuild
=
await
globals
.
buildSystem
.
buildIncremental
(
const
GenerateLocalizationsTarget
(),
...
...
packages/flutter_tools/lib/src/run_hot.dart
View file @
b7d48062
...
...
@@ -26,6 +26,7 @@ import 'devfs.dart';
import
'device.dart'
;
import
'features.dart'
;
import
'globals.dart'
as
globals
;
import
'project.dart'
;
import
'reporting/reporting.dart'
;
import
'resident_devtools_handler.dart'
;
import
'resident_runner.dart'
;
...
...
@@ -314,6 +315,15 @@ class HotRunner extends ResidentRunner {
bool
enableDevTools
=
false
,
String
route
,
})
async
{
File
mainFile
=
globals
.
fs
.
file
(
mainPath
);
// `generated_main.dart` contains the Dart plugin registry.
final
Directory
buildDir
=
FlutterProject
.
current
()
.
directory
.
childDirectory
(
globals
.
fs
.
path
.
join
(
'.dart_tool'
,
'flutter_build'
));
final
File
newMainDart
=
buildDir
?.
childFile
(
'generated_main.dart'
);
if
(
newMainDart
!=
null
&&
newMainDart
.
existsSync
())
{
mainFile
=
newMainDart
;
}
firstBuildTime
=
DateTime
.
now
();
final
List
<
Future
<
bool
>>
startupTasks
=
<
Future
<
bool
>>[];
...
...
@@ -326,7 +336,7 @@ class HotRunner extends ResidentRunner {
if
(
device
.
generator
!=
null
)
{
startupTasks
.
add
(
device
.
generator
.
recompile
(
globals
.
fs
.
file
(
mainPath
)
.
uri
,
mainFile
.
uri
,
<
Uri
>[],
// When running without a provided applicationBinary, the tool will
// simultaneously run the initial frontend_server compilation and
...
...
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
b7d48062
...
...
@@ -1153,6 +1153,7 @@ abstract class FlutterCommand extends Command<void> {
outputDir:
globals
.
fs
.
directory
(
getBuildDirectory
()),
processManager:
globals
.
processManager
,
projectDir:
project
.
directory
,
generateDartPluginRegistry:
true
,
);
await
generateLocalizationsSyntheticPackage
(
...
...
packages/flutter_tools/lib/src/web/compile.dart
View file @
b7d48062
...
...
@@ -69,6 +69,8 @@ Future<void> buildWeb(
?
null
:
globals
.
flutterVersion
.
engineRevision
,
flutterRootDir:
globals
.
fs
.
directory
(
Cache
.
flutterRoot
),
// Web uses a different Dart plugin registry.
generateDartPluginRegistry:
false
,
));
if
(!
result
.
success
)
{
for
(
final
ExceptionMeasurement
measurement
in
result
.
exceptions
.
values
)
{
...
...
packages/flutter_tools/test/general.shard/android/deferred_components_setup_validator_test.dart
View file @
b7d48062
...
...
@@ -36,6 +36,7 @@ void main() {
logger:
logger
,
processManager:
globals
.
processManager
,
engineVersion:
'invalidEngineVersion'
,
generateDartPluginRegistry:
false
,
);
return
result
;
}
...
...
packages/flutter_tools/test/general.shard/plugin_parsing_test.dart
View file @
b7d48062
...
...
@@ -220,6 +220,39 @@ void main() {
);
expect
(
plugin
.
platforms
,
<
String
,
PluginPlatform
>{});
expect
(
plugin
.
defaultPackagePlatforms
,
<
String
,
String
>{
'linux'
:
'sample_package_linux'
,
'macos'
:
'sample_package_macos'
,
'windows'
:
'sample_package_windows'
,
});
expect
(
plugin
.
pluginDartClassPlatforms
,
<
String
,
String
>{});
});
testWithoutContext
(
'Desktop plugin parsing allows a dartPluginClass field'
,
()
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
const
String
pluginYamlRaw
=
'platforms:
\n
'
' linux:
\n
'
' dartPluginClass: LinuxClass
\n
'
' macos:
\n
'
' dartPluginClass: MacOSClass
\n
'
' windows:
\n
'
' dartPluginClass: WindowsClass
\n
'
;
final
YamlMap
pluginYaml
=
loadYaml
(
pluginYamlRaw
)
as
YamlMap
;
final
Plugin
plugin
=
Plugin
.
fromYaml
(
_kTestPluginName
,
_kTestPluginPath
,
pluginYaml
,
const
<
String
>[],
fileSystem:
fileSystem
,
);
expect
(
plugin
.
pluginDartClassPlatforms
,
<
String
,
String
>{
'linux'
:
'LinuxClass'
,
'macos'
:
'MacOSClass'
,
'windows'
:
'WindowsClass'
,
});
});
testWithoutContext
(
'Plugin parsing throws a fatal error on an empty plugin'
,
()
{
...
...
packages/flutter_tools/test/general.shard/plugins_test.dart
View file @
b7d48062
...
...
@@ -14,6 +14,8 @@ import 'package:flutter_tools/src/base/platform.dart';
import
'package:flutter_tools/src/base/time.dart'
;
import
'package:flutter_tools/src/base/utils.dart'
;
import
'package:flutter_tools/src/features.dart'
;
import
'package:flutter_tools/src/dart/package_map.dart'
;
import
'package:flutter_tools/src/flutter_manifest.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/ios/xcodeproj.dart'
;
import
'package:flutter_tools/src/plugins.dart'
;
...
...
@@ -21,6 +23,7 @@ import 'package:flutter_tools/src/project.dart';
import
'package:flutter_tools/src/version.dart'
;
import
'package:meta/meta.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:yaml/yaml.dart'
;
import
'../src/common.dart'
;
...
...
@@ -32,6 +35,7 @@ void main() {
group
(
'plugins'
,
()
{
FileSystem
fs
;
MockFlutterProject
flutterProject
;
MockFlutterManifest
flutterManifest
;
MockIosProject
iosProject
;
MockMacOSProject
macosProject
;
MockAndroidProject
androidProject
;
...
...
@@ -48,6 +52,12 @@ void main() {
// Adds basic properties to the flutterProject and its subprojects.
void
setUpProject
(
FileSystem
fileSystem
)
{
flutterProject
=
MockFlutterProject
();
flutterManifest
=
MockFlutterManifest
();
when
(
flutterManifest
.
dependencies
).
thenReturn
(<
String
>{});
when
(
flutterProject
.
manifest
).
thenReturn
(
flutterManifest
);
when
(
flutterProject
.
directory
).
thenReturn
(
fileSystem
.
systemTempDirectory
.
childDirectory
(
'app'
));
// TODO(franciscojma): Remove logic for .flutter-plugins once it's deprecated.
when
(
flutterProject
.
flutterPluginsFile
).
thenReturn
(
flutterProject
.
directory
.
childFile
(
'.flutter-plugins'
));
...
...
@@ -1297,6 +1307,767 @@ flutter:
});
});
group
(
'resolvePlatformImplementation'
,
()
{
test
(
'selects implementation from direct dependency'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'url_launcher_linux'
,
'url_launcher_macos'
,
};
final
List
<
PluginInterfaceResolution
>
resolutions
=
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher_linux'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_macos'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'macos'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginMacOS'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'undirect_dependency_plugin'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'windows'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginWindows'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher_macos'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'macos'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginMacOS'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
resolutions
.
length
,
equals
(
2
));
expect
(
resolutions
[
0
].
toMap
(),
equals
(
<
String
,
String
>{
'pluginName'
:
'url_launcher_linux'
,
'dartClass'
:
'UrlLauncherPluginLinux'
,
'platform'
:
'linux'
,
})
);
expect
(
resolutions
[
1
].
toMap
(),
equals
(
<
String
,
String
>{
'pluginName'
:
'url_launcher_macos'
,
'dartClass'
:
'UrlLauncherPluginMacOS'
,
'platform'
:
'macos'
,
})
);
});
test
(
'selects default implementation'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{};
final
List
<
PluginInterfaceResolution
>
resolutions
=
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'default_package'
:
'url_launcher_linux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_linux'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
resolutions
.
length
,
equals
(
1
));
expect
(
resolutions
[
0
].
toMap
(),
equals
(
<
String
,
String
>{
'pluginName'
:
'url_launcher_linux'
,
'dartClass'
:
'UrlLauncherPluginLinux'
,
'platform'
:
'linux'
,
})
);
});
test
(
'selects default implementation if interface is direct dependency'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'url_launcher'
};
final
List
<
PluginInterfaceResolution
>
resolutions
=
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'default_package'
:
'url_launcher_linux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_linux'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
resolutions
.
length
,
equals
(
1
));
expect
(
resolutions
[
0
].
toMap
(),
equals
(
<
String
,
String
>{
'pluginName'
:
'url_launcher_linux'
,
'dartClass'
:
'UrlLauncherPluginLinux'
,
'platform'
:
'linux'
,
})
);
});
test
(
'selects user selected implementation despites default implementation'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'user_selected_url_launcher_implementation'
,
'url_launcher'
,
};
final
List
<
PluginInterfaceResolution
>
resolutions
=
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'default_package'
:
'url_launcher_linux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_linux'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'user_selected_url_launcher_implementation'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
resolutions
.
length
,
equals
(
1
));
expect
(
resolutions
[
0
].
toMap
(),
equals
(
<
String
,
String
>{
'pluginName'
:
'user_selected_url_launcher_implementation'
,
'dartClass'
:
'UrlLauncherPluginLinux'
,
'platform'
:
'linux'
,
})
);
});
test
(
'selects user selected implementation despites default implementation'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'user_selected_url_launcher_implementation'
,
'url_launcher'
,
};
final
List
<
PluginInterfaceResolution
>
resolutions
=
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'default_package'
:
'url_launcher_linux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_linux'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'user_selected_url_launcher_implementation'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
resolutions
.
length
,
equals
(
1
));
expect
(
resolutions
[
0
].
toMap
(),
equals
(
<
String
,
String
>{
'pluginName'
:
'user_selected_url_launcher_implementation'
,
'dartClass'
:
'UrlLauncherPluginLinux'
,
'platform'
:
'linux'
,
})
);
});
testUsingContext
(
'provides error when user selected multiple implementations'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'url_launcher_linux_1'
,
'url_launcher_linux_2'
,
};
expect
(()
{
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher_linux_1'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_linux_2'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
testLogger
.
errorText
,
'Plugin `url_launcher_linux_2` implements an interface for `linux`, which was already implemented by plugin `url_launcher_linux_1`.
\n
'
'To fix this issue, remove either dependency from pubspec.yaml.'
'
\n\n
'
);
},
throwsToolExit
(
message:
'Please resolve the errors'
,
));
});
testUsingContext
(
'provides all errors when user selected multiple implementations'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'url_launcher_linux_1'
,
'url_launcher_linux_2'
,
};
expect
(()
{
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher_linux_1'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_linux_2'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'implements'
:
'url_launcher'
,
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
expect
(
testLogger
.
errorText
,
'Plugin `url_launcher_linux_2` implements an interface for `linux`, which was already implemented by plugin `url_launcher_linux_1`.
\n
'
'To fix this issue, remove either dependency from pubspec.yaml.'
'
\n\n
'
);
},
throwsToolExit
(
message:
'Please resolve the errors'
,
));
});
testUsingContext
(
'provides error when plugin pubspec.yaml doesn
\'
t have "implementation" nor "default_implementation"'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'url_launcher_linux_1'
,
};
expect
(()
{
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher_linux_1'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
},
throwsToolExit
(
message:
'Please resolve the errors'
));
expect
(
testLogger
.
errorText
,
'Plugin `url_launcher_linux_1` doesn
\'
t implement a plugin interface, '
'nor sets a default implementation in pubspec.yaml.
\n\n
'
'To set a default implementation, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' platforms:
\n
'
' linux:
\n
'
' default_package: <plugin-implementation>
\n
'
'
\n
'
'To implement an interface, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' implements: <plugin-interface>'
'
\n\n
'
);
});
testUsingContext
(
'provides all errors when plugin pubspec.yaml doesn
\'
t have "implementation" nor "default_implementation"'
,
()
async
{
final
FileSystem
fs
=
MemoryFileSystem
();
final
Set
<
String
>
directDependencies
=
<
String
>{
'url_launcher_linux'
,
'url_launcher_windows'
,
};
expect
(()
{
resolvePlatformImplementation
(<
Plugin
>[
Plugin
.
fromYaml
(
'url_launcher_linux'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'linux'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginLinux'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
Plugin
.
fromYaml
(
'url_launcher_windows'
,
''
,
YamlMap
.
wrap
(<
String
,
dynamic
>{
'platforms'
:
<
String
,
dynamic
>{
'windows'
:
<
String
,
dynamic
>{
'dartPluginClass'
:
'UrlLauncherPluginWindows'
,
},
},
}),
<
String
>[],
fileSystem:
fs
,
appDependencies:
directDependencies
,
),
]);
},
throwsToolExit
(
message:
'Please resolve the errors'
));
expect
(
testLogger
.
errorText
,
'Plugin `url_launcher_linux` doesn
\'
t implement a plugin interface, '
'nor sets a default implementation in pubspec.yaml.
\n\n
'
'To set a default implementation, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' platforms:
\n
'
' linux:
\n
'
' default_package: <plugin-implementation>
\n
'
'
\n
'
'To implement an interface, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' implements: <plugin-interface>'
'
\n\n
'
'Plugin `url_launcher_windows` doesn
\'
t implement a plugin interface, '
'nor sets a default implementation in pubspec.yaml.
\n\n
'
'To set a default implementation, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' platforms:
\n
'
' windows:
\n
'
' default_package: <plugin-implementation>
\n
'
'
\n
'
'To implement an interface, use:
\n
'
'flutter:
\n
'
' plugin:
\n
'
' implements: <plugin-interface>'
'
\n\n
'
);
});
});
group
(
'generateMainDartWithPluginRegistrant'
,
()
{
testUsingContext
(
'Generates new entrypoint'
,
()
async
{
when
(
flutterProject
.
isModule
).
thenReturn
(
false
);
final
List
<
Directory
>
directories
=
<
Directory
>[];
final
Directory
fakePubCache
=
fs
.
systemTempDirectory
.
childDirectory
(
'cache'
);
final
File
packagesFile
=
flutterProject
.
directory
.
childFile
(
'.packages'
)
..
createSync
(
recursive:
true
);
final
Map
<
String
,
String
>
plugins
=
<
String
,
String
>{};
plugins
[
'url_launcher_macos'
]
=
'''
flutter:
plugin:
implements: url_launcher
platforms:
macos:
dartPluginClass: MacOSPlugin
'''
;
plugins
[
'url_launcher_linux'
]
=
'''
flutter:
plugin:
implements: url_launcher
platforms:
linux:
dartPluginClass: LinuxPlugin
'''
;
plugins
[
'url_launcher_windows'
]
=
'''
flutter:
plugin:
implements: url_launcher
platforms:
windows:
dartPluginClass: WindowsPlugin
'''
;
plugins
[
'awesome_macos'
]
=
'''
flutter:
plugin:
implements: awesome
platforms:
macos:
dartPluginClass: AwesomeMacOS
'''
;
for
(
final
MapEntry
<
String
,
String
>
entry
in
plugins
.
entries
)
{
final
String
name
=
fs
.
path
.
basename
(
entry
.
key
);
final
Directory
pluginDirectory
=
fakePubCache
.
childDirectory
(
name
);
packagesFile
.
writeAsStringSync
(
'
$name
:file://
${pluginDirectory.childFile('lib').uri}
\n
'
,
mode:
FileMode
.
writeOnlyAppend
);
pluginDirectory
.
childFile
(
'pubspec.yaml'
)
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
entry
.
value
);
directories
.
add
(
pluginDirectory
);
}
when
(
flutterManifest
.
dependencies
).
thenReturn
(<
String
>{...
plugins
.
keys
});
final
Directory
libDir
=
flutterProject
.
directory
.
childDirectory
(
'lib'
);
libDir
.
createSync
(
recursive:
true
);
final
File
mainFile
=
libDir
.
childFile
(
'main.dart'
);
mainFile
.
writeAsStringSync
(
'''
// @dart = 2.8
void main() {
}
'''
);
final
File
flutterBuild
=
flutterProject
.
directory
.
childFile
(
'generated_main.dart'
);
final
PackageConfig
packageConfig
=
await
loadPackageConfigWithLogging
(
flutterProject
.
directory
.
childDirectory
(
'.dart_tool'
).
childFile
(
'package_config.json'
),
logger:
globals
.
logger
,
throwOnError:
false
,
);
final
bool
didGenerate
=
await
generateMainDartWithPluginRegistrant
(
flutterProject
,
packageConfig
,
'package:app/main.dart'
,
flutterBuild
,
mainFile
,
);
expect
(
didGenerate
,
isTrue
);
expect
(
flutterBuild
.
readAsStringSync
(),
'//
\n
'
'// Generated file. Do not edit.
\n
'
'//
\n
'
'
\n
'
'// @dart = 2.8
\n
'
'
\n
'
'import
\'
package:app/main.dart
\'
as entrypoint;
\n
'
'import
\'
dart:io
\'
; // ignore: dart_io_import.
\n
'
'import
\'
package:url_launcher_linux
${fs.path.separator}
url_launcher_linux.dart
\'
;
\n
'
'import
\'
package:awesome_macos/awesome_macos.dart
\'
;
\n
'
'import
\'
package:url_launcher_macos
${fs.path.separator}
url_launcher_macos.dart
\'
;
\n
'
'import
\'
package:url_launcher_windows
${fs.path.separator}
url_launcher_windows.dart
\'
;
\n
'
'
\n
'
'@pragma(
\'
vm:entry-point
\'
)
\n
'
'void _registerPlugins() {
\n
'
' if (Platform.isLinux) {
\n
'
' LinuxPlugin.registerWith();
\n
'
' } else if (Platform.isMacOS) {
\n
'
' AwesomeMacOS.registerWith();
\n
'
' MacOSPlugin.registerWith();
\n
'
' } else if (Platform.isWindows) {
\n
'
' WindowsPlugin.registerWith();
\n
'
' }
\n
'
'}
\n
'
'void main() {
\n
'
' entrypoint.main();
\n
'
'}
\n
'
''
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Plugin without platform support throws tool exit'
,
()
async
{
when
(
flutterProject
.
isModule
).
thenReturn
(
false
);
final
List
<
Directory
>
directories
=
<
Directory
>[];
final
Directory
fakePubCache
=
fs
.
systemTempDirectory
.
childDirectory
(
'cache'
);
final
File
packagesFile
=
flutterProject
.
directory
.
childFile
(
'.packages'
)
..
createSync
(
recursive:
true
);
final
Map
<
String
,
String
>
plugins
=
<
String
,
String
>{};
plugins
[
'url_launcher_macos'
]
=
'''
flutter:
plugin:
implements: url_launcher
platforms:
macos:
invalid:
'''
;
for
(
final
MapEntry
<
String
,
String
>
entry
in
plugins
.
entries
)
{
final
String
name
=
fs
.
path
.
basename
(
entry
.
key
);
final
Directory
pluginDirectory
=
fakePubCache
.
childDirectory
(
name
);
packagesFile
.
writeAsStringSync
(
'
$name
:file://
${pluginDirectory.childFile('lib').uri}
\n
'
,
mode:
FileMode
.
writeOnlyAppend
);
pluginDirectory
.
childFile
(
'pubspec.yaml'
)
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
entry
.
value
);
directories
.
add
(
pluginDirectory
);
}
when
(
flutterManifest
.
dependencies
).
thenReturn
(<
String
>{...
plugins
.
keys
});
final
Directory
libDir
=
flutterProject
.
directory
.
childDirectory
(
'lib'
);
libDir
.
createSync
(
recursive:
true
);
final
File
mainFile
=
libDir
.
childFile
(
'main.dart'
)..
writeAsStringSync
(
''
);
final
File
flutterBuild
=
flutterProject
.
directory
.
childFile
(
'generated_main.dart'
);
final
PackageConfig
packageConfig
=
await
loadPackageConfigWithLogging
(
flutterProject
.
directory
.
childDirectory
(
'.dart_tool'
).
childFile
(
'package_config.json'
),
logger:
globals
.
logger
,
throwOnError:
false
,
);
await
expectLater
(
generateMainDartWithPluginRegistrant
(
flutterProject
,
packageConfig
,
'package:app/main.dart'
,
flutterBuild
,
mainFile
,
),
throwsToolExit
(
message:
'Invalid plugin specification url_launcher_macos.
\n
'
'Invalid "macos" plugin specification.'
),
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Plugin with platform support without dart plugin class throws tool exit'
,
()
async
{
when
(
flutterProject
.
isModule
).
thenReturn
(
false
);
final
List
<
Directory
>
directories
=
<
Directory
>[];
final
Directory
fakePubCache
=
fs
.
systemTempDirectory
.
childDirectory
(
'cache'
);
final
File
packagesFile
=
flutterProject
.
directory
.
childFile
(
'.packages'
)
..
createSync
(
recursive:
true
);
final
Map
<
String
,
String
>
plugins
=
<
String
,
String
>{};
plugins
[
'url_launcher_macos'
]
=
'''
flutter:
plugin:
implements: url_launcher
'''
;
for
(
final
MapEntry
<
String
,
String
>
entry
in
plugins
.
entries
)
{
final
String
name
=
fs
.
path
.
basename
(
entry
.
key
);
final
Directory
pluginDirectory
=
fakePubCache
.
childDirectory
(
name
);
packagesFile
.
writeAsStringSync
(
'
$name
:file://
${pluginDirectory.childFile('lib').uri}
\n
'
,
mode:
FileMode
.
writeOnlyAppend
);
pluginDirectory
.
childFile
(
'pubspec.yaml'
)
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
entry
.
value
);
directories
.
add
(
pluginDirectory
);
}
when
(
flutterManifest
.
dependencies
).
thenReturn
(<
String
>{...
plugins
.
keys
});
final
Directory
libDir
=
flutterProject
.
directory
.
childDirectory
(
'lib'
);
libDir
.
createSync
(
recursive:
true
);
final
File
mainFile
=
libDir
.
childFile
(
'main.dart'
)..
writeAsStringSync
(
''
);
final
File
flutterBuild
=
flutterProject
.
directory
.
childFile
(
'generated_main.dart'
);
final
PackageConfig
packageConfig
=
await
loadPackageConfigWithLogging
(
flutterProject
.
directory
.
childDirectory
(
'.dart_tool'
).
childFile
(
'package_config.json'
),
logger:
globals
.
logger
,
throwOnError:
false
,
);
await
expectLater
(
generateMainDartWithPluginRegistrant
(
flutterProject
,
packageConfig
,
'package:app/main.dart'
,
flutterBuild
,
mainFile
,
),
throwsToolExit
(
message:
'Invalid plugin specification url_launcher_macos.
\n
'
'Cannot find the `flutter.plugin.platforms` key in the `pubspec.yaml` file. '
'An instruction to format the `pubspec.yaml` can be found here: '
'https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms'
),
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
group
(
'pubspec'
,
()
{
Directory
projectDir
;
...
...
@@ -1396,6 +2167,7 @@ flutter:
}
class
MockAndroidProject
extends
Mock
implements
AndroidProject
{}
class
MockFlutterManifest
extends
Mock
implements
FlutterManifest
{}
class
MockFlutterProject
extends
Mock
implements
FlutterProject
{}
class
MockIosProject
extends
Mock
implements
IosProject
{}
class
MockMacOSProject
extends
Mock
implements
MacOSProject
{}
...
...
packages/flutter_tools/test/general.shard/project_test.dart
View file @
b7d48062
...
...
@@ -110,6 +110,17 @@ void main() {
);
});
_testInMemory
(
'reads dependencies from pubspec.yaml'
,
()
async
{
final
Directory
directory
=
globals
.
fs
.
directory
(
'myproject'
);
directory
.
childFile
(
'pubspec.yaml'
)
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
validPubspecWithDependencies
);
expect
(
FlutterProject
.
fromDirectory
(
directory
).
manifest
.
dependencies
,
<
String
>{
'plugin_a'
,
'plugin_b'
},
);
});
_testInMemory
(
'sets up location'
,
()
async
{
final
Directory
directory
=
globals
.
fs
.
directory
(
'myproject'
);
expect
(
...
...
@@ -905,6 +916,16 @@ name: hello
flutter:
'''
;
String
get
validPubspecWithDependencies
=>
'''
name: hello
flutter:
dependencies:
plugin_a:
plugin_b:
'''
;
String
get
invalidPubspec
=>
'''
name: hello
flutter:
...
...
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