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
6f5f0376
Unverified
Commit
6f5f0376
authored
Feb 27, 2019
by
Jonah Williams
Committed by
GitHub
Feb 27, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add basic web device and run support (#28302)
parent
ce06ef43
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
328 additions
and
4 deletions
+328
-4
index.html
dev/integration_tests/web/web/index.html
+10
-0
application_package.dart
packages/flutter_tools/lib/src/application_package.dart
+3
-1
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+2
-0
device.dart
packages/flutter_tools/lib/src/device.dart
+9
-1
project.dart
packages/flutter_tools/lib/src/project.dart
+32
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+9
-2
compile.dart
packages/flutter_tools/lib/src/web/compile.dart
+1
-0
web_device.dart
packages/flutter_tools/lib/src/web/web_device.dart
+206
-0
index.html.tmpl
packages/flutter_tools/templates/web/index.html.tmpl
+10
-0
devices_test.dart
packages/flutter_tools/test/web/devices_test.dart
+46
-0
No files found.
dev/integration_tests/web/web/index.html
0 → 100644
View file @
6f5f0376
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
web_integration
</title>
<script
defer
src=
"main.dart.js"
type=
"application/javascript"
></script>
</head>
<body>
</body>
</html>
packages/flutter_tools/lib/src/application_package.dart
View file @
6f5f0376
...
...
@@ -21,6 +21,7 @@ import 'ios/plist_utils.dart' as plist;
import
'macos/application_package.dart'
;
import
'project.dart'
;
import
'tester/flutter_tester.dart'
;
import
'web/web_device.dart'
;
class
ApplicationPackageFactory
{
static
ApplicationPackageFactory
get
instance
=>
context
[
ApplicationPackageFactory
];
...
...
@@ -50,10 +51,11 @@ class ApplicationPackageFactory {
return
applicationBinary
!=
null
?
MacOSApp
.
fromPrebuiltApp
(
applicationBinary
)
:
null
;
case
TargetPlatform
.
web
:
return
WebApplicationPackage
(
await
FlutterProject
.
current
());
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
web
:
return
null
;
}
assert
(
platform
!=
null
);
...
...
packages/flutter_tools/lib/src/context_runner.dart
View file @
6f5f0376
...
...
@@ -41,6 +41,7 @@ import 'run_hot.dart';
import
'usage.dart'
;
import
'version.dart'
;
import
'web/compile.dart'
;
import
'web/web_device.dart'
;
import
'windows/windows_workflow.dart'
;
Future
<
T
>
runInContext
<
T
>(
...
...
@@ -65,6 +66,7 @@ Future<T> runInContext<T>(
CocoaPods:
()
=>
CocoaPods
(),
CocoaPodsValidator:
()
=>
const
CocoaPodsValidator
(),
Config:
()
=>
Config
(),
ChromeLauncher:
()
=>
const
ChromeLauncher
(),
DevFSConfig:
()
=>
DevFSConfig
(),
DeviceManager:
()
=>
DeviceManager
(),
Doctor:
()
=>
const
Doctor
(),
...
...
packages/flutter_tools/lib/src/device.dart
View file @
6f5f0376
...
...
@@ -20,6 +20,7 @@ import 'ios/simulators.dart';
import
'linux/linux_device.dart'
;
import
'macos/macos_device.dart'
;
import
'tester/flutter_tester.dart'
;
import
'web/web_device.dart'
;
import
'windows/windows_device.dart'
;
DeviceManager
get
deviceManager
=>
context
[
DeviceManager
];
...
...
@@ -36,7 +37,7 @@ class DeviceManager {
IOSSimulators
(),
FuchsiaDevices
(),
FlutterTesterDevices
(),
]
+
_conditionalDesktopDevices
);
]
+
_conditionalDesktopDevices
+
_conditionalWebDevices
);
/// Only add desktop devices if the flag is enabled.
static
List
<
DeviceDiscovery
>
get
_conditionalDesktopDevices
{
...
...
@@ -47,6 +48,13 @@ class DeviceManager {
]
:
<
DeviceDiscovery
>[];
}
/// Only add web devices if the flag is enabled.
static
List
<
DeviceDiscovery
>
get
_conditionalWebDevices
{
return
flutterWebEnabled
?
<
DeviceDiscovery
>[
WebDevices
(),
]
:
<
DeviceDiscovery
>[];
}
String
_specifiedDeviceId
;
/// A user-specified device ID.
...
...
packages/flutter_tools/lib/src/project.dart
View file @
6f5f0376
...
...
@@ -19,6 +19,7 @@ import 'ios/plist_utils.dart' as plist;
import
'ios/xcodeproj.dart'
as
xcode
;
import
'plugins.dart'
;
import
'template.dart'
;
import
'web/web_device.dart'
;
/// Represents the contents of a Flutter project at the specified [directory].
///
...
...
@@ -95,6 +96,9 @@ class FlutterProject {
/// The Android sub project of this project.
AndroidProject
get
android
=>
AndroidProject
.
_
(
this
);
/// The web sub project of this project.
WebProject
get
web
=>
WebProject
.
_
(
this
);
/// The `pubspec.yaml` file of this project.
File
get
pubspecFile
=>
directory
.
childFile
(
'pubspec.yaml'
);
...
...
@@ -150,6 +154,9 @@ class FlutterProject {
refreshPluginsList
(
this
);
await
android
.
ensureReadyForPlatformSpecificTooling
();
await
ios
.
ensureReadyForPlatformSpecificTooling
();
if
(
flutterWebEnabled
)
{
await
web
.
ensureReadyForPlatformSpecificTooling
();
}
await
injectPlugins
(
this
);
}
...
...
@@ -454,6 +461,31 @@ class AndroidProject {
}
}
/// Represents the web sub-project of a Flutter project.
class
WebProject
{
WebProject
.
_
(
this
.
parent
);
final
FlutterProject
parent
;
Future
<
void
>
ensureReadyForPlatformSpecificTooling
()
async
{
/// Generate index.html in build/web. Eventually we could support
/// a custom html under the web sub directory.
final
Directory
outputDir
=
fs
.
directory
(
getWebBuildDirectory
());
if
(!
outputDir
.
existsSync
())
{
outputDir
.
createSync
(
recursive:
true
);
}
final
Template
template
=
Template
.
fromName
(
'web/index.html.tmpl'
);
template
.
render
(
outputDir
,
<
String
,
dynamic
>{
'appName'
:
parent
.
manifest
.
appName
,
},
printStatusWhenWriting:
false
,
overwriteExisting:
true
,
);
}
}
/// Deletes [directory] with all content.
void
_deleteIfExistsSync
(
Directory
directory
)
{
if
(
directory
.
existsSync
())
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
6f5f0376
...
...
@@ -326,7 +326,11 @@ class FlutterDevice {
await
stopEchoingDeviceLog
();
return
2
;
}
if
(
result
.
hasObservatory
)
{
observatoryUris
=
<
Uri
>[
result
.
observatoryUri
];
}
else
{
observatoryUris
=
<
Uri
>[];
}
return
0
;
}
...
...
@@ -384,8 +388,11 @@ class FlutterDevice {
await
stopEchoingDeviceLog
();
return
2
;
}
if
(
result
.
hasObservatory
)
if
(
result
.
hasObservatory
)
{
observatoryUris
=
<
Uri
>[
result
.
observatoryUri
];
}
else
{
observatoryUris
=
<
Uri
>[];
}
return
0
;
}
...
...
packages/flutter_tools/lib/src/web/compile.dart
View file @
6f5f0376
...
...
@@ -38,6 +38,7 @@ class WebCompiler {
if
(!
processManager
.
canRun
(
engineDartPath
))
{
throwToolExit
(
'Unable to find Dart binary at
$engineDartPath
'
);
}
/// Compile Dart to JavaScript.
final
List
<
String
>
command
=
<
String
>[
engineDartPath
,
dart2jsPath
,
...
...
packages/flutter_tools/lib/src/web/web_device.dart
0 → 100644
View file @
6f5f0376
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'../application_package.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/platform.dart'
;
import
'../base/process_manager.dart'
;
import
'../build_info.dart'
;
import
'../device.dart'
;
import
'../globals.dart'
;
import
'../project.dart'
;
import
'../web/compile.dart'
;
ChromeLauncher
get
chromeLauncher
=>
context
[
ChromeLauncher
];
/// Only launch or display web devices if `FLUTTER_WEB`
/// environment variable is set to true.
bool
get
flutterWebEnabled
{
_flutterWebEnabled
=
platform
.
environment
[
'FLUTTER_WEB'
]?.
toLowerCase
()
==
'true'
;
return
_flutterWebEnabled
;
}
bool
_flutterWebEnabled
;
class
WebApplicationPackage
extends
ApplicationPackage
{
WebApplicationPackage
(
this
.
_flutterProject
)
:
super
(
id:
_flutterProject
.
manifest
.
appName
);
final
FlutterProject
_flutterProject
;
@override
String
get
name
=>
_flutterProject
.
manifest
.
appName
;
/// The location of the web source assets.
Directory
get
webSourcePath
=>
_flutterProject
.
directory
.
childDirectory
(
'web'
);
}
class
WebDevice
extends
Device
{
WebDevice
()
:
super
(
'web'
);
HttpServer
_server
;
WebApplicationPackage
_package
;
@override
bool
get
supportsHotReload
=>
false
;
@override
bool
get
supportsHotRestart
=>
false
;
@override
bool
get
supportsStartPaused
=>
true
;
@override
bool
get
supportsStopApp
=>
true
;
@override
bool
get
supportsScreenshot
=>
false
;
@override
void
clearLogs
()
{}
@override
DeviceLogReader
getLogReader
({
ApplicationPackage
app
})
{
return
NoOpDeviceLogReader
(
app
.
name
);
}
@override
Future
<
bool
>
installApp
(
ApplicationPackage
app
)
async
=>
true
;
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
async
=>
true
;
@override
Future
<
bool
>
isLatestBuildInstalled
(
ApplicationPackage
app
)
async
=>
true
;
@override
Future
<
bool
>
get
isLocalEmulator
async
=>
false
;
@override
bool
isSupported
()
=>
flutterWebEnabled
;
@override
String
get
name
=>
'web'
;
@override
DevicePortForwarder
get
portForwarder
=>
const
NoOpDevicePortForwarder
();
@override
Future
<
String
>
get
sdkNameAndVersion
async
=>
'web'
;
@override
Future
<
LaunchResult
>
startApp
(
covariant
WebApplicationPackage
package
,
{
String
mainPath
,
String
route
,
DebuggingOptions
debuggingOptions
,
Map
<
String
,
Object
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
applicationNeedsRebuild
=
false
,
bool
usesTerminalUi
=
true
,
bool
ipv6
=
false
,
})
async
{
final
Status
status
=
logger
.
startProgress
(
'Compiling
${package.name}
to JavaScript...'
,
timeout:
null
);
final
int
result
=
await
webCompiler
.
compile
(
target:
mainPath
,
minify:
false
,
enabledAssertions:
true
);
status
.
stop
();
if
(
result
!=
0
)
{
printError
(
'Failed to compile
${package.name}
to JavaScript'
);
return
LaunchResult
.
failed
();
}
_package
=
package
;
_server
=
await
HttpServer
.
bind
(
InternetAddress
.
loopbackIPv4
,
0
);
_server
.
listen
(
_basicAssetServer
);
printStatus
(
'Serving assets from http:localhost:
${_server.port}
'
);
await
chromeLauncher
.
launch
(
'http:localhost:
${_server.port}
'
);
return
LaunchResult
.
succeeded
(
observatoryUri:
null
);
}
// Note: we don't currently have a way to track which chrome processes
// belong to the flutter tool, so we'll err on the side of caution by
// keeping these open.
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
await
_server
?.
close
();
_server
=
null
;
return
true
;
}
@override
Future
<
TargetPlatform
>
get
targetPlatform
async
=>
TargetPlatform
.
web
;
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
void
>
_basicAssetServer
(
HttpRequest
request
)
async
{
if
(
request
.
method
!=
'GET'
)
{
request
.
response
.
statusCode
=
HttpStatus
.
forbidden
;
await
request
.
response
.
close
();
return
;
}
// Resolve all get requests to the build/web/asset directory.
final
Uri
uri
=
request
.
uri
;
File
file
;
String
contentType
;
if
(
uri
.
path
==
'/'
)
{
file
=
_package
.
webSourcePath
.
childFile
(
'index.html'
);
contentType
=
'text/html'
;
}
else
if
(
uri
.
path
==
'/main.dart.js'
)
{
file
=
fs
.
file
(
fs
.
path
.
join
(
getWebBuildDirectory
(),
'main.dart.js'
));
contentType
=
'text/javascript'
;
}
else
{
file
=
fs
.
file
(
fs
.
path
.
join
(
getAssetBuildDirectory
(),
uri
.
path
));
}
if
(!
file
.
existsSync
())
{
request
.
response
.
statusCode
=
HttpStatus
.
notFound
;
await
request
.
response
.
close
();
return
;
}
request
.
response
.
statusCode
=
HttpStatus
.
ok
;
if
(
contentType
!=
null
)
{
request
.
response
.
headers
.
add
(
HttpHeaders
.
contentTypeHeader
,
contentType
);
}
await
request
.
response
.
addStream
(
file
.
openRead
());
await
request
.
response
.
close
();
}
}
class
WebDevices
extends
PollingDeviceDiscovery
{
WebDevices
()
:
super
(
'web'
);
final
WebDevice
_webDevice
=
WebDevice
();
@override
bool
get
canListAnything
=>
flutterWebEnabled
;
@override
Future
<
List
<
Device
>>
pollingGetDevices
()
async
{
return
<
Device
>[
_webDevice
,
];
}
@override
bool
get
supportsPlatform
=>
flutterWebEnabled
;
}
// Responsible for launching chrome with devtools configured.
class
ChromeLauncher
{
const
ChromeLauncher
();
static
const
String
_kMacosLocation
=
'/Applications/Google
\
Chrome.app/Contents/MacOS/Google
\
Chrome'
;
Future
<
void
>
launch
(
String
host
)
async
{
if
(
platform
.
isMacOS
)
{
await
processManager
.
start
(<
String
>[
_kMacosLocation
,
host
,
]);
}
throw
UnsupportedError
(
'
$platform
is not supported'
);
}
}
packages/flutter_tools/templates/web/index.html.tmpl
0 → 100644
View file @
6f5f0376
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
{{appName}}
</title>
<script
defer
src=
"main.dart.js"
type=
"application/javascript"
></script>
</head>
<body>
</body>
</html>
packages/flutter_tools/test/web/devices_test.dart
0 → 100644
View file @
6f5f0376
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/web/compile.dart'
;
import
'package:flutter_tools/src/web/web_device.dart'
;
import
'package:mockito/mockito.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
void
main
(
)
{
group
(
WebDevice
,
()
{
final
MockWebCompiler
mockWebCompiler
=
MockWebCompiler
();
final
MockChromeLauncher
mockChromeLauncher
=
MockChromeLauncher
();
final
MockPlatform
mockPlatform
=
MockPlatform
();
FlutterProject
flutterProject
;
setUp
(()
async
{
flutterProject
=
await
FlutterProject
.
fromPath
(
fs
.
path
.
join
(
getFlutterRoot
(),
'dev'
,
'integration_tests'
,
'web'
));
when
(
mockWebCompiler
.
compile
(
target:
anyNamed
(
'target'
),
minify:
anyNamed
(
'minify'
),
enabledAssertions:
anyNamed
(
'enabledAssertions'
),
)).
thenAnswer
((
Invocation
invocation
)
async
=>
0
);
when
(
mockChromeLauncher
.
launch
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{});
});
testUsingContext
(
'can build and connect to chrome'
,
()
async
{
final
WebDevice
device
=
WebDevice
();
await
device
.
startApp
(
WebApplicationPackage
(
flutterProject
));
},
overrides:
<
Type
,
Generator
>{
ChromeLauncher:
()
=>
mockChromeLauncher
,
WebCompiler:
()
=>
mockWebCompiler
,
Platform:
()
=>
mockPlatform
,
});
});
}
class
MockChromeLauncher
extends
Mock
implements
ChromeLauncher
{}
class
MockWebCompiler
extends
Mock
implements
WebCompiler
{}
class
MockPlatform
extends
Mock
implements
Platform
{}
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