When your workflow specifically requires a native app, check a known provider's availability before enabling its launch action. This recipe checks a configured list; it does not enumerate all applications installed on a device.
Reusable Flutter example
import 'package:deeplink_x/deeplink_x.dart';
Future<bool> openInstalledTelegram() async {
final deeplinkX = DeeplinkX();
final app = Telegram();
if (!app.supportedPlatforms.contains(deeplinkX.currentPlatform)) {
return false;
}
if (!await deeplinkX.isAppInstalled(app)) {
return false;
}
return deeplinkX.launchApp(app, disableFallback: true);
}
For a UI list, keep unsupported and not-installed as separate states even though this small helper returns false for both.
Current example behavior
InstalledAppsPage builds groups for Apps, Maps, and Stores. It checks entries concurrently with Future.wait, supports a refresh button and pull-to-refresh, and displays four states:
| State | Meaning in this sample |
|---|---|
| Checking | The availability request is pending. |
| Installed | The configured native check returned true. |
| Not installed | The app supports the current platform but its availability check returned false. |
| Unsupported | The app's declared native platform list excludes this platform. |
Only installed rows can be tapped. Launch uses launchApp(app, disableFallback: true), so a web page or store must not be treated as satisfying this native-only interaction.
The sample screen lists 37 apps/maps and seven stores. The full app catalog also includes ChatGPT, Netflix, Temu, Snapchat, and CapCut. TomTom GO Expert is experimental.
Configuration and limits
- Installation detection depends on target platform, declared supported platforms, Android package visibility, iOS scheme queries, and provider metadata. Show unavailable or unsupported status when detection cannot find a native handler.
- Use the Android visibility declarations, iOS schemes, and each provider's setup documentation.
- The implementation checks Android package names, macOS bundle identifiers, or configured schemes according to the platform. See
LauncherUtil.isAppInstalled. - A successful launch Boolean describes handoff, not completion of a downstream task. Native availability can also change between check and tap.
UI behavior
- Unsupported entries do not run installation checks and show a distinct status.
- A configured installed app is enabled; missing and unsupported entries remain disabled.
- Tapping an installed entry calls
launchAppwith fallback disabled. - Refresh resets and recomputes the configured inventory; pending launch taps cannot overlap.
- The hub does not advertise this screen as full device app enumeration or as the exhaustive package catalog.