Include flutter_runner in precache artifacts. (#36318)

diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index 857f379..876609b 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -50,6 +50,9 @@
   /// Artifacts required for Fuchsia.
   static const DevelopmentArtifact fuchsia = DevelopmentArtifact._('fuchsia', unstable: true);
 
+  /// Artifacts required for the Flutter Runner.
+  static const DevelopmentArtifact flutterRunner = DevelopmentArtifact._('flutter_runner', unstable: true);
+
   /// Artifacts required for any development platform.
   static const DevelopmentArtifact universal = DevelopmentArtifact._('universal');
 
@@ -63,6 +66,7 @@
     linux,
     fuchsia,
     universal,
+    flutterRunner,
   ];
 }
 
@@ -83,6 +87,7 @@
       _artifacts.add(LinuxEngineArtifacts(this));
       _artifacts.add(LinuxFuchsiaSDKArtifacts(this));
       _artifacts.add(MacOSFuchsiaSDKArtifacts(this));
+      _artifacts.add(FlutterRunnerSDKArtifacts(this));
       for (String artifactName in IosUsbArtifacts.artifactNames) {
         _artifacts.add(IosUsbArtifacts(artifactName, this));
       }
@@ -870,6 +875,9 @@
   }
 }
 
+ const String _cipdBaseUrl =
+    'https://chrome-infra-packages.appspot.com/dl';
+
 /// Common functionality for pulling Fuchsia SDKs.
 abstract class _FuchsiaSDKArtifacts extends CachedArtifact {
   _FuchsiaSDKArtifacts(Cache cache, String platform)
@@ -878,9 +886,6 @@
     DevelopmentArtifact.fuchsia,
   });
 
-  static const String _cipdBaseUrl =
-      'https://chrome-infra-packages.appspot.com/dl';
-
   final String _path;
 
   @override
@@ -893,6 +898,30 @@
   }
 }
 
+/// The pre-built flutter runner for Fuchsia development.
+class FlutterRunnerSDKArtifacts extends CachedArtifact {
+  FlutterRunnerSDKArtifacts(Cache cache)
+      : super('flutter_runner', cache, const <DevelopmentArtifact>{
+    DevelopmentArtifact.flutterRunner,
+  });
+
+  @override
+  Directory get location => cache.getArtifactDirectory('flutter_runner');
+
+  @override
+  String get version => cache.getVersionFor('engine');
+
+  @override
+  Future<void> updateInner() async {
+    if (!platform.isLinux && !platform.isMacOS) {
+      return Future<void>.value();
+    }
+    final String url = '$_cipdBaseUrl/flutter/fuchsia/+/git_revision:$version';
+    await _downloadZipArchive('Downloading package flutter runner...',
+        Uri.parse(url), location);
+  }
+}
+
 /// The Fuchsia core SDK for Linux.
 class LinuxFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts {
   LinuxFuchsiaSDKArtifacts(Cache cache) : super(cache, 'linux');
diff --git a/packages/flutter_tools/lib/src/commands/precache.dart b/packages/flutter_tools/lib/src/commands/precache.dart
index 3af67ec..473fea5 100644
--- a/packages/flutter_tools/lib/src/commands/precache.dart
+++ b/packages/flutter_tools/lib/src/commands/precache.dart
@@ -31,6 +31,8 @@
         help: 'Precache artifacts for Fuchsia development.');
     argParser.addFlag('universal', negatable: true, defaultsTo: true,
         help: 'Precache artifacts required for any development platform.');
+    argParser.addFlag('flutter_runner', negatable: true, defaultsTo: false,
+        help: 'Precache the flutter runner artifacts.', hide: true);
   }
 
   @override
diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart
index e2fe07e..07c5c18 100644
--- a/packages/flutter_tools/test/general.shard/cache_test.dart
+++ b/packages/flutter_tools/test/general.shard/cache_test.dart
@@ -169,6 +169,15 @@
     FileSystem: () => MockFileSystem(),
   });
 
+  test('Unstable artifacts', () {
+    expect(DevelopmentArtifact.web.unstable, true);
+    expect(DevelopmentArtifact.linux.unstable, true);
+    expect(DevelopmentArtifact.macOS.unstable, true);
+    expect(DevelopmentArtifact.windows.unstable, true);
+    expect(DevelopmentArtifact.fuchsia.unstable, true);
+    expect(DevelopmentArtifact.flutterRunner.unstable, true);
+  });
+
   group('EngineCachedArtifact', () {
     FakeHttpClient fakeHttpClient;
     FakePlatform fakePlatform;
diff --git a/packages/flutter_tools/test/general.shard/commands/precache_test.dart b/packages/flutter_tools/test/general.shard/commands/precache_test.dart
index 0308da6..466fe51 100644
--- a/packages/flutter_tools/test/general.shard/commands/precache_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/precache_test.dart
@@ -27,7 +27,7 @@
       final PrecacheCommand command = PrecacheCommand();
       applyMocksToCommand(command);
       await createTestCommandRunner(command).run(
-        const <String>['precache', '--ios', '--android', '--web', '--macos', '--linux', '--windows', '--fuchsia']
+        const <String>['precache', '--ios', '--android', '--web', '--macos', '--linux', '--windows', '--fuchsia', '--flutter_runner']
       );
       expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
         DevelopmentArtifact.universal,
@@ -38,6 +38,7 @@
         DevelopmentArtifact.linux,
         DevelopmentArtifact.windows,
         DevelopmentArtifact.fuchsia,
+        DevelopmentArtifact.flutterRunner,
       }));
     }, overrides: <Type, Generator>{
       Cache: () => cache,
@@ -52,7 +53,7 @@
       final PrecacheCommand command = PrecacheCommand();
       applyMocksToCommand(command);
       await createTestCommandRunner(command).run(
-       const <String>['precache', '--ios', '--android', '--web', '--macos', '--linux', '--windows', '--fuchsia']
+       const <String>['precache', '--ios', '--android', '--web', '--macos', '--linux', '--windows', '--fuchsia', '--flutter_runner']
       );
      expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
        DevelopmentArtifact.universal,