Skip to content

32. UI technology: native, cross-platform and web

The question. How is each screen of this app drawn, and what does that say about how the app is built?

Every mobile platform ships its own UI toolkit, with its own controls, gestures and conventions. A product that runs on two platforms must draw every screen twice, or find a way to draw it once. That choice is among the most expensive a team makes, and it is rarely reversed.

Four of the seven constraints (Chapter 2) pull on it.

  • Platform rules. Each operating system defines how a back gesture, a menu, a date picker and a text selection behave. Users expect an app to follow them. New platform features appear first in the platform’s own toolkit.
  • Slow release. A screen compiled into the app changes only with a new release. A screen delivered as web content changes the moment the backend serves a new page.
  • Limited resources. A toolkit that is not part of the operating system must be shipped inside the app. It adds to app size, to memory use and to the work done before the first frame.
  • Human attention. A screen that scrolls, selects text or answers a tap slightly differently from every other app on the device feels wrong, even to a user who cannot say why.

The team’s own cost sits against these. Two codebases need two sets of engineers and drift apart. One codebase halves the work and gives up something on each platform.

This chapter differs from the others in one respect, and you should hold it in mind throughout. The handbook is independent of any stack, so it names no toolkit. It describes five families by what they can do. And the evidence is weaker here than anywhere else in Part II. A user sees behavior, not code. A careful team can make any family behave like another. Almost every claim in this chapter is Inferred at best, and many are Speculative. The probes tell you how a screen is drawn. They do not tell you what language the logic behind it is written in.

There are five families. They are ordered here from the one closest to the operating system to the one furthest from it.

Family 1. The platform toolkit. The screen is built from the operating system’s own controls, by code written separately for each platform. Text, lists, menus and pickers are the same objects the system’s own apps use. This family costs the most to build, because every screen exists twice. It gains full fidelity to platform conventions, the lowest startup cost, the smallest app, and access to each new platform feature on the day it ships. Teams choose it when the product competes on feel, when it leans on hardware and platform surfaces, or when the company can afford two client teams.

Family 2. A mapped toolkit. The screen is described once, in shared code, and a layer in the app turns that description into the platform’s own controls on each platform. A button in the shared description becomes the platform’s button. The team writes one codebase and still gets platform controls, platform scrolling and platform accessibility for free. The cost is a runtime for the shared code, which adds to app size and startup time, and a boundary between the shared code and the controls. Work that crosses the boundary on every frame, such as a gesture that follows the finger, is the hard case. New platform features arrive when someone writes the mapping for them. Teams choose this family when they want one codebase and care that the result looks at home on each platform.

Family 3. A self-drawn toolkit. The app ships its own drawing engine. The engine receives an empty surface from the operating system and paints every pixel on it: text, buttons, scrolling, selection handles, everything. The platform’s controls are not used. They are imitated, or replaced by the product’s own. The team gets one codebase and pixel-identical output on every platform and every operating system version. The cost is the engine in the app’s size, engine startup before the first frame, and the fact that every platform behavior must be reimplemented. Accessibility is not inherited. The engine must describe its pixels to the screen reader through a parallel structure. Teams choose this family when brand consistency matters more than platform convention, or when one small team must cover many platforms.

Family 4. Embedded web content. The screen is a web page, shown inside a component the operating system provides for that purpose. The page comes from the network, from files bundled in the app, or from a cache. One codebase serves the app on both platforms and the website. A page from the network also escapes slow release entirely. The cost is the furthest distance from platform conventions, a loading step, weaker offline behavior, and access to platform features only through a bridge the app must build. Teams choose it for screens that change often, that are shared with the website, or that are visited too rarely to justify building twice: help, legal terms, campaigns, long forms, a checkout owned by another team.

Family 5. A game engine. The whole screen is one surface that the engine redraws many times a second. There are no controls in the platform’s sense. Menus and buttons are drawn objects in the game’s scene. The team gets full control over every frame and one codebase across phones, consoles and desktops. The cost is a large app, a long launch, continuous use of the processor and battery, and no inherited text handling or accessibility at all. Teams choose it for games, and sometimes for a single screen with heavy graphics inside an otherwise ordinary app.

Platform toolkitMapped toolkitSelf-drawn toolkitEmbedded web contentGame engine
Codebases for two platformsTwoOne, plus platform piecesOneOne, shared with the websiteOne
Startup costLowestA runtime to startAn engine to startA page to loadAn engine and assets to load
App size costNoneRuntimeEngineLittle, when pages come from the networkLarge
Fidelity to platform conventionsFullHighImitatedLowNone
New platform featuresAt onceAfter a mapping existsAfter a wrapper existsThrough a bridgeThrough a plugin
Changes without a releaseNoSometimesRarelyYes, when served from the networkAssets and levels
AccessibilityInheritedInheritedRebuilt by the engineThe web’s own modelAbsent unless built

Families belong to screens, not to apps. A single app commonly has a home feed built with the platform toolkit, a settings area in a mapped toolkit left by an earlier team, a help center in embedded web content and a camera effect on a game engine’s surface. Record the family for each screen. One label for a whole app is usually wrong.

Two neighbors of this chapter are easy to confuse with it. Server-driven UI (Chapter 31, which asks how much of the screen the backend decides) changes a screen’s layout without a release, and still draws it with whichever family the client uses. Remote config (Chapter 30, which asks how the app changes its behavior without a new release) changes values. A screen that changes overnight is not thereby web content.

Figure 32.1 shows the five drawing paths side by side. In the universal app model (Chapter 3) all of them are the UI component. What differs is how many layers sit between the domain logic and the pixels, and who owns each layer.

Figure 32.1. Five paths from logic to pixels. Only the platform toolkit receives system behavior without extra work.

Three properties of this figure drive every probe in the chapter.

First, the platform toolkit is the only path that the operating system reaches into directly. System text size, the screen reader, text selection, the context menu and scrolling physics are properties of the platform’s controls. A mapped toolkit inherits them, because it ends in those same controls. A self-drawn toolkit and a game engine must rebuild each one, and anything not rebuilt is missing or slightly different. Each difference is a signal.

Second, embedded web content has a second source. It can load its page from a host on the backend, which the other families never do for layout. That path gives it its release speed and its offline weakness.

Third, the mapped toolkit converges on the platform toolkit. From the last arrow onward the two are the same objects. This is why they are the hardest pair to tell apart, and why most claims that separate them are Speculative.

Web content and shared-code runtimes are sealed off from the rest of the app. They reach the session, the local store, the camera or the payment sheet only through a bridge, a narrow set of messages the host app chooses to answer.

// Inside the host app. The page can ask only for what is listed here.
function onMessageFromPage(message):
match message.name:
"getSession": reply(sessionTokenFor(page.origin)) // only for the app's own pages
"close": navigation.pop()
"openRoute": router.open(message.route)
"share": platform.share(message.payload)
otherwise: reply(Unsupported) // old app, newer page

The bridge matters to a teardown because it is where a mixed app shows its seams. A page that cannot reach the session asks you to sign in again. A page newer than the app asks the bridge for something the app does not know, and a button does nothing. Section 32.5 returns to these.

Each signature in this section is a place where the operating system gives the platform toolkit something for free. The question is always whether the screen has the real behavior, a rebuilt one, or none.

In the platform toolkit, text is selectable only where the developer marked it so: message bodies, article text, text fields. Labels, titles and button captions are not. When selection works, the handles and the menu are the system’s own, and the menu carries system entries such as look up, translate and share.

Embedded web content inverts this. Text on a web page is selectable by default, so a long-press on a label or heading often starts a selection. A long-press on a link or image may open a preview or a menu with entries about the link itself. A tap may flash a gray highlight over the tapped area. A careful team disables all three, so their absence proves nothing. Their presence is the strongest single signal in this chapter.

A self-drawn toolkit draws its own handles and its own menu. They are often close copies of one platform’s style, and they may be the same on both platforms. The menu tends to be shorter, because system entries added in recent operating system versions are missing until the toolkit adds them. A game engine usually has no text selection at all.

Each platform has its own scrolling physics: how fast a fling decays, and what happens at the edge of the content. One platform stretches or bounces past the edge. Another shows a glow or a squeeze. Platform and mapped toolkits get this from the system’s scrolling control.

A self-drawn toolkit imitates the physics, usually well. The tell is an edge effect from the wrong platform, or the same effect on both. Embedded web content scrolls inside the web component, whose deceleration can differ from the app’s other lists, and an inner region that scrolls inside the page can catch the gesture unexpectedly.

One scrolling signal belongs to mapped toolkits. When rows are produced by shared code running apart from the UI, a hard fling can outrun it, and blank rows appear briefly before they fill. The platform toolkit can show the same thing when images load late, so treat it as Speculative.

System text size and accessibility settings

Section titled “System text size and accessibility settings”

Raise the system text size and a platform-toolkit screen grows, if the team used the system’s text styles. That condition matters. Many teams fix their font sizes, and their screens do not grow in any family. So growth is evidence that the system setting reaches the screen, and no growth is weak evidence of anything.

The useful signal is a difference between screens of one app. If the home screen grows and the help screen does not, the two are probably drawn differently. Embedded web content often ignores the system text size unless the page was written to follow it. A game engine ignores it. A self-drawn toolkit follows it when the engine forwards the setting, and may round or cap it differently from the system.

The screen reader is the sharper tool. It reads a structure the toolkit publishes, not the pixels.

What the screen reader doesWhat it suggests
Moves control by control, announcing name, role and state as it does in system appsPlatform or mapped toolkit, or a self-drawn toolkit with full support
Announces web structure, such as headings, links and landmarks, and offers navigation by themEmbedded web content
Finds elements, but focus outlines sit slightly off the visible control, or the order jumpsA self-drawn toolkit describing its pixels through a parallel structure
Lands on one large region, or finds nothingA game engine, or a self-drawn surface with no accessibility support

Chapter 37 uses the same probe to judge how well the app serves the people who depend on it. Here it only classifies the drawing path.

This is the one signature that needs two devices. Put the same screen side by side on both platforms and compare the parts each platform has opinions about: the position of the back control, the look of switches and pickers, how a menu opens, how a modal is dismissed, the typeface, the transition between screens.

What you seeReading
Layout and controls each follow their platform, and the screens differ in structureTwo codebases. Platform toolkit on each.
The same layout on both, with each platform’s own switches, pickers and menusA mapped toolkit, or two teams following one tight design system
Identical pixels, including controls, typeface and transitionsA self-drawn toolkit, embedded web content or a game engine

The middle row is why this signature alone cannot identify a mapped toolkit. A disciplined pair of teams produces the same picture. A second weak tell appears after a major operating system update that restyles the system’s controls. Screens built on the platform’s controls change overnight with no app update. Self-drawn imitations keep the old look until the toolkit and the app catch up.

Loading bars, refresh and offline behavior

Section titled “Loading bars, refresh and offline behavior”

A web page arrives as a document, and it loads like one. Typical marks are a thin progress bar under the title, a blank white or gray area that fills from the top, content that jumps as images and fonts arrive, and a pull-to-refresh that blanks and reloads the whole page instead of updating a list in place. A close control where the rest of the app has a back control, or a title that changes as you move within the screen, marks a web container.

Offline behavior separates code in the app from pages on the network. A screen drawn by code in the app still draws its frame without a network: the title, the tabs, the empty list, an error state in the app’s own style (Chapter 9). A page from the network cannot draw anything. The body is blank or shows a plain error, often in a style that matches nothing else in the app. This is the cleanest probe in the chapter, with one exception. Web content bundled in the app or cached draws offline like any other screen.

Every family except the first ships something the operating system does not provide. The cost appears as a floor under app size and as time before the first frame (Chapter 7).

A small app with a near-instant first frame is consistent with the platform toolkit. A simple app that is tens of megabytes larger than its features suggest, with a visible pause on the splash at cold start, is consistent with a bundled runtime or engine. A very large app with a long loading screen and a progress bar is a game engine’s pattern. None of these is more than Speculative. Media, fonts, bundled models and third-party SDKs inflate size too, and Chapter 38 lists them.

No single signature identifies a family. Combine them, in this order of strength.

  1. Selectable labels, link menus, a page-style loading bar or a whole-screen failure offline. Any two of these make embedded web content Inferred.
  2. A screen reader that finds one region or nothing, with a large app and constant redrawing. A game engine, Inferred.
  3. Identical pixels on both platforms with controls that follow neither exactly, and selection handles or menus that differ from the system’s. A self-drawn toolkit, Inferred when you have compared both platforms, Speculative when you have one.
  4. System behavior everywhere, and a different structure on each platform. The platform toolkit, Inferred.
  5. System behavior everywhere, and the same structure on both platforms. A mapped toolkit or two disciplined teams. Speculative either way.

Most large apps mix families, and the joins are easier to detect than the families themselves. A seam is a place where you pass from one drawing path to another. Four things tend to break there.

The session. Web content keeps its own storage, separate from the app’s. Unless the bridge hands over the session (Chapter 20, which asks how the app knows who you are), the page does not know who you are and shows a sign-in form inside an app you are already signed in to.

Navigation. The host app has a back stack (Chapter 8). The page has its own history. Back may leave the whole web screen when you expected to go one page back, or step through page history when you expected to leave.

Appearance. The page ignores the dark appearance the rest of the app follows, uses a different typeface, or shows the website’s header, footer or consent banner inside the app.

State. A change made in the page is not known to the screens around it. You update an address in a web form, go back, and the screen under it still shows the old one until it refetches.

Figure 32.2 shows the life of one embedded web screen, online and offline.

Figure 32.2. One embedded web screen, online and then offline.

Record every seam you find. A list of which screens sit on which side is often the most reliable output of this chapter, and it feeds Chapter 38, because a seam between families is frequently a boundary between teams.

32.6 What the drawing path says about the code

Section titled “32.6 What the drawing path says about the code”

The drawing path supports a few claims about the codebase, and it is easy to claim too much.

A screen in embedded web content is very probably shared with, or derived from, the product’s website. Open the same function in a browser and compare. Identical layout and wording raises this to Inferred.

A self-drawn or mapped toolkit across the whole app implies one UI codebase for both platforms, and usually a single team that ships both at once. Simultaneous releases with the same version notes on both stores support it.

The platform toolkit on both platforms implies two UI codebases. It says nothing about the logic underneath. Domain logic, the data layer and the sync engine can be written once in a language that compiles for both platforms and sit under two separate UIs. This arrangement leaves no visual signature at all. Its only trace is behavioral: the same edge-case bug, the same validation wording and the same sync behavior on both platforms. Even then, a shared specification followed by two teams explains the evidence equally well. Mark any claim of shared logic under platform UI as Speculative.

A cross-platform runtime can also load new logic from the backend without a store release, where platform rules allow it. From outside this looks the same as remote config or server-driven UI, so it cannot be claimed on behavior alone.

Run P32.1, P32.5 and P32.6 on every screen you care about. They take seconds and catch embedded web content. Run P32.2 and P32.3 next, on one screen of each kind. P32.4 needs a second platform. Select the outcome you saw in each probe, and it is recorded in your worksheet for the teardown chosen here.

Open worksheet
Do
  1. Open the screen you want to classify.
  2. Long-press a static label, such as a heading, a row title or a button caption.
  3. Long-press a link or an image, if the screen has one.
  4. Long-press a block of content text, such as an article body or a message, and look at the handles and the menu.
  5. Do the same in one of the device's own apps for comparison.
Watch

Whether labels can be selected, whether a menu about the link appears, and whether the selection handles and menu match the ones the system's own apps show.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Note the text size on three or four different screens of the app, including one you suspect is web content.
  2. Raise the system text size by several steps in the device's display or accessibility settings.
  3. Return to the app and visit the same screens. Force-quit and reopen it if nothing changed.
Watch

Which screens grow and which do not. The difference between screens matters more than the result on any one.

