Skip to content

feat!: return FlutterApplication on app.start instead of app.started #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,20 @@ void main() async {

// You can run an application from the daemon.
// Or alternatively you can attach using `daemon.attach`
final application = daemon.run(
final application = await daemon.run(
arguments: [
// Any flutter arguments go here.
],
workingDirectory: 'your/flutter/app/location/',
);

// Wait until it is fully started.
await application.started;

application.events.listen((event) {
// Listen to events specifically emitted by this application.
});

g
// Restart the application
await application.restart();

Expand Down
7 changes: 5 additions & 2 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ void main(List<String> arguments) async {
final daemon = FlutterDaemon();
daemon.events.listen(print);

final workingDirectory = arguments.removeAt(0);
final workingDirectory = arguments.first;
final application = await daemon.run(
arguments: arguments,
arguments: arguments.sublist(1),
workingDirectory: workingDirectory,
);

// Wait for it to be fully started.
await application.started;

print('started');
await Future<void>.delayed(const Duration(seconds: 10));

Expand Down
25 changes: 24 additions & 1 deletion lib/src/flutter_application/flutter_application.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:flutter_daemon/flutter_daemon.dart';

export 'requests/requests.dart';
Expand All @@ -10,7 +12,21 @@ export 'requests/requests.dart';
/// {@endtemplate}
class FlutterApplication {
/// {@macro flutter_application}
FlutterApplication(this.appId, this._daemon);
FlutterApplication(this.appId, this._daemon) : _started = Completer() {
events
.firstWhere((e) => e.event == 'app.started')
.whenComplete(_started.complete);
}

/// {@macro flutter_application}
///
/// Created when the daemon is getting attached to a running app.
FlutterApplication.attached(
this.appId,
this._daemon,
) : _started = Completer() {
_started.complete();
}

/// The application id of the attached flutter app.
final String appId;
Expand All @@ -19,6 +35,13 @@ class FlutterApplication {
late final Stream<FlutterDaemonEvent> events =
_daemon.events.where((event) => event.params['appId'] == appId);

/// Resolves once the application has emitted the `app.started` event.
///
/// If this application was created through an attach it will already be
/// resolved.
Future<void> get started => _started.future;
final Completer<void> _started;

final FlutterDaemon _daemon;

/// Restarts the application.
Expand Down
4 changes: 2 additions & 2 deletions lib/src/flutter_daemon/flutter_daemon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ class FlutterDaemon {
if (data.containsKey('event')) {
final event = FlutterDaemonEvent.fromJSON(data);
_eventsController.add(event);
if (event.event == 'app.started') {
log('App started', level: 300);
if (event.event == 'app.start') {
log('App is attachable', level: 300);
completer.complete(
FlutterApplication(event.params['appId'] as String, this),
);
Expand Down
15 changes: 15 additions & 0 deletions test/src/flutter_application/flutter_application_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ void main() {
});
});

// Ensure the Flutter application get's an app.started event.
when(() => daemon.events).thenAnswer((_) {
return Stream.value(
FlutterDaemonEvent.fromJSON({
'event': 'app.started',
'params': {'appId': 'appId'},
}),
);
});

application = FlutterApplication('appId', daemon);
});

Expand All @@ -55,6 +65,11 @@ void main() {
registerFallbackValue(AppCallServiceExtensionRequest('dummy', 'dummy'));
});

test('$FlutterApplication.attached resolves started directly', () {
final app = FlutterApplication.attached('appId', daemon);
expect(app.started, completes);
});

test('restart', () async {
final response = await application.restart();
expect(response.code, equals(0));
Expand Down
54 changes: 54 additions & 0 deletions test/src/flutter_daemon/flutter_daemon_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

expect(daemon.isFinished, isFalse);
exitWith(0);
await finishedFuture;
Expand All @@ -81,8 +87,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

expect(daemon.isFinished, isFalse);
exitWith(0);
await finishedFuture;
Expand All @@ -94,8 +106,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

expect(
daemon.run(arguments: [], workingDirectory: ''),
throwsA(
Expand Down Expand Up @@ -123,8 +141,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

exitWith(0);
await daemon.dispose();

Expand Down Expand Up @@ -165,8 +189,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

when(() => stdin.writeln(any())).thenAnswer((_) {
final requests = json.decode(
_.positionalArguments.first as String,
Expand Down Expand Up @@ -201,8 +231,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

final eventFuture = daemon.events.first;
stdout.write(
json.encode([
Expand All @@ -223,8 +259,14 @@ void main() {

/// Emit app start event.
await stdout.appStart();

final app = await appFuture;
expect(await appFuture, isA<FlutterApplication>());

// Emit app started event;
await stdout.appStarted();
expect(app.started, completes);

final eventFuture = daemon.events.first;

// Thanks to Flutter we can now get some errors on stdout instead of
Expand Down Expand Up @@ -253,6 +295,18 @@ extension on StreamController<List<int>> {
void write(String data) => add(utf8.encode('$data\n'));

Future<void> appStart() {
write(
json.encode([
{
'event': 'app.start',
'params': {'appId': '0000'},
}
]),
);
return Future.delayed(Duration.zero);
}

Future<void> appStarted() {
write(
json.encode([
{
Expand Down