Skip to content

Commit 35ad43f

Browse files
authored
Migrate to ChannelBuffers.push (flutter#81235)
1 parent cb0bda3 commit 35ad43f

File tree

77 files changed

+1112
-736
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

+1112
-736
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 ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
14+
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
1515
});
1616
}

dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ 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-
2623
// Focus on a TextFormField.
2724
final Finder finder = find.byKey(const Key('input'));
2825
expect(finder, findsOneWidget);
@@ -48,9 +45,6 @@ void main() {
4845
app.main();
4946
await tester.pumpAndSettle();
5047

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

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

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

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

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

examples/hello_world/test_driver/smoke_web_engine_test.dart

Lines changed: 2 additions & 1 deletion
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' hide TypeMatcher, isInstanceOf;
8+
import 'package:test/test.dart';
99
import 'package:webdriver/async_io.dart';
1010

1111
/// The following test is used as a simple smoke test for verifying Flutter
@@ -33,6 +33,7 @@ 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.
3637
await Future<void>.delayed(const Duration(seconds: 2));
3738

3839
// 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 a
108-
/// [ui.PlatformDispatcher.onPlatformMessage] handler, and [RendererBinding]
107+
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers
108+
/// listeners with the [ChannelBuffers], 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: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
65
import 'dart:typed_data';
76
import 'dart:ui' as ui;
87

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

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

22-
/// Calls the handler registered for the given channel.
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.)
2330
///
24-
/// Typically called by [ServicesBinding] to handle platform messages received
25-
/// from [dart:ui.PlatformDispatcher.onPlatformMessage].
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).
2641
///
2742
/// 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+
// )
2852
Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback);
2953

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

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);
70+
// Looking for setMockMessageHandler or checkMockMessageHandler?
71+
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
7972
}

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

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

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+
5273
/// Creates a default [BinaryMessenger] instance that can be used for sending
5374
/// platform messages.
5475
@protected
5576
BinaryMessenger createBinaryMessenger() {
5677
return const _DefaultBinaryMessenger._();
5778
}
5879

59-
6080
/// Called when the operating system notifies the application of a memory
6181
/// pressure situation.
6282
///
@@ -253,17 +273,20 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
253273
class _DefaultBinaryMessenger extends BinaryMessenger {
254274
const _DefaultBinaryMessenger._();
255275

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>{};
260-
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>{};
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+
}
265287

266-
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
288+
@override
289+
Future<ByteData?> send(String channel, ByteData? message) {
267290
final Completer<ByteData?> completer = Completer<ByteData?>();
268291
// ui.PlatformDispatcher.instance is accessed directly instead of using
269292
// ServicesBinding.instance.platformDispatcher because this method might be
@@ -272,6 +295,8 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
272295
// ui.PlatformDispatcher.instance because the PlatformDispatcher may be
273296
// dependency injected elsewhere with a different instance. However, static
274297
// 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.
275300
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
276301
try {
277302
completer.complete(reply);
@@ -287,70 +312,27 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
287312
return completer.future;
288313
}
289314

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-
331315
@override
332316
void setMessageHandler(String channel, MessageHandler? handler) {
333317
if (handler == null) {
334-
_handlers.remove(channel);
318+
ui.channelBuffers.clearListener(channel);
335319
} else {
336-
_handlers[channel] = handler;
337-
ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
338-
await handlePlatformMessage(channel, data, callback);
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+
}
339335
});
340336
}
341337
}
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;
356338
}

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

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

98-
9998
/// Thrown to indicate that a platform interaction failed in the platform
10099
/// plugin.
101100
///

0 commit comments

Comments
 (0)