Skip to content

Commit bcdab11

Browse files
authored
Add support for application exit requests (flutter#121378)
Add support for application exit requests
1 parent b1464e0 commit bcdab11

File tree

20 files changed

+313
-25
lines changed

20 files changed

+313
-25
lines changed

dev/benchmarks/complex_layout/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>

dev/benchmarks/macrobenchmarks/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>

dev/integration_tests/channels/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>

dev/integration_tests/flavors/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929
<key>NSMainNibFile</key>
3030
<string>MainMenu</string>
3131
<key>NSPrincipalClass</key>
32-
<string>FlutterApplication</string>
32+
<string>NSApplication</string>
3333
</dict>
3434
</plist>

dev/integration_tests/flutter_gallery/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>

dev/integration_tests/ui/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>

dev/manual_tests/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ui';
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter/services.dart';
9+
10+
/// Flutter code sample for [ServicesBinding.handleRequestAppExit].
11+
12+
void main() {
13+
runApp(const ApplicationExitExample());
14+
}
15+
16+
class ApplicationExitExample extends StatelessWidget {
17+
const ApplicationExitExample({super.key});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return const MaterialApp(
22+
home: Scaffold(body: Body()),
23+
);
24+
}
25+
}
26+
27+
class Body extends StatefulWidget {
28+
const Body({super.key});
29+
30+
@override
31+
State<Body> createState() => _BodyState();
32+
}
33+
34+
class _BodyState extends State<Body> with WidgetsBindingObserver {
35+
bool _shouldExit = false;
36+
String lastResponse = 'No exit requested yet';
37+
38+
@override
39+
void initState() {
40+
super.initState();
41+
WidgetsBinding.instance.addObserver(this);
42+
}
43+
44+
@override
45+
void dispose() {
46+
WidgetsBinding.instance.removeObserver(this);
47+
super.dispose();
48+
}
49+
50+
Future<void> _quit() async {
51+
final AppExitType exitType = _shouldExit ? AppExitType.required : AppExitType.cancelable;
52+
setState(() {
53+
lastResponse = 'App requesting ${exitType.name} exit';
54+
});
55+
await ServicesBinding.instance.exitApplication(exitType);
56+
}
57+
58+
@override
59+
Future<AppExitResponse> didRequestAppExit() async {
60+
final AppExitResponse response = _shouldExit ? AppExitResponse.exit : AppExitResponse.cancel;
61+
setState(() {
62+
lastResponse = 'App responded ${response.name} to exit request';
63+
});
64+
return response;
65+
}
66+
67+
void _radioChanged(bool? value) {
68+
value ??= true;
69+
if (_shouldExit == value) {
70+
return;
71+
}
72+
setState(() {
73+
_shouldExit = value!;
74+
});
75+
}
76+
77+
@override
78+
Widget build(BuildContext context) {
79+
return Center(
80+
child: SizedBox(
81+
width: 300,
82+
child: IntrinsicHeight(
83+
child: Column(
84+
children: <Widget>[
85+
RadioListTile<bool>(
86+
title: const Text('Do Not Allow Exit'),
87+
groupValue: _shouldExit,
88+
value: false,
89+
onChanged: _radioChanged,
90+
),
91+
RadioListTile<bool>(
92+
title: const Text('Allow Exit'),
93+
groupValue: _shouldExit,
94+
value: true,
95+
onChanged: _radioChanged,
96+
),
97+
const SizedBox(height: 30),
98+
ElevatedButton(
99+
onPressed: _quit,
100+
child: const Text('Quit'),
101+
),
102+
const SizedBox(height: 30),
103+
Text(lastResponse),
104+
],
105+
),
106+
),
107+
),
108+
);
109+
}
110+
}

examples/api/macos/Runner/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<key>NSMainNibFile</key>
2828
<string>MainMenu</string>
2929
<key>NSPrincipalClass</key>
30-
<string>FlutterApplication</string>
30+
<string>NSApplication</string>
3131
</dict>
3232
</plist>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter_api_samples/services/binding/handle_request_app_exit.0.dart' as example;
6+
import 'package:flutter_test/flutter_test.dart';
7+
8+
void main() {
9+
testWidgets('Application Exit example', (WidgetTester tester) async {
10+
await tester.pumpWidget(
11+
const example.ApplicationExitExample(),
12+
);
13+
14+
expect(find.text('No exit requested yet'), findsOneWidget);
15+
expect(find.text('Do Not Allow Exit'), findsOneWidget);
16+
expect(find.text('Allow Exit'), findsOneWidget);
17+
expect(find.text('Quit'), findsOneWidget);
18+
await tester.tap(find.text('Quit'));
19+
await tester.pump();
20+
expect(find.text('App requesting cancelable exit'), findsOneWidget);
21+
});
22+
}

0 commit comments

Comments
 (0)