|
| 1 | +--- |
| 2 | +sidebar_position: 5 |
| 3 | +title: 🏛️ Architecture |
| 4 | +description: How Shorebird works. |
| 5 | +--- |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +Shorebird is a set of tools that allow you to build and deploy new versions of |
| 10 | +your Flutter app directly to your users' devices. |
| 11 | + |
| 12 | +Shorebird consists of 3 major parts: |
| 13 | + |
| 14 | +- A command line tool that you use to build and deploy your app. |
| 15 | +- A modified Flutter engine that you include in your app. |
| 16 | +- Servers that host patches for your app. |
| 17 | + |
| 18 | +## `shorebird` tool |
| 19 | + |
| 20 | +The `shorebird` tool is documented extensively elsewhere. Most of the build |
| 21 | +logic is just wrapping the `flutter` tool and it also adds a few commands to |
| 22 | +interface with Shorebird's servers. |
| 23 | + |
| 24 | +## A modified Flutter engine |
| 25 | + |
| 26 | +Code push requires technical changes to the underlying Flutter engine. To make |
| 27 | +those changes required forking Flutter. |
| 28 | + |
| 29 | +We had to fork 3 Flutter repos to make Shorebird work: |
| 30 | + |
| 31 | +### flutter/engine |
| 32 | + |
| 33 | +The engine is the C++ code that runs on the device. It is responsible for |
| 34 | +rendering the UI, handling input, and communicating with the host. |
| 35 | + |
| 36 | +We forked this code to add the ability to have release versions of the Flutter |
| 37 | +engine be able to load new code from Shorebird's servers. |
| 38 | + |
| 39 | +At time of writing, Shorebird's fork is based on Flutter 3.7.12. You can see |
| 40 | +our engine changes here: |
| 41 | +https://github.com/flutter/engine/compare/3.7.12...shorebirdtech:engine:stable_codepush |
| 42 | + |
| 43 | +### flutter/flutter |
| 44 | + |
| 45 | +The flutter/flutter repo contains the Dart code that runs on the device as well |
| 46 | +as the `flutter` tool that is used to build and run Flutter apps. |
| 47 | + |
| 48 | +We initially did not fork this code. And still don't really want to fork |
| 49 | +this code, but in order to deliver a modified engine without affecting other |
| 50 | +Flutter installations, we needed to be able to change the _version_ of the |
| 51 | +engine that the `flutter` tool downloads. |
| 52 | + |
| 53 | +Our one fork is to change bin/internal/engine.version to point to our |
| 54 | +engine version. You can see our changes here: |
| 55 | +https://github.com/flutter/flutter/compare/3.7.8...shorebirdtech:flutter:stable_codepush |
| 56 | + |
| 57 | +### flutter/buildroot |
| 58 | + |
| 59 | +The buildroot repo contains the build scripts that are used to build the |
| 60 | +Flutter engine for various platforms. It's separate from flutter/engine in |
| 61 | +order to share code and configuration with the Fuchsia build system. |
| 62 | + |
| 63 | +We also didn't want to fork this code. However we need to for now in order |
| 64 | +to integrate our updater code. Our updater code: |
| 65 | +https://github.com/shorebirdtech/updater |
| 66 | +is a Rust library which we link into the engine. The way we do that is via |
| 67 | +a C-API on a static library (libupdater.a). The default flags for linking |
| 68 | +for the Flutter engine hide all symbols from linked static libraries. We |
| 69 | +need to be able to expose the shorebird\_\* symbols from libupdater.a up through |
| 70 | +FFI to the Dart code. We did that my making one change to buildroot and then |
| 71 | +a second change to the engine to place the symbols on the allow-list. |
| 72 | + |
| 73 | +Our one change: |
| 74 | +https://github.com/shorebirdtech/buildroot/commit/7383548fa2306b5d53979ac5e9d176b35258811b |
| 75 | + |
| 76 | +## Vendoring our fork |
| 77 | + |
| 78 | +When you install Shorebird, it installs Flutter and Dart from our fork. These |
| 79 | +are currently not exposed on the user's path, rather just private copies |
| 80 | +that Shorebird will use when building your app. |
| 81 | + |
| 82 | +This was necessary to avoid conflicts with other Flutter installations on the |
| 83 | +user's machine. Specifically, the way that Flutter downloads artifacts is |
| 84 | +based on the version of the engine. If we were to use the same version of the |
| 85 | +engine as the user's Flutter installation, then we would overwrite the user's |
| 86 | +engine artifacts. |
| 87 | + |
| 88 | +We deliver our artifacts to this fork of Flutter with two ways. First is we |
| 89 | +change the version of the engine in the `flutter` tool. Second is we pass |
| 90 | +FLUTTER_STORAGE_BASE_URL set to download.shorebird.dev (instead of |
| 91 | +download.flutter.io) when calling our vended copy of the `flutter` tool. |
| 92 | + |
| 93 | +Currently this means `shorebird` will not work in an environment where the |
| 94 | +user needs to use FLUTTER_STORAGE_BASE_URL to download Flutter artifacts |
| 95 | +from a private mirror (e.g. a corporate network or China). |
| 96 | +https://github.com/shorebirdtech/shorebird/issues/237 |
| 97 | + |
| 98 | +## Serving our forked binaries |
| 99 | + |
| 100 | +We also use a custom server to handle requests from `flutter` for our |
| 101 | +(modified) engine. You can see that server here: |
| 102 | +https://github.com/shorebirdtech/shorebird/tree/main/packages/artifact_proxy |
| 103 | + |
| 104 | +Our "artifact_proxy" knows how to serve the modified binaries from our |
| 105 | +Google Storage bucket, as well as how to serve unmodified binaries for all |
| 106 | +parts of Flutter we didn't have to modify from |
| 107 | +Google's Flutter Google storage bucket. |
0 commit comments