Caution. This probe changes a device-wide setting. Every app will redraw with larger text. Restore your usual text size when you finish.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Turn on the screen reader.
  2. Open the screen and swipe to move from element to element, from the top of the screen to the bottom.
  3. Listen to what is announced for each control, and watch where the focus outline is drawn.
  4. Turn the screen reader off.
Watch

Whether controls are announced one by one with a name, a role and a state. Whether web terms such as heading, link or landmark are announced. Whether the focus outline sits exactly on each control.

Caution. This probe turns on the device's screen reader, which changes how every touch works. Learn the gesture or shortcut that turns it off before you turn it on.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Install the app on one device of each platform, if you have both. A friend's device beside yours also works.
  2. Open the same screen on both.
  3. Compare the parts each platform has opinions about: the back control, switches, pickers, menus, how a modal is dismissed, the typeface and the transition between screens.
  4. Compare the overall layout and the order of sections.
Watch

Whether the two screens differ in structure, share a structure with different controls, or match pixel for pixel.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Force-quit the app, so that screens are not simply kept in memory.
  2. Turn on airplane mode and open the app.
  3. Visit each screen of interest, including help, terms, promotions and account screens.
  4. Turn airplane mode off.
Watch

Whether each screen still draws its own frame, such as title, tabs and empty layout, or whether the whole body is blank or shows a plain error unlike the app's other error states.

Caution. This probe uses airplane mode, which interrupts calls and other apps on that device.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Open the screen online and watch how it first appears.
  2. Pull down to refresh, if the screen allows it.
  3. Move to another screen and come back.
Watch

Whether a thin progress bar runs under the title, whether the content area blanks and refills from the top, and whether content jumps as it arrives.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Open a long list in one of the device's own apps. Fling it, and drag past its top edge. Note the feel and the edge effect.
  2. Do the same on a long list in the app.
  3. Fling the app's list as hard as you can, several times.
Watch

Whether deceleration and the edge effect match the system's, and whether blank rows appear during a hard fling.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. Sign in to the app.
  2. Open a screen that showed web signals in P32.1, P32.5 or P32.6.
  3. Look for a sign-in form, a website header or footer, or a consent banner.
  4. Move two or three steps into the screen, then use the system's back control.
Watch

Whether the screen knows who you are, whether it carries parts of the website, and whether back moves one step or leaves the whole screen.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Do
  1. In the store listing or the device's storage settings, read the size of the app itself, not its data.
  2. Do the same for two or three apps of similar scope.
  3. Force-quit the app, open it, and count the seconds from tap to first frame. Repeat three times.
Watch

Whether the app is much larger than peers of similar scope, and whether a cold start pauses on the splash before anything is drawn.

Read

Select what you saw to record it in your worksheet. Select it again to clear it.

Read the confidence column closely in this chapter. Few rows reach Inferred on their own.

SignalDesign it points toConfidence
A long-press selects a label, heading or button captionEmbedded web contentInferred
A long-press on a link opens a preview or a menu about the linkEmbedded web contentInferred
A thin progress bar runs under the title while the screen loadsEmbedded web content loading a pageInferred
Pull to refresh blanks and reloads the whole screenEmbedded web content reloading a documentInferred
One screen is blank offline while the others draw their layoutEmbedded web content served from the networkInferred
A web-style screen draws fully offlineWeb content bundled in the app or cachedInferred
A sign-in form appears inside a signed-in appEmbedded web content with no session handed over the bridgeInferred
A website header, footer or consent banner appears inside the appThe public website shown without an in-app variantObserved
The screen reader announces headings, links and landmarksEmbedded web contentInferred
The screen reader finds one region or nothingA game engine or a self-drawn surface with no accessibility supportInferred
Focus outlines sit slightly off the visible controlsA self-drawn toolkit publishing a parallel accessibility structureSpeculative
Pixel-identical screens on both platforms, including controls and typefaceA self-drawn toolkit, embedded web content or a game engineInferred
The same layout on both platforms with each platform's own controlsA mapped toolkit, or two teams on one design systemSpeculative
Controls keep an old look after the operating system restyles its ownImitated controls in a self-drawn toolkitSpeculative
Selection handles or the text menu differ from the system'sText handling rebuilt by a self-drawn toolkitSpeculative
Some screens follow the system text size and others do notMixed families, or uneven adoption within oneSpeculative
Blank rows during a hard fling on a list with system scrolling feelA mapped toolkit producing rows apart from the UISpeculative
A simple app is far larger than its peers and pauses before the first frameA bundled runtime or drawing engineSpeculative

