Skip to content

feat: open the forum as an app from the home screen, with a splash screen, an offline page and pull-to-refresh - #5338

Open
imorland wants to merge 17 commits into
2.xfrom
im/home-screen-app
Open

imorland wants to merge 17 commits into
2.xfrom
im/home-screen-app

Conversation

@imorland

@imorland imorland commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Related: FriendsOfFlarum/pwa#36 (fof/pwa 2.1 builds on this and keeps push notifications)

Changes proposed in this pull request:
A new Appearance switch, "Open as an app from the home screen", lets phones open the forum from the home screen in a window of its own, with the same splash screen on iPhones, iPads and Android: the app icon on a splash background colour, or full-screen images a theme sets with Theme::splashScreen(). The splash background shows around the icon and through its transparent parts, and takes solid colours only (#rgb or #rrggbb). Opening as an app needs an app icon, for a theme's splash images too: without one, the home screen would get a screenshot of the page, so the forum opens in the browser. The switch is on for new installs; a migration keeps it off for forums upgrading from 2.0, so nothing changes for them until an admin turns it on.

A service worker at /sw shows an offline page when the forum can't be reached. Page loads under the admin and API paths (from paths in config.php) go straight to the network. Extensions add to the worker with Extend\ServiceWorker: each script is served at /sw/{part}, keyed by the extension's id and its position so every server behind a load balancer gives the same address, and loaded with importScripts() in its own try/catch, so a script that throws or doesn't parse stops only itself. The worker is only kept while the forum opens as an app or an extension has added a script; otherwise /sw serves a worker that clears its offline cache and unregisters itself, and the forum only unregisters a worker whose script is core's /sw, clearing that worker's offline page as it does.

The home-screen meta tags and splash screen links are added to the forum's pages only, not the admin's; Content\Meta is unchanged from 2.x. Neither iPhones and iPads nor Android's Chrome give a home-screen app a way to reload, so the forum opened as an app gets pull-to-refresh, ported from FriendsOfFlarum/pwa#27 by rafaucau.

Reviewers should focus on:

  • composer.json conflicts with fof/pwa <2.1.0: every release so far, 2.0.1 included, registers the same /sw and /offline routes, which makes every forum request fail.
  • The worker registers on forums served over HTTPS only while opening as an app is on or an extension adds a script to it, and handles page loads only. Turning both off removes it from browsers that already have it.
  • The open_as_app migration and the installer: migrations write 0, then the installer's settings step writes 1 for new installs.

Screenshot
N/A here: tested on the iOS 27 Simulator and an Android 16 emulator (splash screens, offline page and reconnect, pull-to-refresh). The later fixes (upgrade default, admin and API pages, splash background, per-script imports, needing an app icon, the offline page) are covered by tests; the import isolation, the offline page and its reload, and admin pages being left to the network were also checked in Chromium. A headless Chromium run against a dev forum, emulating an iPhone 15, passes 58 checks across the admin settings and previews, the head tags and manifest, the splash images (sizes, cache headers, pixels), the worker (registration, offline page, reconnect, admin and API pages left alone, removal when turned off), and pull-to-refresh. The 46 splash links add about 10 KB to each forum page, about 0.7 KB gzipped.

Necessity

  • Has the problem that is being solved here been clearly explained?
  • If applicable, have various options for solving this problem been considered?
  • For core PRs, does this need to be in core, or could it be in an extension?
  • Are we willing to maintain this for years / potentially forever?

Confirmed

  • Frontend changes: tested on a local Flarum installation.
  • Frontend changes: tests are green (run yarn test in js/).
  • Frontend changes: tests have been added, or are not appropriate here.
  • Backend changes: tests are green (run composer test).
  • Backend changes: tests have been added, or are not appropriate here.
  • Where applicable, changes are suitable for all supported database drivers (MySQL, MariaDB, PostgreSQL, SQLite). (Settings only, no schema changes; the migration inserts one settings row with insertOrIgnore.)
  • Core developer confirmed locally this works as intended.
  • The description above is written by me and describes what this pull request actually does.

Required changes:

@imorland imorland added this to the 2.1 milestone Oct 30, 2026
@imorland
imorland requested a review from a team as a code owner October 30, 2026 17:11
…app, from a service worker extensions can add to
…e, and only keep the service worker when it's needed
… core's own service worker

Forums upgrading from 2.0 get open_as_app = 0 from a migration, so they don't
start registering a service worker or opening standalone until an admin turns
it on; new installs still turn it on. When the forum doesn't want a worker,
the forum client now only unregisters one whose script is core's /sw, leaving
workers extensions registered at the same scope alone.
…min frontend

Content\Meta runs for every frontend, so the admin pages got the "open as an
app" meta tags and every splash screen link. They're now added by a forum-only
content callback, and Meta is back to what 2.x has. The service worker leaves
admin and API page loads to the network, so they never show the forum's
offline page.
The skipped paths already come from the URL generator, which reads the paths
in config.php. The tests now read them the same way instead of assuming
/admin and /api, and cover custom paths and a forum in a subdirectory.
The splash screen placed the maskable icon, background and all, on the splash
screen background, so a background set apart from the app icon's showed the
icon as a square of the other colour. It now draws the transparent icon at the
size of the maskable icon's safe zone, so the splash background fills around
and through it. With the two backgrounds the same, it looks as before.
The scripts were joined into one, so one that didn't parse made the browser
reject the whole service worker, offline page included. Each is now served at
/sw/{part} and imported inside its own try/catch: a SyntaxError from
importScripts() is catchable, so it only stops that script. The import address
carries a hash of the file, so a changed script still updates the worker.
…app with an app icon

Splash screens are drawn into a directory per version, and outdated ones go
with one listing and a directory delete each, rather than about 92 single
deletes, one remote round trip each on a disk like S3. That also clears
versions left behind by a change to the drawing.

The forum only tells phones to open it as an app when it has an app icon:
without one, the home screen gets a screenshot of the page. A theme's splash
screen needs one too.
…the offline page reloading itself

An extension's worker script is keyed by who added it and in what order,
not by the file's absolute path, so servers behind a load balancer agree on
its address. The offline page no longer retries when opened at its own
address, where a successful retry reloaded it every 5 seconds. A failed load
of pull-to-refresh is caught.
…e worker

When opening as an app is turned off, the forum unregisters its worker
straight away, so the worker never ran again to clear the offline page it
stored, and the cache stayed in the browser. The forum now deletes this
worker's offline caches itself, leaving other forums' and extensions' alone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant