flutter/docs/wiki_archive/Upgrading-Flutter-projects-from-using-PlatformMessages-to-using-channels.md
Tong Mu 97b5264fcc
Migrate in-comment links of the flutter/engine repository to the flutter/flutter repository (#166790)
This PR migrates almost all in-comment links that points to the main
branch of flutter/engine repository to the flutter/flutter repository,
ensuring that such links are always up to date.

I've manually verified that all links are valid. There are a few cases
where the migration is not so trivial and I had to look up for the
updated location or line number, but I'm pretty sure the new value is
correct.

The only place that I don't know how to migrate is two links in
[Upgrading-pre-1.12-Android-projects.md](https://github.com/flutter/flutter/blob/master/docs/platforms/android/Upgrading-pre-1.12-Android-projects.md)
pointing to
`https://github.com/flutter/engine/blob/main/shell/platform/android/io/flutter/app/FlutterActivity.java`,
which I guess no longer exists.

There are still many links that point to a specific branch or revision
of the engine repo. I don't think we need to migrate these links, since
they're probably not meant to be kept up to date.

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
2025-04-10 15:58:23 +00:00

5.5 KiB

(This wiki page applies to people migrating code written before March 2017. It is unlikely to still be relevant.)

Introduction

Prior to pull requests flutter/flutter#8837 and flutter/engine#3482, both merged on March 17 2017, communication between Flutter app components written in Dart and host platform app components written for Android or iOS was accomplished by sending and receiving string/JSON messages using methods defined in the following types:

  • PlatformMessages (Dart)
  • FlutterView (Android)
  • FlutterViewController (iOS)

These methods have been removed, leaving only methods for sending unencoded binary messages. A new channel concept has been introduced in their place:

The main goals of the new API are to achieve

  • higher-level communication: asynchronous method calls and event streams
  • less boilerplate and redundancy
  • a more symmetric API across Dart, Android, and iOS

The following sections detail how to port code written against the old API.

Flutter side

With the new API you define in one place the name and type of the channel you need:

var fooChannel = new PlatformMessageChannel<String>('foo', const StringCodec());
var barChannel = new PlatformMethodChannel('bar', const JSONMethodCodec());

There are four codecs to choose from: binary, string, JSON, and standard. The standard codec employs efficient binary serialization of JSON-like values, supporting also buffers as leaf values (e.g. Dart TypedData, Java primitive arrays, Cocoa NSData).

Once you have a channel, you can use it in multiple places without repeating the information needed for its creation.

Sending messages to platform

Replace code like this

String reply = await PlatformMessages.sendString('foo', myString);

with code like this

String reply = await fooChannel.send(myString);

Receiving messages from platform

Replace code like this

PlatformMessages.setStringMessageHandler('foo', (String message) async {
  // do something, then
  return reply;
});

with code like this

fooChannel.setMessageHandler((String message) async {
  // do something, then
  return reply;
});

Invoking platform methods

Replace code like this

var arguments = { 'argA': 'hello', 'argB': 42 };
var message = {
  'method': 'someMethod',
  'args': <Map<String, dynamic>>[arguments],
};
dynamic reply = await PlatformMessages.sendJSON('bar', message);
// what about errors?

or this

var arguments = { 'argA': 'hello', 'argB': 42 };
dynamic reply = await PlatformMessages.invokeMethod(
  'bar',
  'someMethod',
  <Map<String, dynamic>>[arguments],
);
// what about errors?

with code like this

try {
  dynamic result = await barChannel.invokeMethod(
    'someMethod',
    { 'argA': 'hello', 'argB': 42 },
  );
  // use result
} on PlatformException catch(e) {
  // handle error
}

Receiving method calls from platform code

Replace code like this

PlatformMessages.setJSONMessageHandler('bar', (dynamic methodCall) async {
  String method = methodCall['method'];
  List arguments = methodCall['args'];
  // handle call then
  return result;
  // but what about errors?
});

with code like this

barChannel.setMethodCallHandler((MethodCall call) async {
  String method = call.method;
  dynamic arguments = call.arguments;
  // handle call then
  return result;
  // or
  throw new PlatformException(errorCode, anErrorMessage, someDetails);
});

See platform_channel for an example.

Android side

Similar to Flutter side, using FlutterMessageChannel and FlutterMethodChannel from io.flutter.plugin.common.

FlutterView view = ...
FlutterMessageChannel<String> fooChannel =
  new FlutterMessageChannel<>(view, "foo", StringCodec.INSTANCE);

fooChannel.send(myString);

// or if you need to handle a reply:

fooChannel.send(myString, new ReplyHandler<String>() {
  public void onReply(String reply) {
    // do something with reply
  }
});

API documentation. See platform_channel for another example.

iOS side

Similar to Flutter side, using FlutterMessageChannel and FlutterMethodChannel from FlutterChannels.h.

FlutterViewController controller = ...
FlutterMessageChannel* fooChannel =
  [FlutterMessageChannel messageChannelWithName:@"foo"
                                binaryMessenger:controller
                                          codec:[FlutterStringCodec sharedInstance]];

[fooChannel sendMessage:myString];

// or if you need to handle a reply:

[fooChannel sendMessage:myString replyHandler:^(id reply) {
  // do something with (NSString*)reply
}];

API documentation. See platform_channel for another example.