Skip to content

Commit 7f1d141

Browse files
authored
Revert "Migrate to ChannelBuffers.push (flutter#81235)" (flutter#81829)
This reverts commit 35ad43f.
1 parent 51ca131 commit 7f1d141

File tree

77 files changed

+736
-1112
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+736
-1112
lines changed

dev/automated_tests/flutter_test/ticker_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ void main() {
1111
Ticker((Duration duration) { }).start();
1212

1313
final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused');
14-
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
14+
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
1515
});
1616
}

dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ void main() {
2020
app.main();
2121
await tester.pumpAndSettle();
2222

23+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
24+
SystemChannels.textInput.setMockMethodCallHandler(null);
25+
2326
// Focus on a TextFormField.
2427
final Finder finder = find.byKey(const Key('input'));
2528
expect(finder, findsOneWidget);
@@ -45,6 +48,9 @@ void main() {
4548
app.main();
4649
await tester.pumpAndSettle();
4750

51+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
52+
SystemChannels.textInput.setMockMethodCallHandler(null);
53+
4854
// Focus on a TextFormField.
4955
final Finder finder = find.byKey(const Key('empty-input'));
5056
expect(finder, findsOneWidget);
@@ -70,6 +76,9 @@ void main() {
7076
app.main();
7177
await tester.pumpAndSettle();
7278

79+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
80+
SystemChannels.textInput.setMockMethodCallHandler(null);
81+
7382
// This text will show no-enter initially. It will have 'enter-pressed'
7483
// after `onFieldSubmitted` of TextField is triggered.
7584
final Finder textFinder = find.byKey(const Key('text'));
@@ -103,6 +112,9 @@ void main() {
103112
app.main();
104113
await tester.pumpAndSettle();
105114

115+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
116+
SystemChannels.textInput.setMockMethodCallHandler(null);
117+
106118
// Focus on a TextFormField.
107119
final Finder finder = find.byKey(const Key('input'));
108120
expect(finder, findsOneWidget);
@@ -135,6 +147,9 @@ void main() {
135147
app.main();
136148
await tester.pumpAndSettle();
137149

150+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
151+
SystemChannels.textInput.setMockMethodCallHandler(null);
152+
138153
// Focus on a TextFormField.
139154
final Finder finder = find.byKey(const Key('input'));
140155
expect(finder, findsOneWidget);
@@ -182,6 +197,9 @@ void main() {
182197
app.main();
183198
await tester.pumpAndSettle();
184199

200+
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
201+
SystemChannels.textInput.setMockMethodCallHandler(null);
202+
185203
// Select something from the selectable text.
186204
final Finder finder = find.byKey(const Key('selectable'));
187205
expect(finder, findsOneWidget);

examples/hello_world/test_driver/smoke_web_engine_test.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import 'dart:async';
66

77
import 'package:flutter_driver/flutter_driver.dart';
8-
import 'package:test/test.dart';
8+
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
99
import 'package:webdriver/async_io.dart';
1010

1111
/// The following test is used as a simple smoke test for verifying Flutter
@@ -33,7 +33,6 @@ void main() {
3333
test('enable accessibility', () async {
3434
await driver.enableAccessibility();
3535

36-
// TODO(ianh): this delay violates our style guide. We should instead wait for a triggering event.
3736
await Future<void>.delayed(const Duration(seconds: 2));
3837

3938
// Elements with tag "flt-semantics" would show up after enabling

packages/flutter/lib/src/foundation/binding.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ abstract class BindingBase {
104104
/// A number of additional bindings are defined as extensions of
105105
/// [BindingBase], e.g., [ServicesBinding], [RendererBinding], and
106106
/// [WidgetsBinding]. Each of these bindings define behaviors that interact
107-
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers
108-
/// listeners with the [ChannelBuffers], and [RendererBinding]
107+
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers a
108+
/// [ui.PlatformDispatcher.onPlatformMessage] handler, and [RendererBinding]
109109
/// registers [ui.PlatformDispatcher.onMetricsChanged],
110110
/// [ui.PlatformDispatcher.onTextScaleFactorChanged],
111111
/// [ui.PlatformDispatcher.onSemanticsEnabledChanged], and

packages/flutter/lib/src/services/binary_messenger.dart

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
56
import 'dart:typed_data';
67
import 'dart:ui' as ui;
78

9+
import 'binding.dart';
10+
811
/// A function which takes a platform message and asynchronously returns an encoded response.
912
typedef MessageHandler = Future<ByteData?>? Function(ByteData? message);
1013

@@ -16,39 +19,12 @@ abstract class BinaryMessenger {
1619
/// const constructors so that they can be used in const expressions.
1720
const BinaryMessenger();
1821

19-
/// Queues a message.
20-
///
21-
/// The returned future completes immediately.
22-
///
23-
/// This method adds the provided message to the given channel (named by the
24-
/// `channel` argument) of the [ChannelBuffers] object. This simulates what
25-
/// happens when a plugin on the platform thread (e.g. Kotlin or Swift code)
26-
/// sends a message to the plugin package on the Dart thread.
27-
///
28-
/// The `data` argument contains the message as encoded bytes. (The format
29-
/// used for the message depends on the channel.)
22+
/// Calls the handler registered for the given channel.
3023
///
31-
/// The `callback` argument, if non-null, is eventually invoked with the
32-
/// response that would have been sent to the platform thread.
33-
///
34-
/// In production code, it is more efficient to call
35-
/// `ServicesBinding.instance.channelBuffers.push` directly.
36-
///
37-
/// In tests, consider using
38-
/// `tester.binding.defaultBinaryMessenger.handlePlatformMessage` (see
39-
/// [WidgetTester], [TestWidgetsFlutterBinding], [TestDefaultBinaryMessenger],
40-
/// and [TestDefaultBinaryMessenger.handlePlatformMessage] respectively).
24+
/// Typically called by [ServicesBinding] to handle platform messages received
25+
/// from [dart:ui.PlatformDispatcher.onPlatformMessage].
4126
///
4227
/// To register a handler for a given message channel, see [setMessageHandler].
43-
///
44-
/// To send a message _to_ a plugin on the platform thread, see [send].
45-
// TODO(ianh): deprecate this method once cocoon and other customer_tests are migrated:
46-
// @NotYetDeprecated(
47-
// 'Instead of calling this method, use ServicesBinding.instance.channelBuffers.push. '
48-
// 'In tests, consider using tester.binding.defaultBinaryMessenger.handlePlatformMessage '
49-
// 'or TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.handlePlatformMessage. '
50-
// 'This feature was deprecated after v2.1.0-10.0.pre.'
51-
// )
5228
Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback);
5329

5430
/// Send a binary message to the platform plugins on the given channel.
@@ -67,6 +43,37 @@ abstract class BinaryMessenger {
6743
/// The handler's return value, if non-null, is sent as a response, unencoded.
6844
void setMessageHandler(String channel, MessageHandler? handler);
6945

70-
// Looking for setMockMessageHandler or checkMockMessageHandler?
71-
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
46+
/// Returns true if the `handler` argument matches the `handler` previously
47+
/// passed to [setMessageHandler].
48+
///
49+
/// This method is useful for tests or test harnesses that want to assert the
50+
/// handler for the specified channel has not been altered by a previous test.
51+
///
52+
/// Passing null for the `handler` returns true if the handler for the
53+
/// `channel` is not set.
54+
bool checkMessageHandler(String channel, MessageHandler? handler);
55+
56+
/// Set a mock callback for intercepting messages from the [send] method on
57+
/// this class, on the given channel, without decoding them.
58+
///
59+
/// The given callback will replace the currently registered mock callback for
60+
/// that channel, if any. To remove the mock handler, pass null as the
61+
/// `handler` argument.
62+
///
63+
/// The handler's return value, if non-null, is used as a response, unencoded.
64+
///
65+
/// This is intended for testing. Messages intercepted in this manner are not
66+
/// sent to platform plugins.
67+
void setMockMessageHandler(String channel, MessageHandler? handler);
68+
69+
/// Returns true if the `handler` argument matches the `handler` previously
70+
/// passed to [setMockMessageHandler].
71+
///
72+
/// This method is useful for tests or test harnesses that want to assert the
73+
/// mock handler for the specified channel has not been altered by a previous
74+
/// test.
75+
///
76+
/// Passing null for the `handler` returns true if the handler for the
77+
/// `channel` is not set.
78+
bool checkMockMessageHandler(String channel, MessageHandler? handler);
7279
}

packages/flutter/lib/src/services/binding.dart

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
3030
_instance = this;
3131
_defaultBinaryMessenger = createBinaryMessenger();
3232
_restorationManager = createRestorationManager();
33+
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
3334
initLicenses();
3435
SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object));
3536
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
@@ -48,35 +49,14 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
4849
BinaryMessenger get defaultBinaryMessenger => _defaultBinaryMessenger;
4950
late BinaryMessenger _defaultBinaryMessenger;
5051

51-
/// The low level buffering and dispatch mechanism for messages sent by
52-
/// plugins on the engine side to their corresponding plugin code on
53-
/// the framework side.
54-
///
55-
/// This exposes the [dart:ui.channelBuffers] object. Bindings can override
56-
/// this getter to intercept calls to the [ChannelBuffers] mechanism (for
57-
/// example, for tests).
58-
///
59-
/// In production, direct access to this object should not be necessary.
60-
/// Messages are received and dispatched by the [defaultBinaryMessenger]. This
61-
/// object is primarily used to send mock messages in tests, via the
62-
/// [ChannelBuffers.push] method (simulating a plugin sending a message to the
63-
/// framework).
64-
///
65-
/// See also:
66-
///
67-
/// * [PlatformDispatcher.sendPlatformMessage], which is used for sending
68-
/// messages to plugins from the framework (the opposite of
69-
/// [channelBuffers]).
70-
/// * [platformDispatcher], the [PlatformDispatcher] singleton.
71-
ui.ChannelBuffers get channelBuffers => ui.channelBuffers;
72-
7352
/// Creates a default [BinaryMessenger] instance that can be used for sending
7453
/// platform messages.
7554
@protected
7655
BinaryMessenger createBinaryMessenger() {
7756
return const _DefaultBinaryMessenger._();
7857
}
7958

59+
8060
/// Called when the operating system notifies the application of a memory
8161
/// pressure situation.
8262
///
@@ -273,20 +253,17 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
273253
class _DefaultBinaryMessenger extends BinaryMessenger {
274254
const _DefaultBinaryMessenger._();
275255

276-
@override
277-
Future<void> handlePlatformMessage(
278-
String channel,
279-
ByteData? message,
280-
ui.PlatformMessageResponseCallback? callback,
281-
) async {
282-
ui.channelBuffers.push(channel, message, (ByteData? data) {
283-
if (callback != null)
284-
callback(data);
285-
});
286-
}
256+
// Handlers for incoming messages from platform plugins.
257+
// This is static so that this class can have a const constructor.
258+
static final Map<String, MessageHandler> _handlers =
259+
<String, MessageHandler>{};
287260

288-
@override
289-
Future<ByteData?> send(String channel, ByteData? message) {
261+
// Mock handlers that intercept and respond to outgoing messages.
262+
// This is static so that this class can have a const constructor.
263+
static final Map<String, MessageHandler> _mockHandlers =
264+
<String, MessageHandler>{};
265+
266+
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
290267
final Completer<ByteData?> completer = Completer<ByteData?>();
291268
// ui.PlatformDispatcher.instance is accessed directly instead of using
292269
// ServicesBinding.instance.platformDispatcher because this method might be
@@ -295,8 +272,6 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
295272
// ui.PlatformDispatcher.instance because the PlatformDispatcher may be
296273
// dependency injected elsewhere with a different instance. However, static
297274
// access at this location seems to be the least bad option.
298-
// TODO(ianh): Use ServicesBinding.instance once we have better diagnostics
299-
// on that getter.
300275
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
301276
try {
302277
completer.complete(reply);
@@ -312,27 +287,70 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
312287
return completer.future;
313288
}
314289

290+
@override
291+
// TODO(goderbauer): Add pragma (and enable test in
292+
// break_on_framework_exceptions_test.dart) when it works on async methods,
293+
// https://github.com/dart-lang/sdk/issues/45673
294+
// @pragma('vm:notify-debugger-on-exception')
295+
Future<void> handlePlatformMessage(
296+
String channel,
297+
ByteData? data,
298+
ui.PlatformMessageResponseCallback? callback,
299+
) async {
300+
ByteData? response;
301+
try {
302+
final MessageHandler? handler = _handlers[channel];
303+
if (handler != null) {
304+
response = await handler(data);
305+
} else {
306+
ui.channelBuffers.push(channel, data, callback!);
307+
callback = null;
308+
}
309+
} catch (exception, stack) {
310+
FlutterError.reportError(FlutterErrorDetails(
311+
exception: exception,
312+
stack: stack,
313+
library: 'services library',
314+
context: ErrorDescription('during a platform message callback'),
315+
));
316+
} finally {
317+
if (callback != null) {
318+
callback(response);
319+
}
320+
}
321+
}
322+
323+
@override
324+
Future<ByteData?>? send(String channel, ByteData? message) {
325+
final MessageHandler? handler = _mockHandlers[channel];
326+
if (handler != null)
327+
return handler(message);
328+
return _sendPlatformMessage(channel, message);
329+
}
330+
315331
@override
316332
void setMessageHandler(String channel, MessageHandler? handler) {
317333
if (handler == null) {
318-
ui.channelBuffers.clearListener(channel);
334+
_handlers.remove(channel);
319335
} else {
320-
ui.channelBuffers.setListener(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
321-
ByteData? response;
322-
try {
323-
response = await handler(data);
324-
} catch (exception, stack) {
325-
326-
FlutterError.reportError(FlutterErrorDetails(
327-
exception: exception,
328-
stack: stack,
329-
library: 'services library',
330-
context: ErrorDescription('during a platform message callback'),
331-
));
332-
} finally {
333-
callback(response);
334-
}
336+
_handlers[channel] = handler;
337+
ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
338+
await handlePlatformMessage(channel, data, callback);
335339
});
336340
}
337341
}
342+
343+
@override
344+
bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
345+
346+
@override
347+
void setMockMessageHandler(String channel, MessageHandler? handler) {
348+
if (handler == null)
349+
_mockHandlers.remove(channel);
350+
else
351+
_mockHandlers[channel] = handler;
352+
}
353+
354+
@override
355+
bool checkMockMessageHandler(String channel, MessageHandler? handler) => _mockHandlers[channel] == handler;
338356
}

packages/flutter/lib/src/services/message_codec.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ abstract class MethodCodec {
9595
ByteData encodeErrorEnvelope({ required String code, String? message, Object? details});
9696
}
9797

98+
9899
/// Thrown to indicate that a platform interaction failed in the platform
99100
/// plugin.
100101
///

0 commit comments

Comments
 (0)