Dartvel, home
Docs
Features
Studio
Cloud
Compared

Search the site

GitHub
pub.dev

GETTING STARTED

Getting started
Existing Flutter apps
Existing Native apps
Run on your phone

APP

UI and styling
Routing
State
Accessibility
Keyboard shortcuts
Localization
Devices and desktop
Native device access
Media, 3D and XR

DATA

Data models
Forms
Search
Sync and offline
Import and export
Change capture
Database
Cache
File storage
Images
Privacy and erasure

BACKEND

Backend functions
Auth and sessions
Authorization
Queues and jobs
Workers and memory
Notifications and mail
Outbound HTTP
AI
Webhooks
GraphQL and OpenAPI
API keys and OAuth
Multi-tenancy
Billing and commerce
Modules

OPERATIONS

Edge security
Secrets and environments
Monitoring
Releases

SHIPPING

Build targets
Telegram Mini Apps
Static web hosting
Servers and deploying

REFERENCE

Testing
CLI reference
Coding agents

APP

Devices and desktop

Native features come through DV.Platform on every target, and a target that lacks one says so instead of failing quietly.

Home screen widgets, kiosks, windows, tabs and desktop trays are declared in Dart like the rest of your app.

ON THIS PAGE

Call native features through DV.Platform

Put a widget on the home screen

Lock a screen to your app

Open more windows and tabs

Lay out around the fold on a foldable

Trays, menus, shortcuts and drag and drop

Call native features through DV.Platform

Each target binds the native features it actually has, through FFI or JNI, never platform channels. A tray exists on a desktop and not in a browser.

Before you rely on a feature, check capability. Calling one the target lacks is an error that names it.

Linux binds the most today and iOS the fewest. A test checks that every binding a target claims has a handler behind it, and on Android an emulator job checks it again.

// One surface on every target. A feature the platform does not have answers
// that it is unavailable, and does not throw, so a call site does not need
// to know which platform it is on.
Future<void> shareReceipt(String orderId) async {
  await DV.Haptics.lightVibrate();
  await DV.Share.shareText('Order $orderId is on its way.');
}

Copy code to clipboard

Partial

Spec section: Platform

Planned work and implementation limits

On Android, biometrics and NFC tags are not bound yet.

iOS binds only a handful of features so far.

Put a widget on the home screen

Annotate a widget with @DVHomeWidget and the build adds it to the home screen, with a route that opens the app at it.

Android, iOS and macOS widgets are packaged by dartvel build. A target with nowhere to put one leaves it out and tells you.

Functional

Class

// A widget, with the annotation on it. The same functional widget every
// other piece of Dartvel UI is: the input is private, and the generated
// NextShiftWidget is what the home screen and the route reach.
@DVHomeWidget(title: 'Next shift')
@DVFunctionalWidget()
Widget _nextShiftWidget(BuildContext context) => const DVBox.list(<Widget>[
      DVText('Next shift'),
      DVText('Thursday, 07:00'),
    ]);

// What the home screen shows, pushed from anywhere in the app.
Future<void> refreshShift(String when) =>
    DVHomeWidgets.publish('next-shift', when);

Copy code to clipboard

Partial

Spec section: Home Widgets

Lock a screen to your app

A kiosk policy sets the exit PIN, the idle timeout and what is cleared between visitors. dartvel doctor refuses a policy the target cannot honour.

After the idle warning the session resets: what the policy names is cleared, and the app goes home.

System key combinations that leave the app are blocked on Linux, Windows and macOS, as far as each OS lets an app, and by lock task mode on Android. Accessibility keys still work.

Partial

Spec section: Kiosk Mode

Open more windows and tabs

DV.Platform.window.open opens a page in its own window on Linux, once: opening it again focuses the one that is open. A second launch of the app hands its arguments to the first.

A window opens on the display you ask for, such as DVDisplayHint.secondary for a projector, and window.setFullscreen(true, on: ...) fills that display. If that display is not connected, the call is refused and the current screen stays as it is.

Tab workspaces keep tabs in order, let you drag one out into a window where the target allows it, and restore them per user and tenant.

On a TV the tabs become tiles the remote moves between.

// Idempotent by route: opening a route a window already shows returns that
// window instead of a second copy of it.
// The route is the generated target, never a string: moving the page moves
// this with it, and a route that no longer exists is a compile error rather
// than a window onto nothing.
Future<DVWindow> openCart() => DV.Platform.window.open(DVRoutes.cart);

Copy code to clipboard

Partial

Spec section: Multi-Window

Partial

Spec section: Tab Workspaces

Lay out around the fold on a foldable

On a foldable the first pane sits on one side of the fold and the second on the other, with nothing in the hinge. With no fold they sit side by side on a tablet and stack on a phone.

DVBox.threePane gives a tri-fold one pane per panel. With no fold it is three columns on a desktop, two on a tablet and a stack on a phone.

context.screen.folds lists each fold with where it is and whether it hides pixels. posture is book, tabletop or flat.

Android foldables report their folds today. Fold reporting on iOS is planned and requires a native binding.

// The fold is a rectangle the page is told about, so a layout can keep
// content out from under the hinge without guessing at a breakpoint.
Widget shiftBoard(BuildContext context) {
  final List<DVFold> folds = context.screen.folds;
  final bool split = folds.any((DVFold fold) => fold.occludes);
  return DVBox.list(<Widget>[
    const DVText('Today'),
    if (!split) const DVText('Tomorrow'),
  ]);
}

Copy code to clipboard

Trays, menus, shortcuts and drag and drop

Add a tray icon with a menu, app menus and global shortcuts on Linux, Windows and macOS.

A window can accept dropped files or text, and gets what was dropped and where.

Native print and file dialogs have Linux, Windows and macOS bindings.

// Trays, menus and shortcuts are the same DV.Platform surface, so a desktop
// build asks for them and a phone build answers that it has none.
Future<void> installDesktopChrome() async {
  await DV.Platform.tray.show(
    icon: DVAsset.tray,
    tooltip: 'Oakline',
    menu: const <DVTrayMenuItem>[
      DVTrayMenuItem.header('Oakline'),
      DVTrayMenuItem.separator(),
      DVTrayMenuItem(id: 'cart', label: 'Open the cart'),
      DVTrayMenuItem(id: 'sounds', label: 'Order sounds', checked: true),
    ],
    onSelected: (String id) => DV.Platform.window.open(DVRoutes.cart),
  );
  // The same icon, changed in place: no flicker, no second icon.
  await DV.Platform.tray.update(tooltip: 'Oakline: 2 orders waiting');
  await DV.Platform.shortcuts.register(
    const DVGlobalShortcut(id: 'cart', accelerator: 'Ctrl+Shift+O'),
    onPressed: () => DV.Platform.window.open(DVRoutes.cart),
  );
}

Copy code to clipboard

Platform access

Every native feature on this page reaches the device through DV.Platform. See the platform page for the full member list, binding status per platform, and planned capabilities.

Partial

Spec section: Desktop, Embedded, and Qt-Critical Capabilities

PREVIOUS Localization Typed translation keys, plurals and ARB files
NEXT Native device access DV.Platform: camera, location, files, windows and the rest of the device
GitHub
pub.dev
npm
Acknowledgements
Privacy
Terms

FSL-1.1-MIT licensed. Built with Dartvel.

Dartvel is made by

SigmaDev Digital

To the bottom