Multiple Dart entrypoints and engines
A host app can start a Flutter module through more than one Dart entrypoint
(functions marked @pragma('vm:entry-point')), and run several Flutter engines
at once, for example with FlutterEngineGroup. Shorebird supports this with no
extra setup. This page explains how patches behave in that case.
One patch for the whole module
Section titled “One patch for the whole module”A patch replaces the module’s compiled Dart code as a whole, not one entrypoint at a time. Every entrypoint is part of the same release and the same patch, so a patch can change the code that any of them runs.
Shorebird picks the patch to run when the app process starts. With auto_update
on (the default), it also checks for a new one once per process, not once per
engine (see Checking for updates). A patch downloaded
while the app is running is meant for the next time the app starts. To run it,
fully quit the app and launch it again.
Don’t count on engines you create later in the same process running the same patch as the first one. On Android they do: Shorebird picks the patch once per process. On iOS, an engine created after a new patch has downloaded can start that new patch while older engines keep running the previous one. If your entrypoints share state that a patch changes the shape of, start every engine when the app starts, or make the code tolerate both versions.
What a patch can’t change
Section titled “What a patch can’t change”The host app’s native code names the entrypoints it starts, and Shorebird doesn’t patch native code. So, in a patch:
- Don’t remove or rename an entrypoint that the host app starts. The host app shipped in the store still asks for it by name. Shorebird doesn’t check this when you create the patch.
- Adding an entrypoint is allowed, but nothing calls it until you ship a host app that does. Add it in a release instead.
- Keep
@pragma('vm:entry-point')on every entrypoint. Without it, the Dart compiler can remove a function that only native code calls.
Changing what an entrypoint does, or what its arguments mean, is fine as long as the host app you shipped still passes arguments the new code accepts.
Checking for updates
Section titled “Checking for updates”With auto_update on (the default), the updater checks for a patch once per
process, when the first engine starts. You don’t need to do anything in each
entrypoint.
With auto_update: false, your code decides when to check, using
package:shorebird_code_push.
Check from the entrypoint that runs first, or from each entrypoint if you don’t
know which one will. If you check from each one, pass every check the same
track, and expect a network request each time an engine starts. Only one check
runs at a time: if a second engine calls update while another check is
running, that call returns without starting another check. (In a release built
with a Flutter version older than 3.41.7, or with shorebird_code_push older
than 2.0.6, it throws an UpdateException instead.) update also throws when a
check fails, for example when the device is offline, so catch errors from
update in every entrypoint that calls it. The
testing patches
page has an example.