Skip to main content

Page JSON Overview

Aptean Mesh uses a Server-Driven UI (SDUI) architecture. Every screen in the Android client is defined as a JSON document authored in Business Central (BC). The client does not contain hard-coded layouts -- it receives JSON page definitions at runtime, parses them, and renders the corresponding UI components.

How It Works

  1. Author -- A developer creates a JSON page definition and stores it in the Mobile Page table (MobilePage220FDW) in BC, linked to an App Bundle.
  2. Serve -- When the client connects, it calls GetPageFlow on the BCRPC220FDW API page. BC returns every page in the active bundle in a single payload.
  3. Render -- The client deserializes each page into Kotlin data classes (Page, Header, Footer, Component, Contract) and renders them using Jetpack Compose.
  4. Interact -- User actions (button taps, scans, list selections) trigger actions defined in the page's contract. These actions call back into BC via JSON-RPC, and the response updates the page data in place.
Page Flow Overview
Developer Setup
BC Developer
Authors JSON pages in Mobile Page table
Registers service codeunit in Service Registry
Runtime Flow
App Startup
GetPageFlow ──▶ BC returns all page JSON for the bundle
|v
Client
Deserializes into Kotlin types (Page, Header, Component…)
Jetpack Compose renders the screen
|v
User Interaction
Tap / scan / input triggers Service.RPC(State)
BC returns updated JsonObject
Client updates page data in place

How Pages Are Stored

Each page JSON document lives in the Mobile Page table:

FieldDescription
App Bundle IDThe bundle this page belongs to
Page IDUnique identifier for the page within the bundle (e.g., "HOME")
Page JsonThe full JSON document defining layout and behavior

Pages are managed through the Mobile Pages page in BC, accessible from the App Bundle card.

How the Client Fetches Pages

The client calls GetPageFlow once on startup. BC returns:

{
"result": {
"bundle": "00000000-0000-0000-0000-000000000001",
"rootPage": "HOME",
"pageFlow": [
{
"pageID": "HOME",
"pageJson": { ... }
},
{
"pageID": "PICK",
"pageJson": { ... }
}
]
}
}

The client caches all page definitions locally. Navigation between pages is instant -- no additional network call is needed unless an action triggers an API request.

Caching and Refresh

  • Page definitions are cached on the client after the initial GetPageFlow call. They persist until the user switches bundles or the app is restarted.
  • Page data (the values bound to components) is refreshed whenever an action's API response returns new values. Pull-to-refresh re-executes the page's initialAction when header.refresh is true.
  • Filters are applied client-side against cached data or by re-invoking an API action with filter parameters.

When to Use JSON vs AL Logic

ScenarioApproach
Define which components appear on a screenJSON page definition
Control layout, titles, field labelsJSON page definition
Validate input, compute values, query dataAL codeunit (called via actions)
Navigate between pagesJSON action with "type": "navigate"
Show/hide components dynamicallyJSON visibleKey bound to data returned by AL
Complex business logic, transactionsAL codeunit behind an API action

The JSON defines what the user sees. AL code defines what happens when they interact.

Page Structure at a Glance

{
"pageId": "PICK",
"service": "PICKSERVICE",
"header": {
"title": "Pick",
"refresh": true
},
"body": [
{ "type": "stepInput", "dataKey": "scanInput", "action": "onScan" },
{ "type": "repeater", "dataKey": "lines", "key": "lineNo", "template": "CARD" }
],
"contract": {
"initialAction": "onLoad",
"actions": [
{ "id": "onLoad", "type": "api", "method": "Initialize", "params": ["locationFilter"] }
]
}
}

What's Next

  • Page Structure -- Top-level Page, Header, Footer, DrawerItem, Contract, and EventContext types
  • Components -- All UI component types with complete property references
  • Actions -- All action types (API, navigate, filter, lookup) with confirmation and input prompt dialogs
  • Commands -- Server-sent commands (alert, navigate, refresh, vibrate) returned in RPC responses
  • Filters -- Filter definitions, modes, static and dynamic options, segment mapping
  • Data Contract -- Contract structure, action references, parameter passing, scan patterns