Flutter apps
The Flutter SDK relyo_flutter runs on iOS (15 and later), Android (8 and later) and Flutter Web with the same code. It transmits the Flutter UI as a sequence of images: only changed regions are sent, up to 10 images per second. No operating system permission is needed.
Dependency
The package is not on pub.dev but in the Relyo repository:
# pubspec.yaml
dependencies:
relyo_flutter:
git:
url: https://github.com/justcode049/Relyo.git
path: packages/flutter-sdk
ref: main # better: pin a specific commit
The repository is not public yet. Until then, request access by email to [email protected].
Requires Flutter 3.38 or later.
- iOS: deployment target 15.0 (
platform :ios, '15.0'in thePodfile). - Android:
android.permission.INTERNETin the manifest; for a local server viaws://during development alsoandroid:usesCleartextTraffic="true".
Setup
import 'package:relyo_flutter/relyo_flutter.dart';
void main() {
Relyo.init(
relayUrl: 'wss://relyo.de',
projectKey: 'pk_yourapp', // not needed with the open service
connect: RelyoConnect.lazy,
appVersion: '1.4.0',
);
runApp(RelyoScope(child: const MyApp()));
}
RelyoScope goes around MaterialApp or CupertinoApp and may only appear once. The SDK dialogs and the status bar live in their own overlay outside the transmitted area and therefore never appear in the supporter’s view.
Support entry
Ideally in the settings, unobtrusively at the end of the list:
TextButton(
onPressed: () => Relyo.instance.showCode(context),
child: const Text('Support'),
)
showCode shows the code dialog; after that the SDK guides through consent, session and end. During the session it enlarges the app’s top inset by the height of the status bar (36 pixels) so the bar does not cover any controls.
Options
| Parameter | Default | Meaning |
|---|---|---|
relayUrl | – | Required. Server address, for example wss://relyo.de. |
projectKey | – | The app’s project key. Without a key, a server with the open service assigns the app to its app ID (bundle ID or package name). |
user | – | Signed-in user, RelyoUser(id: …, name: …). Display only, not verified. |
connect | RelyoConnect.auto | auto: with user connect at once, otherwise only on showCode; eager: always at once; lazy: only on showCode. |
appVersion | '' | App version; shown in the console. |
fps | 5 | Target frame rate, 2 to 10. With limited bandwidth the SDK lowers it by itself. |
consentText | – | Your own explanation in the consent dialog; {agent} is replaced by the supporter’s name. |
Further calls:
Relyo.instance.identify(const RelyoUser(id: 'u_123', name: 'Max M.')); // after login
Relyo.instance.identify(null); // on logout
Relyo.instance.end(); // end the session, otherwise “Beenden” in the status bar
Before the first connection the SDK stores nothing on the device, not even an identifier.
Masking
Masking happens on the device before any image leaves it:
- Always: every field with
obscureText: true. RelyoRedact: everything inside this widget.
RelyoRedact(
child: TextField(decoration: InputDecoration(labelText: 'IBAN')),
)
Masked areas are painted black before the image is encoded. If the SDK cannot fully check the screen once, it blacks out the whole image. The SDK rejects remote input into masked fields.
Navigation
So that the supporter sees where the user is and drawings disappear on page changes:
MaterialApp(
navigatorObservers: [RelyoNavigatorObserver()],
// …
)
With GoRouter, additionally for changes that do not trigger a navigator push (go(), ShellRoute):
final router = GoRouter(observers: [RelyoNavigatorObserver()], routes: [/* … */]);
router.routerDelegate.addListener(() {
Relyo.instance.reportRoute(router.routerDelegate.currentConfiguration.uri.path);
});
Control
After the second consent, the supporter can tap, swipe and scroll, type text into the focused field and send Enter and Backspace. Any touch of the user’s own or a hardware key ends control at once.
Limitations
- Platform views (WebView, maps, camera) appear as a grey area labelled “Eingebettete Ansicht”.
- System dialogs (permissions, sharing) and the on-screen keyboard are not in the image.
- Remote text only in Flutter text fields (
TextField,CupertinoTextFieldand anything based onEditableText). - When the app goes to the background, transmission pauses and resumes when the user returns.
- The dialogs are in German only so far.
Testing
For your own widget tests without a server, package:relyo_flutter/testing.dart provides an in-memory test server (RelyoTesting.install, FakeRelyoServer).