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
55f3da7a
Unverified
Commit
55f3da7a
authored
Dec 20, 2018
by
Stanislav Baranov
Committed by
GitHub
Dec 20, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Flutter tool support for building dynamic updates (#25576)
parent
a282058d
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
520 additions
and
79 deletions
+520
-79
flutter.gradle
packages/flutter_tools/gradle/flutter.gradle
+28
-7
gradle.dart
packages/flutter_tools/lib/src/android/gradle.dart
+70
-2
application_package.dart
packages/flutter_tools/lib/src/application_package.dart
+25
-0
build.dart
packages/flutter_tools/lib/src/base/build.dart
+74
-5
build_info.dart
packages/flutter_tools/lib/src/build_info.dart
+26
-3
bundle.dart
packages/flutter_tools/lib/src/bundle.dart
+6
-2
build_apk.dart
packages/flutter_tools/lib/src/commands/build_apk.dart
+3
-1
build_bundle.dart
packages/flutter_tools/lib/src/commands/build_bundle.dart
+18
-19
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+2
-17
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+90
-6
build_test.dart
packages/flutter_tools/test/base/build_test.dart
+177
-17
mocks.dart
packages/flutter_tools/test/src/mocks.dart
+1
-0
No files found.
packages/flutter_tools/gradle/flutter.gradle
View file @
55f3da7a
...
...
@@ -321,9 +321,17 @@ class FlutterPlugin implements Plugin<Project> {
if
(
project
.
hasProperty
(
'precompile'
))
{
compilationTraceFilePathValue
=
project
.
property
(
'precompile'
)
}
Boolean
buildHotUpdateValue
=
false
if
(
project
.
hasProperty
(
'hotupdate'
))
{
buildHotUpdateValue
=
project
.
property
(
'hotupdate'
).
toBoolean
()
Boolean
createPatchValue
=
false
if
(
project
.
hasProperty
(
'patch'
))
{
createPatchValue
=
project
.
property
(
'patch'
).
toBoolean
()
}
Integer
buildNumberValue
=
null
if
(
project
.
hasProperty
(
'build-number'
))
{
buildNumberValue
=
project
.
property
(
'build-number'
).
toInteger
()
}
String
baselineDirValue
=
null
if
(
project
.
hasProperty
(
'baseline-dir'
))
{
baselineDirValue
=
project
.
property
(
'baseline-dir'
)
}
String
extraFrontEndOptionsValue
=
null
if
(
project
.
hasProperty
(
'extra-front-end-options'
))
{
...
...
@@ -367,7 +375,9 @@ class FlutterPlugin implements Plugin<Project> {
fileSystemScheme
fileSystemSchemeValue
trackWidgetCreation
trackWidgetCreationValue
compilationTraceFilePath
compilationTraceFilePathValue
buildHotUpdate
buildHotUpdateValue
createPatch
createPatchValue
buildNumber
buildNumberValue
baselineDir
baselineDirValue
buildSharedLibrary
buildSharedLibraryValue
targetPlatform
targetPlatformValue
sourceDir
project
.
file
(
project
.
flutter
.
source
)
...
...
@@ -428,7 +438,11 @@ abstract class BaseFlutterTask extends DefaultTask {
@Optional
@Input
String
compilationTraceFilePath
@Optional
@Input
Boolean
buildHotUpdate
Boolean
createPatch
@Optional
@Input
Integer
buildNumber
@Optional
@Input
String
baselineDir
@Optional
@Input
Boolean
buildSharedLibrary
@Optional
@Input
...
...
@@ -523,8 +537,15 @@ abstract class BaseFlutterTask extends DefaultTask {
if
(
compilationTraceFilePath
!=
null
)
{
args
"--precompile"
,
compilationTraceFilePath
}
if
(
buildHotUpdate
)
{
args
"--hotupdate"
if
(
createPatch
)
{
args
"--patch"
args
"--build-number"
,
project
.
android
.
defaultConfig
.
versionCode
if
(
buildNumber
!=
null
)
{
assert
buildNumber
==
project
.
android
.
defaultConfig
.
versionCode
}
}
if
(
baselineDir
!=
null
)
{
args
"--baseline-dir"
,
baselineDir
}
if
(
extraFrontEndOptions
!=
null
)
{
args
"--extra-front-end-options"
,
"${extraFrontEndOptions}"
...
...
packages/flutter_tools/lib/src/android/gradle.dart
View file @
55f3da7a
...
...
@@ -3,10 +3,13 @@
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:convert'
;
import
'package:archive/archive.dart'
;
import
'package:meta/meta.dart'
;
import
'../android/android_sdk.dart'
;
import
'../application_package.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
...
...
@@ -374,8 +377,8 @@ Future<void> _buildGradleProjectV2(
command
.
add
(
'-Ptrack-widget-creation=
${buildInfo.trackWidgetCreation}
'
);
if
(
buildInfo
.
compilationTraceFilePath
!=
null
)
command
.
add
(
'-Pprecompile=
${buildInfo.compilationTraceFilePath}
'
);
if
(
buildInfo
.
buildHotUpdate
)
command
.
add
(
'-P
hotupdate
=true'
);
if
(
buildInfo
.
createPatch
)
command
.
add
(
'-P
patch
=true'
);
if
(
buildInfo
.
extraFrontEndOptions
!=
null
)
command
.
add
(
'-Pextra-front-end-options=
${buildInfo.extraFrontEndOptions}
'
);
if
(
buildInfo
.
extraGenSnapshotOptions
!=
null
)
...
...
@@ -420,6 +423,71 @@ Future<void> _buildGradleProjectV2(
appSize
=
' (
${getSizeAsMB(apkFile.lengthSync())}
)'
;
}
printStatus
(
'Built
${fs.path.relative(apkFile.path)}$appSize
.'
);
final
AndroidApk
package
=
AndroidApk
.
fromApk
(
apkFile
);
final
File
baselineApkFile
=
fs
.
directory
(
buildInfo
.
baselineDir
).
childFile
(
'
${package.versionCode}
.apk'
);
if
(
buildInfo
.
createBaseline
)
{
// Save baseline apk for generating dynamic patches in later builds.
baselineApkFile
.
parent
.
createSync
(
recursive:
true
);
apkFile
.
copySync
(
baselineApkFile
.
path
);
printStatus
(
'Saved baseline package
${baselineApkFile.path}
.'
);
}
if
(
buildInfo
.
createPatch
)
{
if
(!
baselineApkFile
.
existsSync
())
throwToolExit
(
'Error: Could not find baseline package
${baselineApkFile.path}
.'
);
printStatus
(
'Found baseline package
${baselineApkFile.path}
.'
);
final
Archive
newApk
=
ZipDecoder
().
decodeBytes
(
apkFile
.
readAsBytesSync
());
final
Archive
oldApk
=
ZipDecoder
().
decodeBytes
(
baselineApkFile
.
readAsBytesSync
());
final
Archive
update
=
Archive
();
for
(
ArchiveFile
newFile
in
newApk
)
{
if
(!
newFile
.
isFile
||
!
newFile
.
name
.
startsWith
(
'assets/flutter_assets/'
))
continue
;
final
ArchiveFile
oldFile
=
oldApk
.
findFile
(
newFile
.
name
);
if
(
oldFile
!=
null
&&
oldFile
.
crc32
==
newFile
.
crc32
)
continue
;
final
String
name
=
fs
.
path
.
relative
(
newFile
.
name
,
from:
'assets/'
);
update
.
addFile
(
ArchiveFile
(
name
,
newFile
.
content
.
length
,
newFile
.
content
));
}
final
File
updateFile
=
fs
.
directory
(
buildInfo
.
patchDir
)
.
childFile
(
'
${package.versionCode}
-
${buildInfo.patchNumber}
.zip'
);
if
(
update
.
files
.
isEmpty
)
{
printStatus
(
'No changes detected relative to baseline build.'
);
if
(
updateFile
.
existsSync
())
{
updateFile
.
deleteSync
();
printStatus
(
'Deleted dynamic patch
${updateFile.path}
.'
);
}
return
;
}
final
ArchiveFile
oldFile
=
oldApk
.
findFile
(
'assets/flutter_assets/isolate_snapshot_data'
);
if
(
oldFile
==
null
)
throwToolExit
(
'Error: Could not find baseline assets/flutter_assets/isolate_snapshot_data.'
);
final
int
baselineChecksum
=
getCrc32
(
oldFile
.
content
);
final
Map
<
String
,
dynamic
>
manifest
=
<
String
,
dynamic
>{
'baselineChecksum'
:
baselineChecksum
,
'buildNumber'
:
package
.
versionCode
,
'patchNumber'
:
buildInfo
.
patchNumber
,
};
const
JsonEncoder
encoder
=
JsonEncoder
.
withIndent
(
' '
);
final
String
manifestJson
=
encoder
.
convert
(
manifest
);
update
.
addFile
(
ArchiveFile
(
'manifest.json'
,
manifestJson
.
length
,
manifestJson
.
codeUnits
));
updateFile
.
parent
.
createSync
(
recursive:
true
);
updateFile
.
writeAsBytesSync
(
ZipEncoder
().
encode
(
update
),
flush:
true
);
printStatus
(
'Created dynamic patch
${updateFile.path}
.'
);
}
}
File
_findApkFile
(
GradleProject
project
,
BuildInfo
buildInfo
)
{
...
...
packages/flutter_tools/lib/src/application_package.dart
View file @
55f3da7a
...
...
@@ -41,6 +41,7 @@ class AndroidApk extends ApplicationPackage {
AndroidApk
({
String
id
,
@required
this
.
file
,
@required
this
.
versionCode
,
@required
this
.
launchActivity
})
:
assert
(
file
!=
null
),
assert
(
launchActivity
!=
null
),
...
...
@@ -78,6 +79,7 @@ class AndroidApk extends ApplicationPackage {
return
AndroidApk
(
id:
data
.
packageName
,
file:
apk
,
versionCode:
int
.
tryParse
(
data
.
versionCode
),
launchActivity:
'
${data.packageName}
/
${data.launchableActivityName}
'
);
}
...
...
@@ -88,6 +90,9 @@ class AndroidApk extends ApplicationPackage {
/// The path to the activity that should be launched.
final
String
launchActivity
;
/// The version code of the APK.
final
int
versionCode
;
/// Creates a new AndroidApk based on the information in the Android manifest.
static
Future
<
AndroidApk
>
fromAndroidProject
(
AndroidProject
androidProject
)
async
{
File
apkFile
;
...
...
@@ -138,6 +143,7 @@ class AndroidApk extends ApplicationPackage {
return
AndroidApk
(
id:
packageId
,
file:
apkFile
,
versionCode:
null
,
launchActivity:
launchActivity
);
}
...
...
@@ -449,8 +455,25 @@ class ApkManifestData {
final
String
activityName
=
nameAttribute
.
value
.
substring
(
1
,
nameAttribute
.
value
.
indexOf
(
'" '
));
// Example format: (type 0x10)0x1
final
_Attribute
versionCodeAttr
=
manifest
.
firstAttribute
(
'android:versionCode'
);
if
(
versionCodeAttr
==
null
)
{
printError
(
'Error running
$packageName
. Manifest versionCode not found'
);
return
null
;
}
if
(!
versionCodeAttr
.
value
.
startsWith
(
'(type 0x10)'
))
{
printError
(
'Error running
$packageName
. Manifest versionCode invalid'
);
return
null
;
}
final
int
versionCode
=
int
.
tryParse
(
versionCodeAttr
.
value
.
substring
(
11
));
if
(
versionCode
==
null
)
{
printError
(
'Error running
$packageName
. Manifest versionCode invalid'
);
return
null
;
}
final
Map
<
String
,
Map
<
String
,
String
>>
map
=
<
String
,
Map
<
String
,
String
>>{};
map
[
'package'
]
=
<
String
,
String
>{
'name'
:
packageName
};
map
[
'version-code'
]
=
<
String
,
String
>{
'name'
:
versionCode
.
toString
()};
map
[
'launchable-activity'
]
=
<
String
,
String
>{
'name'
:
activityName
};
return
ApkManifestData
.
_
(
map
);
...
...
@@ -464,6 +487,8 @@ class ApkManifestData {
String
get
packageName
=>
_data
[
'package'
]
==
null
?
null
:
_data
[
'package'
][
'name'
];
String
get
versionCode
=>
_data
[
'version-code'
]
==
null
?
null
:
_data
[
'version-code'
][
'name'
];
String
get
launchableActivityName
{
return
_data
[
'launchable-activity'
]
==
null
?
null
:
_data
[
'launchable-activity'
][
'name'
];
}
...
...
packages/flutter_tools/lib/src/base/build.dart
View file @
55f3da7a
...
...
@@ -4,6 +4,8 @@
import
'dart:async'
;
import
'package:archive/archive.dart'
;
import
'package:collection/collection.dart'
;
import
'package:meta/meta.dart'
;
import
'../android/android_sdk.dart'
;
...
...
@@ -348,7 +350,9 @@ class JITSnapshotter {
@required
String
packagesPath
,
@required
String
outputPath
,
@required
String
compilationTraceFilePath
,
@required
bool
buildHotUpdate
,
@required
bool
createPatch
,
int
buildNumber
,
String
baselineDir
,
List
<
String
>
extraGenSnapshotOptions
=
const
<
String
>[],
})
async
{
if
(!
_isValidJitPlatform
(
platform
))
{
...
...
@@ -367,8 +371,73 @@ class JITSnapshotter {
final
List
<
String
>
inputPaths
=
<
String
>[
mainPath
,
compilationTraceFilePath
,
engineVmSnapshotData
,
engineIsolateSnapshotData
,
];
if
(
buildHotUpdate
)
{
if
(
createPatch
)
{
inputPaths
.
add
(
isolateSnapshotInstructions
);
if
(
buildNumber
==
null
)
{
printError
(
'Error: Dynamic patching requires --build-number specified'
);
return
1
;
}
if
(
baselineDir
==
null
)
{
printError
(
'Error: Dynamic patching requires --baseline-dir specified'
);
return
1
;
}
final
File
baselineApk
=
fs
.
directory
(
baselineDir
).
childFile
(
'
$buildNumber
.apk'
);
if
(!
baselineApk
.
existsSync
())
{
printError
(
'Error: Could not find baseline package
${baselineApk.path}
.'
);
return
1
;
}
final
Archive
baselinePkg
=
ZipDecoder
().
decodeBytes
(
baselineApk
.
readAsBytesSync
());
{
final
File
f
=
fs
.
file
(
isolateSnapshotInstructions
);
final
ArchiveFile
af
=
baselinePkg
.
findFile
(
fs
.
path
.
join
(
'assets/flutter_assets/isolate_snapshot_instr'
));
if
(
af
==
null
)
{
printError
(
'Error: Invalid baseline package
${baselineApk.path}
.'
);
return
1
;
}
// When building an update, gen_snapshot expects to find the original isolate
// snapshot instructions from the previous full build, so we need to extract
// it from saves baseline APK.
if
(!
f
.
existsSync
())
{
f
.
writeAsBytesSync
(
af
.
content
,
flush:
true
);
}
else
{
// But if this file is already extracted, we make sure that it's identical.
final
Function
contentEquals
=
const
ListEquality
<
int
>().
equals
;
if
(!
contentEquals
(
f
.
readAsBytesSync
(),
af
.
content
))
{
printError
(
'Error: Detected changes unsupported by dynamic patching.'
);
return
1
;
}
}
}
{
final
File
f
=
fs
.
file
(
engineVmSnapshotData
);
final
ArchiveFile
af
=
baselinePkg
.
findFile
(
fs
.
path
.
join
(
'assets/flutter_assets/vm_snapshot_data'
));
if
(
af
==
null
)
{
printError
(
'Error: Invalid baseline package
${baselineApk.path}
.'
);
return
1
;
}
// If engine snapshot artifact doesn't exist, gen_snapshot below will fail
// with a friendly error, so we don't need to handle this case here too.
if
(
f
.
existsSync
())
{
// But if engine snapshot exists, its content must match the engine snapshot
// in baseline APK. Otherwise, we're trying to build an update at an engine
// version that might be binary incompatible with baseline APK.
final
Function
contentEquals
=
const
ListEquality
<
int
>().
equals
;
if
(!
contentEquals
(
f
.
readAsBytesSync
(),
af
.
content
))
{
printError
(
'Error: Detected engine changes unsupported by dynamic patching.'
);
return
1
;
}
}
}
}
final
String
depfilePath
=
fs
.
path
.
join
(
outputDir
.
path
,
'snapshot.d'
);
...
...
@@ -385,7 +454,7 @@ class JITSnapshotter {
final
Set
<
String
>
outputPaths
=
Set
<
String
>();
outputPaths
.
addAll
(<
String
>[
isolateSnapshotData
]);
if
(!
buildHotUpdate
)
{
if
(!
createPatch
)
{
outputPaths
.
add
(
isolateSnapshotInstructions
);
}
...
...
@@ -397,7 +466,7 @@ class JITSnapshotter {
'--isolate_snapshot_data=
$isolateSnapshotData
'
,
]);
if
(!
buildHotUpdate
)
{
if
(!
createPatch
)
{
genSnapshotArgs
.
add
(
'--isolate_snapshot_instructions=
$isolateSnapshotInstructions
'
);
}
else
{
genSnapshotArgs
.
add
(
'--reused_instructions=
$isolateSnapshotInstructions
'
);
...
...
@@ -429,7 +498,7 @@ class JITSnapshotter {
'buildMode'
:
buildMode
.
toString
(),
'targetPlatform'
:
platform
.
toString
(),
'entryPoint'
:
mainPath
,
'
buildHotUpdate'
:
buildHotUpdate
.
toString
(),
'
createPatch'
:
createPatch
.
toString
(),
'extraGenSnapshotOptions'
:
extraGenSnapshotOptions
.
join
(
' '
),
},
depfilePaths:
<
String
>[],
...
...
packages/flutter_tools/lib/src/build_info.dart
View file @
55f3da7a
...
...
@@ -13,7 +13,11 @@ class BuildInfo {
const
BuildInfo
(
this
.
mode
,
this
.
flavor
,
{
this
.
trackWidgetCreation
=
false
,
this
.
compilationTraceFilePath
,
this
.
buildHotUpdate
,
this
.
createBaseline
,
this
.
createPatch
,
this
.
patchNumber
,
this
.
patchDir
,
this
.
baselineDir
,
this
.
extraFrontEndOptions
,
this
.
extraGenSnapshotOptions
,
this
.
buildSharedLibrary
,
...
...
@@ -43,8 +47,24 @@ class BuildInfo {
/// Dart compilation trace file to use for JIT VM snapshot.
final
String
compilationTraceFilePath
;
/// Save baseline package.
final
bool
createBaseline
;
/// Build differential snapshot.
final
bool
buildHotUpdate
;
final
bool
createPatch
;
/// Internal version number of dynamic patch (not displayed to users).
/// Each patch should have a unique number to differentiate from previous
/// patches for the same versionCode on Android or CFBundleVersion on iOS.
final
int
patchNumber
;
/// The directory where to store generated dynamic patches.
final
String
patchDir
;
/// The directory where to store generated baseline packages.
/// Built packages, such as APK files on Android, are saved and can be used
/// to generate dynamic patches in later builds.
final
String
baselineDir
;
/// Extra command-line options for front-end.
final
String
extraFrontEndOptions
;
...
...
@@ -92,6 +112,9 @@ class BuildInfo {
/// Exactly one of [isDebug], [isProfile], or [isRelease] is true.
bool
get
isRelease
=>
mode
==
BuildMode
.
release
||
mode
==
BuildMode
.
dynamicRelease
;
/// Returns whether a dynamic build is requested.
bool
get
isDynamic
=>
mode
==
BuildMode
.
dynamicProfile
||
mode
==
BuildMode
.
dynamicRelease
;
bool
get
usesAot
=>
isAotBuildMode
(
mode
);
bool
get
supportsEmulator
=>
isEmulatorBuildMode
(
mode
);
bool
get
supportsSimulator
=>
isEmulatorBuildMode
(
mode
);
...
...
@@ -101,7 +124,7 @@ class BuildInfo {
BuildInfo
(
mode
,
flavor
,
trackWidgetCreation:
trackWidgetCreation
,
compilationTraceFilePath:
compilationTraceFilePath
,
buildHotUpdate:
buildHotUpdate
,
createPatch:
createPatch
,
extraFrontEndOptions:
extraFrontEndOptions
,
extraGenSnapshotOptions:
extraGenSnapshotOptions
,
buildSharedLibrary:
buildSharedLibrary
,
...
...
packages/flutter_tools/lib/src/bundle.dart
View file @
55f3da7a
...
...
@@ -60,7 +60,9 @@ Future<void> build({
bool
reportLicensedPackages
=
false
,
bool
trackWidgetCreation
=
false
,
String
compilationTraceFilePath
,
bool
buildHotUpdate
=
false
,
bool
createPatch
=
false
,
int
buildNumber
,
String
baselineDir
,
List
<
String
>
extraFrontEndOptions
=
const
<
String
>[],
List
<
String
>
extraGenSnapshotOptions
=
const
<
String
>[],
List
<
String
>
fileSystemRoots
,
...
...
@@ -108,7 +110,9 @@ Future<void> build({
packagesPath:
packagesPath
,
compilationTraceFilePath:
compilationTraceFilePath
,
extraGenSnapshotOptions:
extraGenSnapshotOptions
,
buildHotUpdate:
buildHotUpdate
,
createPatch:
createPatch
,
buildNumber:
buildNumber
,
baselineDir:
baselineDir
,
);
if
(
snapshotExitCode
!=
0
)
{
throwToolExit
(
'Snapshotting exited with non-zero exit code:
$snapshotExitCode
'
);
...
...
packages/flutter_tools/lib/src/commands/build_apk.dart
View file @
55f3da7a
...
...
@@ -12,7 +12,9 @@ import 'build.dart';
class
BuildApkCommand
extends
BuildSubCommand
{
BuildApkCommand
({
bool
verboseHelp
=
false
})
{
usesTargetOption
();
addBuildModeFlags
();
addBuildModeFlags
(
verboseHelp:
verboseHelp
);
addDynamicModeFlags
(
verboseHelp:
verboseHelp
);
addDynamicPatchingFlags
(
verboseHelp:
verboseHelp
);
usesFlavorOption
();
usesPubOption
();
usesBuildNumberOption
();
...
...
packages/flutter_tools/lib/src/commands/build_bundle.dart
View file @
55f3da7a
...
...
@@ -4,6 +4,8 @@
import
'dart:async'
;
import
'package:args/command_runner.dart'
;
import
'../base/common.dart'
;
import
'../build_info.dart'
;
import
'../bundle.dart'
;
...
...
@@ -14,7 +16,10 @@ class BuildBundleCommand extends BuildSubCommand {
BuildBundleCommand
({
bool
verboseHelp
=
false
})
{
usesTargetOption
();
usesFilesystemOptions
(
hide:
!
verboseHelp
);
addBuildModeFlags
();
usesBuildNumberOption
();
addBuildModeFlags
(
verboseHelp:
verboseHelp
);
addDynamicModeFlags
(
verboseHelp:
verboseHelp
);
addDynamicBaselineFlags
(
verboseHelp:
verboseHelp
);
argParser
..
addFlag
(
'precompiled'
,
negatable:
false
)
// This option is still referenced by the iOS build scripts. We should
...
...
@@ -31,23 +36,6 @@ class BuildBundleCommand extends BuildSubCommand {
hide:
!
verboseHelp
,
help:
'Track widget creation locations. Requires Dart 2.0 functionality.'
,
)
..
addOption
(
'precompile'
,
hide:
!
verboseHelp
,
help:
'Precompile functions specified in input file. This flag is only '
'allowed when using --dynamic. It takes a Dart compilation trace '
'file produced by the training run of the application. With this '
'flag, instead of using default Dart VM snapshot provided by the '
'engine, the application will use its own snapshot that includes '
'additional compiled functions.'
)
..
addFlag
(
'hotupdate'
,
hide:
!
verboseHelp
,
help:
'Build differential snapshot based on the last state of the build '
'tree and any changes to the application source code since then. '
'This flag is only allowed when using --dynamic. With this flag, '
'a partial VM snapshot is generated that is loaded on top of the '
'original VM snapshot that contains precompiled code.'
)
..
addMultiOption
(
FlutterOptions
.
kExtraFrontEndOptions
,
splitCommas:
true
,
hide:
true
,
...
...
@@ -86,6 +74,15 @@ class BuildBundleCommand extends BuildSubCommand {
final
BuildMode
buildMode
=
getBuildMode
();
int
buildNumber
;
try
{
buildNumber
=
argResults
[
'build-number'
]
!=
null
?
int
.
parse
(
argResults
[
'build-number'
])
:
null
;
}
catch
(
e
)
{
throw
UsageException
(
'--build-number (
${argResults['build-number']}
) must be an int.'
,
null
);
}
await
build
(
platform:
platform
,
buildMode:
buildMode
,
...
...
@@ -98,7 +95,9 @@ class BuildBundleCommand extends BuildSubCommand {
reportLicensedPackages:
argResults
[
'report-licensed-packages'
],
trackWidgetCreation:
argResults
[
'track-widget-creation'
],
compilationTraceFilePath:
argResults
[
'precompile'
],
buildHotUpdate:
argResults
[
'hotupdate'
],
createPatch:
argResults
[
'patch'
],
buildNumber:
buildNumber
,
baselineDir:
argResults
[
'baseline-dir'
],
extraFrontEndOptions:
argResults
[
FlutterOptions
.
kExtraFrontEndOptions
],
extraGenSnapshotOptions:
argResults
[
FlutterOptions
.
kExtraGenSnapshotOptions
],
fileSystemScheme:
argResults
[
'filesystem-scheme'
],
...
...
packages/flutter_tools/lib/src/commands/run.dart
View file @
55f3da7a
...
...
@@ -24,6 +24,8 @@ abstract class RunCommandBase extends FlutterCommand {
// Used by run and drive commands.
RunCommandBase
({
bool
verboseHelp
=
false
})
{
addBuildModeFlags
(
defaultToRelease:
false
,
verboseHelp:
verboseHelp
);
addDynamicModeFlags
(
verboseHelp:
verboseHelp
);
addDynamicPatchingFlags
(
verboseHelp:
verboseHelp
);
usesFlavorOption
();
argParser
..
addFlag
(
'trace-startup'
,
...
...
@@ -104,23 +106,6 @@ class RunCommand extends RunCommandBase {
hide:
!
verboseHelp
,
help:
'Specify a pre-built application binary to use when running.'
,
)
..
addOption
(
'precompile'
,
hide:
!
verboseHelp
,
help:
'Precompile functions specified in input file. This flag is only '
'allowed when using --dynamic. It takes a Dart compilation trace '
'file produced by the training run of the application. With this '
'flag, instead of using default Dart VM snapshot provided by the '
'engine, the application will use its own snapshot that includes '
'additional functions.'
)
..
addFlag
(
'hotupdate'
,
hide:
!
verboseHelp
,
help:
'Build differential snapshot based on the last state of the build '
'tree and any changes to the application source code since then. '
'This flag is only allowed when using --dynamic. With this flag, '
'a partial VM snapshot is generated that is loaded on top of the '
'original VM snapshot that contains precompiled code.'
)
..
addFlag
(
'track-widget-creation'
,
hide:
!
verboseHelp
,
help:
'Track widget creation locations. Requires Dart 2.0 functionality.'
,
...
...
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
55f3da7a
...
...
@@ -241,6 +241,64 @@ abstract class FlutterCommand extends Command<void> {
'--release or --profile; --debug always has this enabled.'
);
}
void
addDynamicModeFlags
({
bool
verboseHelp
=
false
})
{
argParser
.
addOption
(
'precompile'
,
hide:
!
verboseHelp
,
help:
'Precompile functions specified in input file. This flag is only '
'allowed when using --dynamic. It takes a Dart compilation trace '
'file produced by the training run of the application. With this '
'flag, instead of using default Dart VM snapshot provided by the '
'engine, the application will use its own snapshot that includes '
'additional compiled functions.'
);
argParser
.
addFlag
(
'patch'
,
hide:
!
verboseHelp
,
negatable:
false
,
help:
'Generate dynamic patch for current changes from baseline.
\n
'
'Dynamic patch is generated relative to baseline package.
\n
'
'This flag is only allowed when using --dynamic.
\n
'
);
}
void
addDynamicPatchingFlags
({
bool
verboseHelp
=
false
})
{
argParser
.
addOption
(
'patch-number'
,
defaultsTo:
'1'
,
hide:
!
verboseHelp
,
help:
'An integer used as an internal version number for dynamic patch.
\n
'
'Each update should have a unique number to differentiate from previous '
'patches for same
\'
versionCode
\'
on Android or
\'
CFBundleVersion
\'
on iOS.
\n
'
'This flag is only used when --dynamic --patch is specified.
\n
'
);
argParser
.
addOption
(
'patch-dir'
,
defaultsTo:
'public'
,
hide:
!
verboseHelp
,
help:
'The directory where to store generated dynamic patches.
\n
'
'This directory can be deployed to a CDN such as Firebase Hosting.
\n
'
'It is recommended to store this directory in version control.
\n
'
'This flag is only used when --dynamic --patch is specified.
\n
'
);
argParser
.
addFlag
(
'baseline'
,
hide:
!
verboseHelp
,
negatable:
false
,
help:
'Save built package as baseline for future dynamic patching.
\n
'
'Built package, such as APK file on Android, is saved and '
'can be used to generate dynamic patches in later builds.
\n
'
'This flag is only allowed when using --dynamic.
\n
'
);
addDynamicBaselineFlags
(
verboseHelp:
verboseHelp
);
}
void
addDynamicBaselineFlags
({
bool
verboseHelp
=
false
})
{
argParser
.
addOption
(
'baseline-dir'
,
defaultsTo:
'.baseline'
,
hide:
!
verboseHelp
,
help:
'The directory where to store and find generated baseline packages.
\n
'
'It is recommended to store this directory in version control.
\n
'
'This flag is only used when --dynamic --baseline is specified.
\n
'
);
}
void
usesFuchsiaOptions
({
bool
hide
=
false
})
{
argParser
.
addOption
(
'target-model'
,
...
...
@@ -308,6 +366,16 @@ abstract class FlutterCommand extends Command<void> {
'--build-number (
${argResults['build-number']}
) must be an int.'
,
null
);
}
int
patchNumber
;
try
{
patchNumber
=
argParser
.
options
.
containsKey
(
'patch-number'
)
&&
argResults
[
'patch-number'
]
!=
null
?
int
.
parse
(
argResults
[
'patch-number'
])
:
null
;
}
catch
(
e
)
{
throw
UsageException
(
'--patch-number (
${argResults['patch-number']}
) must be an int.'
,
null
);
}
return
BuildInfo
(
getBuildMode
(),
argParser
.
options
.
containsKey
(
'flavor'
)
?
argResults
[
'flavor'
]
...
...
@@ -316,9 +384,19 @@ abstract class FlutterCommand extends Command<void> {
compilationTraceFilePath:
argParser
.
options
.
containsKey
(
'precompile'
)
?
argResults
[
'precompile'
]
:
null
,
buildHotUpdate:
argParser
.
options
.
containsKey
(
'hotupdate'
)
?
argResults
[
'hotupdate'
]
createBaseline:
argParser
.
options
.
containsKey
(
'baseline'
)
?
argResults
[
'baseline'
]
:
false
,
createPatch:
argParser
.
options
.
containsKey
(
'patch'
)
?
argResults
[
'patch'
]
:
false
,
patchNumber:
patchNumber
,
patchDir:
argParser
.
options
.
containsKey
(
'patch-dir'
)
?
argResults
[
'patch-dir'
]
:
null
,
baselineDir:
argParser
.
options
.
containsKey
(
'baseline-dir'
)
?
argResults
[
'baseline-dir'
]
:
null
,
extraFrontEndOptions:
argParser
.
options
.
containsKey
(
FlutterOptions
.
kExtraFrontEndOptions
)
?
argResults
[
FlutterOptions
.
kExtraFrontEndOptions
]
:
null
,
...
...
@@ -571,15 +649,21 @@ abstract class FlutterCommand extends Command<void> {
?
argResults
[
'dynamic'
]
:
false
;
final
String
compilationTraceFilePath
=
argParser
.
options
.
containsKey
(
'precompile'
)
?
argResults
[
'precompile'
]
:
null
;
final
bool
buildHotUpdate
=
argParser
.
options
.
containsKey
(
'hotupdate'
)
?
argResults
[
'hotupdate'
]
:
false
;
final
bool
createBaseline
=
argParser
.
options
.
containsKey
(
'baseline'
)
?
argResults
[
'baseline'
]
:
false
;
final
bool
createPatch
=
argParser
.
options
.
containsKey
(
'patch'
)
?
argResults
[
'patch'
]
:
false
;
if
(
compilationTraceFilePath
!=
null
&&
getBuildMode
()
==
BuildMode
.
debug
)
throw
ToolExit
(
'Error: --precompile is not allowed when --debug is specified.'
);
if
(
compilationTraceFilePath
!=
null
&&
!
dynamicFlag
)
throw
ToolExit
(
'Error: --precompile is allowed only when --dynamic is specified.'
);
if
(
buildHotUpdate
&&
compilationTraceFilePath
==
null
)
throw
ToolExit
(
'Error: --hotupdate is allowed only when --precompile is specified.'
);
if
(
createBaseline
&&
createPatch
)
throw
ToolExit
(
'Error: Only one of --baseline, --patch is allowed.'
);
if
(
createBaseline
&&
compilationTraceFilePath
==
null
)
throw
ToolExit
(
'Error: --baseline is allowed only when --precompile is specified.'
);
if
(
createPatch
&&
compilationTraceFilePath
==
null
)
throw
ToolExit
(
'Error: --patch is allowed only when --precompile is specified.'
);
}
ApplicationPackageStore
applicationPackages
;
...
...
packages/flutter_tools/test/base/build_test.dart
View file @
55f3da7a
This diff is collapsed.
Click to expand it.
packages/flutter_tools/test/src/mocks.dart
View file @
55f3da7a
...
...
@@ -29,6 +29,7 @@ class MockApplicationPackageStore extends ApplicationPackageStore {
android:
AndroidApk
(
id:
'io.flutter.android.mock'
,
file:
fs
.
file
(
'/mock/path/to/android/SkyShell.apk'
),
versionCode:
1
,
launchActivity:
'io.flutter.android.mock.MockActivity'
),
iOS:
BuildableIOSApp
(
MockIosProject
())
...
...
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