xray_device_actions 0.1.3
xray_device_actions: ^0.1.3 copied to clipboard
Lets the xRay desktop app drive a Flutter app — appearance, locale, text scale, animations and debug overlays — through the xray_inspector device inspector.
xray_device_actions #
Lets the xRay desktop app drive your Flutter app while you inspect it: appearance, locale, text scale, animation speed, bold text, high contrast, layout bounds and the performance overlay. Deep links, simulated push notifications and feature-flag overrides are registered on the same XRayDeviceInspector from xray_inspector.
For full documentation and guides, see the xRay docs.
Setup #
final deviceInspector = XRayDeviceInspector(
appVersion: () => '3.4.1 (412)',
);
final server = XRayInspectorServer(
config: XRayInspectorServerConfig(inspectors: [deviceInspector /* , … */]),
);
// Debug builds only, see the xray_inspector README.
if (!kReleaseMode) await server.start();
runApp(XRayDeviceOverrides(
inspector: deviceInspector,
supportedLocales: AppLocalizations.supportedLocales,
child: const MyApp(),
));
XRayDeviceOverrides must sit above MaterialApp. Appearance, text scale, bold text, high contrast and "animations off" reach your app through MediaQuery. For the locale override, pass the chosen locale to your app:
MaterialApp(
locale: XRayDeviceOverrides.localeOf(context), // null keeps your own logic
supportedLocales: AppLocalizations.supportedLocales,
// …
)
- Appearance overrides the platform brightness, so it works when your app follows the system theme (
ThemeMode.system). - Show layout bounds is Flutter's
debugPaintSizeEnabledand only paints in debug builds. - Quick settings live in memory: restarting the app brings back its own values.
Deep links #
deviceInspector.deepLinkHandler = XRayDeepLinkHandler(
name: 'GoRouter',
onOpen: (uri) {
router.go(uri.hasScheme ? uri.path : uri.toString());
return XRayDeepLinkResult.handled(
destination: router.routerDelegate.currentConfiguration.uri.toString(),
);
},
routes: () => const [
XRayRoute(path: '/', name: 'HomeScreen'),
XRayRoute(path: '/product/:id', name: 'ProductScreen'),
],
);
Return XRayDeepLinkResult.notHandled('reason') for links your app does not know. A handler that throws is reported as not handled.
Push notifications #
Push notifications sent from the desktop app are simulated: nothing goes through APNs or FCM. The inspector calls your handlers in-process with the title, body and data payload, so you test what your app does with a message, not the delivery itself.
deviceInspector.pushHandler = XRayPushHandler(
onForeground: (message) => showInAppBanner(message.title, message.body),
onBackground: (message) => syncInBackground(message.data),
onOpened: (message) => router.go(message.data['deeplink'] as String),
);
Feature flags #
Implement XRayFeatureFlagAdapter for each flag source (your remote config, a vendor SDK, local debug flags). Store overrides on the device, so they survive restarts until they are reset from the desktop app:
class RemoteConfigAdapter implements XRayFeatureFlagAdapter {
@override
String get name => 'Remote Config';
@override
Future<List<XRayFeatureFlag>> readFlags() async => [
XRayFeatureFlag(
key: 'new_checkout_flow',
type: XRayFeatureFlagType.boolean,
remoteValue: remoteConfig.getBool('new_checkout_flow'),
overrideValue: _override('new_checkout_flow'),
isOverridden: prefs.containsKey('override.new_checkout_flow'),
),
];
@override
Future<void> setOverride(String key, Object? value) =>
prefs.setString('override.$key', jsonEncode(value));
@override
Future<void> clearOverride(String key) => prefs.remove('override.$key');
Object? _override(String key) {
final raw = prefs.getString('override.$key');
return raw == null ? null : jsonDecode(raw);
}
}
Your app reads the override first and falls back to the remote value.
Disclaimer: This is a commercial package. To use this package, you need to have either a commercial xRay license or a free xRay Community License. The xRay desktop apps for macOS, Windows and Linux are the authorized UI clients for this library. For more details, please check the LICENSE file.