Skip to content

Commit ae4451d

Browse files
authored
[linux] Add MethodChannel (#153)
This adds the MethodChannel and related APIs on Linux, further aligning with the Flutter APIs. As with the current state on macOS, this is implemented as an implementation detail of the existing plugin classes, so that there's no plugin API breakage at this stage. This currently deviates from the MethodChannel API on other platforms by using InvokeMethodCall instead of InvokeMethod. Addressing this will be done in a follow-up change. Part of issue #102
1 parent 5fa4895 commit ae4451d

12 files changed

+244
-55
lines changed

library/linux/include/flutter_desktop_embedding/binary_messenger.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,26 @@
1414
#ifndef LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_BINARY_MESSENGER_H_
1515
#define LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_BINARY_MESSENGER_H_
1616

17+
#include <functional>
1718
#include <string>
1819

20+
// TODO: Consider adding absl as a dependency and using absl::Span for all of
21+
// the message/message_size pairs.
1922
namespace flutter_desktop_embedding {
2023

24+
// A message reply callback.
25+
//
26+
// Used for submitting a reply back to a Flutter message sender.
27+
typedef std::function<void(const uint8_t *reply, const size_t reply_size)>
28+
BinaryReply;
29+
30+
// A message handler callback.
31+
//
32+
// Used for receiving messages from Flutter and providing an asynchronous reply.
33+
typedef std::function<void(const uint8_t *message, const size_t message_size,
34+
BinaryReply reply)>
35+
BinaryMessageHandler;
36+
2137
// A protocol for a class that handles communication of binary data on named
2238
// channels to and from the Flutter engine.
2339
class BinaryMessenger {
@@ -32,7 +48,13 @@ class BinaryMessenger {
3248
// TODO: Add support for a version of Send expecting a reply once
3349
// https://github.com/flutter/flutter/issues/18852 is fixed.
3450

35-
// TODO: Add SetMessageHandler. See Issue #102.
51+
// Registers a message handler for incoming binary messages from the Flutter
52+
// side on the specified channel.
53+
//
54+
// Replaces any existing handler. Provide a null handler to unregister the
55+
// existing handler.
56+
virtual void SetMessageHandler(const std::string &channel,
57+
BinaryMessageHandler handler) = 0;
3658
};
3759

3860
} // namespace flutter_desktop_embedding

library/linux/include/flutter_desktop_embedding/json_plugin.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
#ifndef LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_JSON_PLUGIN_H_
1515
#define LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_JSON_PLUGIN_H_
1616

17+
#include <memory>
18+
#include <string>
19+
1720
#include "json_method_call.h"
21+
#include "method_channel.h"
1822
#include "plugin.h"
1923

2024
namespace flutter_desktop_embedding {
@@ -38,16 +42,24 @@ class JsonPlugin : public Plugin {
3842
std::unique_ptr<MethodResult> result) override;
3943

4044
protected:
45+
// Plugin implementation:
46+
void RegisterMethodChannels(BinaryMessenger *messenger) override;
47+
4148
// Identical to HandleMethodCall, except that the call has been cast to the
4249
// more specific type. Subclasses must implement this instead of
4350
// HandleMethodCall.
4451
virtual void HandleJsonMethodCall(const JsonMethodCall &method_call,
4552
std::unique_ptr<MethodResult> result) = 0;
4653

47-
// Calls InvokeMethodCall with a JsonMethodCall constructed from the given
48-
// values.
54+
// Calls InvokeMethodCall on |method_channel_| with a JsonMethodCall
55+
// constructed from the given values.
4956
void InvokeMethod(const std::string &method,
5057
const Json::Value &arguments = Json::Value());
58+
59+
private:
60+
// The MethodChannel used by this plugin for communication with the Flutter
61+
// engine.
62+
std::unique_ptr<MethodChannel> method_channel_;
5163
};
5264

5365
} // namespace flutter_desktop_embedding
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
#ifndef LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_METHOD_CHANNEL_H_
15+
#define LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_METHOD_CHANNEL_H_
16+
17+
#include <string>
18+
19+
#include "binary_messenger.h"
20+
#include "method_call.h"
21+
#include "method_codec.h"
22+
#include "method_result.h"
23+
24+
namespace flutter_desktop_embedding {
25+
26+
// A handler for receiving a method call from the Flutter engine.
27+
//
28+
// Implementations must asynchronously call exactly one of the methods on
29+
// |result| to indicate the resust of the method call.
30+
typedef std::function<void(const MethodCall &call,
31+
std::unique_ptr<MethodResult> result)>
32+
MethodCallHandler;
33+
34+
// A channel for communicating with the Flutter engine using invocation of
35+
// asynchronous methods.
36+
class MethodChannel {
37+
public:
38+
// Creates an instance that sends and receives method calls on the channel
39+
// named |name|, encoded with |codec| and dispatched via |messenger|.
40+
//
41+
// TODO: Make codec optional once the standard codec is supported (Issue #67).
42+
MethodChannel(BinaryMessenger *messenger, const std::string &name,
43+
const MethodCodec *codec);
44+
~MethodChannel();
45+
46+
// Prevent copying.
47+
MethodChannel(MethodChannel const &) = delete;
48+
MethodChannel &operator=(MethodChannel const &) = delete;
49+
50+
// Sends |method_call| to the Flutter engine on this channel.
51+
//
52+
// TODO: Implement InovkeMethod and remove this. This is a temporary
53+
// implementation, since supporting InvokeMethod involves significant changes
54+
// to other classes.
55+
void InvokeMethodCall(const MethodCall &method_call) const;
56+
57+
// TODO: Add support for a version expecting a reply once
58+
// https://github.com/flutter/flutter/issues/18852 is fixed.
59+
60+
// Registers a handler that should be called any time a method call is
61+
// received on this channel.
62+
void SetMethodCallHandler(MethodCallHandler handler) const;
63+
64+
private:
65+
BinaryMessenger *messenger_;
66+
std::string name_;
67+
const MethodCodec *codec_;
68+
};
69+
70+
} // namespace flutter_desktop_embedding
71+
72+
#endif // LIBRARY_LINUX_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_METHOD_CHANNEL_H_

library/linux/include/flutter_desktop_embedding/plugin.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,26 @@ class Plugin {
5959
// while waiting for this plugin to handle its platform message.
6060
virtual bool input_blocking() const { return input_blocking_; }
6161

62-
// Sets the pointer to the caller-owned binary messenger.
62+
// Binds this plugin to the given caller-owned binary messenger. It must
63+
// remain valid for the life of the plugin.
6364
//
6465
// The embedder typically sets this pointer rather than the client.
65-
virtual void set_binary_messenger(BinaryMessenger *messenger) {
66-
messenger_ = messenger;
67-
}
66+
void SetBinaryMessenger(BinaryMessenger *messenger);
6867

6968
protected:
69+
// Implementers should register any MethodChannels that should receive
70+
// messages from Flutter with |messenger| when this is called.
71+
virtual void RegisterMethodChannels(BinaryMessenger *messenger) = 0;
72+
7073
// Calls a method in the Flutter engine on this Plugin's channel.
74+
//
75+
// Deprecated. Use MethodChannel's InvokeMethodCall instead.
7176
void InvokeMethodCall(const MethodCall &method_call);
7277

7378
private:
7479
std::string channel_;
7580
// Caller-owned instance of the binary messenger used to message the engine.
76-
BinaryMessenger *messenger_;
81+
const BinaryMessenger *messenger_;
7782
bool input_blocking_;
7883
};
7984

library/linux/src/embedder.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ namespace flutter_desktop_embedding {
242242

243243
bool AddPlugin(GLFWwindow *flutter_window, std::unique_ptr<Plugin> plugin) {
244244
auto state = GetSavedEmbedderState(flutter_window);
245-
plugin->set_binary_messenger(state->plugin_handler.get());
246245
return state->plugin_handler->AddPlugin(std::move(plugin));
247246
}
248247

library/linux/src/internal/engine_method_result.cc

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,17 @@
1717

1818
namespace flutter_desktop_embedding {
1919

20-
EngineMethodResult::EngineMethodResult(
21-
FlutterEngine engine,
22-
const FlutterPlatformMessageResponseHandle *response_handle,
23-
const MethodCodec *codec)
24-
: engine_(engine), response_handle_(response_handle), codec_(codec) {
25-
if (!response_handle_) {
26-
std::cerr << "Error: Response handle must be provided for a response."
20+
EngineMethodResult::EngineMethodResult(BinaryReply reply_handler,
21+
const MethodCodec *codec)
22+
: reply_handler_(std::move(reply_handler)), codec_(codec) {
23+
if (!reply_handler_) {
24+
std::cerr << "Error: Reply handler must be provided for a response."
2725
<< std::endl;
2826
}
2927
}
3028

3129
EngineMethodResult::~EngineMethodResult() {
32-
if (response_handle_) {
30+
if (reply_handler_) {
3331
// Warn, rather than send a not-implemented response, since the engine may
3432
// no longer be valid at this point.
3533
std::cerr
@@ -55,20 +53,18 @@ void EngineMethodResult::ErrorInternal(const std::string &error_code,
5553
void EngineMethodResult::NotImplementedInternal() { SendResponseData(nullptr); }
5654

5755
void EngineMethodResult::SendResponseData(const std::vector<uint8_t> *data) {
58-
if (!response_handle_) {
56+
if (!reply_handler_) {
5957
std::cerr
60-
<< "Error: Response can be set only once. Ignoring duplicate response."
58+
<< "Error: Only one of Success, Error, or NotImplemented can be called,"
59+
<< " and it can be called exactyl once. Ignoring duplicate result."
6160
<< std::endl;
6261
return;
6362
}
6463

6564
const uint8_t *message = data && !data->empty() ? data->data() : nullptr;
6665
size_t message_size = data ? data->size() : 0;
67-
FlutterEngineSendPlatformMessageResponse(engine_, response_handle_, message,
68-
message_size);
69-
// The engine frees the response handle once
70-
// FlutterEngineSendPlatformMessageResponse is called.
71-
response_handle_ = nullptr;
66+
reply_handler_(message, message_size);
67+
reply_handler_ = nullptr;
7268
}
7369

7470
} // namespace flutter_desktop_embedding

library/linux/src/internal/engine_method_result.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
#include <string>
1818
#include <vector>
1919

20-
#include <flutter_embedder.h>
21-
20+
#include "library/linux/include/flutter_desktop_embedding/binary_messenger.h"
2221
#include "library/linux/include/flutter_desktop_embedding/method_codec.h"
2322
#include "library/linux/include/flutter_desktop_embedding/method_result.h"
2423

@@ -27,15 +26,12 @@ namespace flutter_desktop_embedding {
2726
// Implemention of MethodResult that sends responses to the Flutter egnine.
2827
class EngineMethodResult : public MethodResult {
2928
public:
30-
// Creates a result object that will send results to |engine|, tagged as
31-
// associated with |response_handle|, encoded using |codec|. The |engine|
32-
// and |codec| pointers must remain valid for as long as this object exists.
29+
// Creates a result object that will send results to |reply_handler|, encoded
30+
// using |codec|. The |codec| pointer must remain valid for as long as this
31+
// object exists.
3332
//
3433
// If the codec is null, only NotImplemented() may be called.
35-
EngineMethodResult(
36-
FlutterEngine engine,
37-
const FlutterPlatformMessageResponseHandle *response_handle,
38-
const MethodCodec *codec);
34+
EngineMethodResult(BinaryReply reply_handler, const MethodCodec *codec);
3935
~EngineMethodResult();
4036

4137
protected:
@@ -52,8 +48,7 @@ class EngineMethodResult : public MethodResult {
5248
// the engine.
5349
void SendResponseData(const std::vector<uint8_t> *data);
5450

55-
FlutterEngine engine_;
56-
const FlutterPlatformMessageResponseHandle *response_handle_;
51+
BinaryReply reply_handler_;
5752
const MethodCodec *codec_;
5853
};
5954

library/linux/src/internal/plugin_handler.cc

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414
#include "library/linux/src/internal/plugin_handler.h"
1515

16+
#include "library/linux/include/flutter_desktop_embedding/method_channel.h"
1617
#include "library/linux/src/internal/engine_method_result.h"
1718

1819
#include <iostream>
@@ -27,6 +28,7 @@ bool PluginHandler::AddPlugin(std::unique_ptr<Plugin> plugin) {
2728
if (plugins_.find(plugin->channel()) != plugins_.end()) {
2829
return false;
2930
}
31+
plugin->SetBinaryMessenger(this);
3032
plugins_.insert(std::make_pair(plugin->channel(), std::move(plugin)));
3133
return true;
3234
}
@@ -36,36 +38,42 @@ void PluginHandler::HandleMethodCallMessage(
3638
std::function<void(void)> input_block_cb,
3739
std::function<void(void)> input_unblock_cb) {
3840
std::string channel(message->channel);
41+
auto *response_handle = message->response_handle;
42+
auto *response_engine = engine_;
43+
BinaryReply reply_handler = [response_engine, response_handle](
44+
const uint8_t *reply,
45+
const size_t reply_size) mutable {
46+
if (!response_handle) {
47+
std::cerr << "Error: Response can be set only once. Ignoring "
48+
"duplicate response."
49+
<< std::endl;
50+
return;
51+
}
52+
FlutterEngineSendPlatformMessageResponse(response_engine, response_handle,
53+
reply, reply_size);
54+
// The engine frees the response handle once
55+
// FlutterEngineSendPlatformMessageResponse is called.
56+
response_handle = nullptr;
57+
};
3958

40-
// Find the plugin for the channel; if there isn't one, report the failure.
41-
if (plugins_.find(channel) == plugins_.end()) {
59+
// Find the handler for the channel; if there isn't one, report the failure.
60+
if (handlers_.find(channel) == handlers_.end()) {
4261
auto result =
4362
std::make_unique<flutter_desktop_embedding::EngineMethodResult>(
44-
engine_, message->response_handle, nullptr);
63+
std::move(reply_handler), nullptr);
4564
result->NotImplemented();
4665
return;
4766
}
67+
const BinaryMessageHandler &message_handler = handlers_[channel];
4868
const std::unique_ptr<Plugin> &plugin = plugins_[channel];
4969

50-
// Use the plugin's codec to decode the call and build a result handler.
51-
const flutter_desktop_embedding::MethodCodec &codec = plugin->GetCodec();
52-
auto result = std::make_unique<flutter_desktop_embedding::EngineMethodResult>(
53-
engine_, message->response_handle, &codec);
54-
std::unique_ptr<flutter_desktop_embedding::MethodCall> method_call =
55-
codec.DecodeMethodCall(message->message, message->message_size);
56-
if (!method_call) {
57-
std::cerr << "Unable to construct method call from message on channel "
58-
<< message->channel << std::endl;
59-
result->NotImplemented();
60-
return;
61-
}
62-
6370
// Process the call, handling input blocking if requested by the plugin.
64-
if (plugin->input_blocking()) {
71+
if (plugin && plugin->input_blocking()) {
6572
input_block_cb();
6673
}
67-
plugin->HandleMethodCall(*method_call, std::move(result));
68-
if (plugin->input_blocking()) {
74+
message_handler(message->message, message->message_size,
75+
std::move(reply_handler));
76+
if (plugin && plugin->input_blocking()) {
6977
input_unblock_cb();
7078
}
7179
}
@@ -81,4 +89,9 @@ void PluginHandler::Send(const std::string &channel, const uint8_t *message,
8189
FlutterEngineSendPlatformMessage(engine_, &platform_message);
8290
}
8391

92+
void PluginHandler::SetMessageHandler(const std::string &channel,
93+
BinaryMessageHandler handler) {
94+
handlers_[channel] = std::move(handler);
95+
}
96+
8497
} // namespace flutter_desktop_embedding

library/linux/src/internal/plugin_handler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,13 @@ class PluginHandler : public BinaryMessenger {
6363
// BinaryMessenger implementation:
6464
void Send(const std::string &channel, const uint8_t *message,
6565
const size_t message_size) const override;
66+
void SetMessageHandler(const std::string &channel,
67+
BinaryMessageHandler handler) override;
6668

6769
private:
6870
FlutterEngine engine_;
6971
std::map<std::string, std::unique_ptr<Plugin>> plugins_;
72+
std::map<std::string, BinaryMessageHandler> handlers_;
7073
};
7174

7275
} // namespace flutter_desktop_embedding

0 commit comments

Comments
 (0)