Widgets are separate programs
Span has widgets on the Home Screen and Lock Screen on iOS, Control Center buttons, and on Android, home screen widgets, a Quick Settings tile and app shortcuts. They show the last measurement and open the app straight into measuring.
I assumed a widget was a small view inside the app. It is not. On both platforms it is drawn by the system, often while the app is not running, and that changes how it gets anything to show.
iOS: an extension and an App Group
An iOS widget lives in an extension, which is a separate program with its own files. It cannot see the app’s code, so the design system and the widget views moved into a Shared folder that both the app and the extension compile.
It also cannot open the app’s database. When something is saved, the app writes a small summary to an App Group, which is storage both programs can read, and asks WidgetKit to redraw. App Groups need the Apple team to allow that capability when signing for a phone. If it is refused, the widgets show “Nothing yet” and the rest of the app still works.
Control Center buttons have a limit of their own. They must use SF Symbols, so they use the closest system icons instead of the design’s.
Android: preferences and one way in
An Android Glance widget is described by the app and drawn by the launcher, and it can update while the app is closed. Opening the Room database from there would be heavy, so saving a measurement also writes its title and value to preferences, and asks the widget to refresh.
Widgets, the tile and shortcuts all open the app the same way. Each one starts the main activity with a single extra naming where to land. The activity is singleTop, so if the app is already open, it receives the request in onNewIntent instead of opening a second copy of the screen.
A Quick Settings tile can only open the app here, because Span has nothing to switch on or off.
Two small surprises
- My first shortcut was called “Projects”. The design showed the actual job, like “Mrs Ade’s living room”, and opened it. It now uses the latest project’s name and opens that project
- A UI test for widget links kept showing the first onboarding page. XCUIApplication.open(url) had restarted the app instead of handing it the link. XCUIDevice.shared.system.open(url) goes through iOS, as a widget tap does
On my iPhone, the Span widget shows up in the widget gallery with its preview, so it is registered with iOS. The preview uses sample measurements on purpose, because the gallery asks for a preview before the widget has real data. The Android widgets have only been tested on an emulator home screen so far.