Search the signals from every chapter in the signal lookup.

The drawing path leaves a lighter mark on the backend than most concerns, and the mark is specific.

  • Platform, mapped and self-drawn toolkits. The backend serves data, not layout. The API shape (Chapter 10) is whatever the team chose. One shared client codebase makes it more likely that both platforms call exactly the same endpoints in the same order, and less likely that the backend carries platform-specific responses.
  • Embedded web content from the network. A web page host exists and serves pages built for a small screen. It needs a way to accept the app’s session, to hide the website’s own header and footer when inside the app, and to learn the app’s version, so that a new page does not call a bridge message an old app lacks. Old app versions meet new pages every day, which is the compatibility problem of Chapter 33 (how old versions keep working, and how they are retired) in reverse.
  • Bundled or cached web content. A delivery path for page bundles exists, with versions, so that the app can replace its local pages without a release.
  • Game engine. An asset delivery service for levels, textures and audio, usually fetched after install. A first launch that downloads for minutes is that service at work.

A team that serves the same pages to the app and the website has also made the website a dependency of the app. A website outage becomes an app outage for those screens only, which you may one day observe.

  • A sign-in form inside a signed-in app. The screen is embedded web content and the bridge did not pass the session, or the session expired separately in the page’s own storage.
  • A website header, footer or consent banner inside the app. The page is the public website, served without an in-app variant.
  • One screen stays light in dark appearance. That screen is drawn by a different path from its neighbors, most often web content.
  • A button that does nothing on an old app version. The page asked the bridge for a capability this version lacks. This confirms web content served from the network, and a missing version check.
  • Back leaves the whole flow from its third step. The flow is a sequence of pages inside one web screen, and the host’s back stack knows only the screen.
  • Controls that look one operating system version old. Imitated controls in a self-drawn toolkit, waiting for the toolkit to follow a system restyle.
  • The keyboard covers the field being typed in. The drawing path does not receive the system’s keyboard handling for free. This is common in web content and self-drawn toolkits, and possible anywhere.
  • Taps answer late while scrolling stays smooth. Scrolling runs in the platform’s control while the logic that answers the tap runs elsewhere and is busy. Consistent with a mapped toolkit. Speculative.
  • The screen reader goes silent on one screen. That screen is a single drawn surface with no published structure.
  • Emoji or a rare script renders differently from the rest of the device. The screen draws text with its own engine and fonts, not the system’s.

These are the fields this chapter adds to the teardown worksheet. Probe outcomes fill some of them in. Record the family per screen in the notes, and give each claim its confidence word.

Open worksheet
  • A screen is drawn by one of five families: the platform toolkit, a mapped toolkit, a self-drawn toolkit, embedded web content or a game engine. Families are assigned per screen, and most large apps mix them.
  • The families trade one codebase against startup time, app size, fidelity to platform conventions and access to new platform features.
  • The operating system gives the platform toolkit text selection, scrolling physics, text scaling and screen reader support for free. Every other family inherits, rebuilds or lacks each one, and the differences are the signals.
  • Embedded web content is the easiest family to detect: selectable labels, link menus, page-style loading, full-page refresh and whole-screen failure offline.
  • A mapped toolkit ends in the platform’s own controls, so it is the hardest to separate from two well-coordinated platform teams. Claims about it are Speculative.
  • Seams between families show in the session, in back navigation, in appearance and in stale state. A seam is often a team boundary.
  • The drawing path says how the UI is built. It says nothing about shared logic underneath, which leaves no visual signature.
  • Almost every claim in this chapter is Inferred or Speculative. Write the confidence word next to each one.