feat: Add streaming handlers for live TV proxying and VOD HLS transcoding using FFmpeg.

This commit is contained in:
Michael committed 2025-12-16 20:12:57 +01:00
1 parent 887bfad433
commit 89bd5bd7cb
51 files changed
+4568

No files matched your search

@@ -0,0 +1,50 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
#include <flutter_messenger.h>
#include <map>
#include <string>
#include "include/flutter/binary_messenger.h"
namespace flutter {
// Wrapper around a FlutterDesktopMessengerRef that implements the
// BinaryMessenger API.
class BinaryMessengerImpl : public BinaryMessenger {
public:
explicit BinaryMessengerImpl(FlutterDesktopMessengerRef core_messenger);
virtual ~BinaryMessengerImpl();
// Prevent copying.
BinaryMessengerImpl(BinaryMessengerImpl const&) = delete;
BinaryMessengerImpl& operator=(BinaryMessengerImpl const&) = delete;
// |flutter::BinaryMessenger|
void Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const override;
// |flutter::BinaryMessenger|
void SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) override;
private:
// Handle for interacting with the C API.
FlutterDesktopMessengerRef messenger_;
// A map from channel names to the BinaryMessageHandler that should be called
// for incoming messages on that channel.
std::map<std::string, BinaryMessageHandler> handlers_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
@@ -0,0 +1,102 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BYTE_BUFFER_STREAMS_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BYTE_BUFFER_STREAMS_H_
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <vector>
#include "include/flutter/byte_streams.h"
namespace flutter {
// Implementation of ByteStreamReader base on a byte array.
class ByteBufferStreamReader : public ByteStreamReader {
public:
// Createa a reader reading from |bytes|, which must have a length of |size|.
// |bytes| must remain valid for the lifetime of this object.
explicit ByteBufferStreamReader(const uint8_t* bytes, size_t size)
: bytes_(bytes), size_(size) {}
virtual ~ByteBufferStreamReader() = default;
// |ByteStreamReader|
uint8_t ReadByte() override {
if (location_ >= size_) {
std::cerr << "Invalid read in StandardCodecByteStreamReader" << std::endl;
return 0;
}
return bytes_[location_++];
}
// |ByteStreamReader|
void ReadBytes(uint8_t* buffer, size_t length) override {
if (location_ + length > size_) {
std::cerr << "Invalid read in StandardCodecByteStreamReader" << std::endl;
return;
}
std::memcpy(buffer, &bytes_[location_], length);
location_ += length;
}
// |ByteStreamReader|
void ReadAlignment(uint8_t alignment) override {
uint8_t mod = location_ % alignment;
if (mod) {
location_ += alignment - mod;
}
}
private:
// The buffer to read from.
const uint8_t* bytes_;
// The total size of the buffer.
size_t size_;
// The current read location.
size_t location_ = 0;
};
// Implementation of ByteStreamWriter based on a byte array.
class ByteBufferStreamWriter : public ByteStreamWriter {
public:
// Creates a writer that writes into |buffer|.
// |buffer| must remain valid for the lifetime of this object.
explicit ByteBufferStreamWriter(std::vector<uint8_t>* buffer)
: bytes_(buffer) {
assert(buffer);
}
virtual ~ByteBufferStreamWriter() = default;
// |ByteStreamWriter|
void WriteByte(uint8_t byte) { bytes_->push_back(byte); }
// |ByteStreamWriter|
void WriteBytes(const uint8_t* bytes, size_t length) {
assert(length > 0);
bytes_->insert(bytes_->end(), bytes, bytes + length);
}
// |ByteStreamWriter|
void WriteAlignment(uint8_t alignment) {
uint8_t mod = bytes_->size() % alignment;
if (mod) {
for (int i = 0; i < alignment - mod; ++i) {
WriteByte(0);
}
}
}
private:
// The buffer to write to.
std::vector<uint8_t>* bytes_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BYTE_BUFFER_STREAMS_H_
@@ -0,0 +1,284 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains the implementations of any class in the wrapper that
// - is not fully inline, and
// - is necessary for all clients of the wrapper (either app or plugin).
// It exists instead of the usual structure of having some_class_name.cc files
// so that changes to the set of things that need non-header implementations
// are not breaking changes for the template.
//
// If https://github.com/flutter/flutter/issues/57146 is fixed, this can be
// removed in favor of the normal structure since templates will no longer
// manually include files.
#include <cassert>
#include <iostream>
#include <variant>
#include "binary_messenger_impl.h"
#include "include/flutter/engine_method_result.h"
#include "include/flutter/method_channel.h"
#include "include/flutter/standard_method_codec.h"
#include "texture_registrar_impl.h"
namespace flutter {
// ========== binary_messenger_impl.h ==========
namespace {
using FlutterDesktopMessengerScopedLock =
std::unique_ptr<FlutterDesktopMessenger,
decltype(&FlutterDesktopMessengerUnlock)>;
// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along
// with a BinaryReply that will send a response on |message|'s response handle.
//
// This serves as an adaptor between the function-pointer-based message callback
// interface provided by the C API and the std::function-based message handler
// interface of BinaryMessenger.
void ForwardToHandler(FlutterDesktopMessengerRef messenger,
const FlutterDesktopMessage* message,
void* user_data) {
auto* response_handle = message->response_handle;
auto messenger_ptr = std::shared_ptr<FlutterDesktopMessenger>(
FlutterDesktopMessengerAddRef(messenger),
&FlutterDesktopMessengerRelease);
BinaryReply reply_handler = [messenger_ptr, response_handle](
const uint8_t* reply,
size_t reply_size) mutable {
// Note: This lambda can be called on any thread.
auto lock = FlutterDesktopMessengerScopedLock(
FlutterDesktopMessengerLock(messenger_ptr.get()),
&FlutterDesktopMessengerUnlock);
if (!FlutterDesktopMessengerIsAvailable(messenger_ptr.get())) {
// Drop reply if it comes in after the engine is destroyed.
return;
}
if (!response_handle) {
std::cerr << "Error: Response can be set only once. Ignoring "
"duplicate response."
<< std::endl;
return;
}
FlutterDesktopMessengerSendResponse(messenger_ptr.get(), response_handle,
reply, reply_size);
// The engine frees the response handle once
// FlutterDesktopSendMessageResponse is called.
response_handle = nullptr;
};
const BinaryMessageHandler& message_handler =
*static_cast<BinaryMessageHandler*>(user_data);
message_handler(message->message, message->message_size,
std::move(reply_handler));
}
} // namespace
BinaryMessengerImpl::BinaryMessengerImpl(
FlutterDesktopMessengerRef core_messenger)
: messenger_(core_messenger) {}
BinaryMessengerImpl::~BinaryMessengerImpl() = default;
void BinaryMessengerImpl::Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const {
if (reply == nullptr) {
FlutterDesktopMessengerSend(messenger_, channel.c_str(), message,
message_size);
return;
}
struct Captures {
BinaryReply reply;
};
auto captures = new Captures();
captures->reply = reply;
auto message_reply = [](const uint8_t* data, size_t data_size,
void* user_data) {
auto captures = reinterpret_cast<Captures*>(user_data);
captures->reply(data, data_size);
delete captures;
};
bool result = FlutterDesktopMessengerSendWithReply(
messenger_, channel.c_str(), message, message_size, message_reply,
captures);
if (!result) {
delete captures;
}
}
void BinaryMessengerImpl::SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) {
if (!handler) {
handlers_.erase(channel);
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(), nullptr,
nullptr);
return;
}
// Save the handler, to keep it alive.
handlers_[channel] = std::move(handler);
BinaryMessageHandler* message_handler = &handlers_[channel];
// Set an adaptor callback that will invoke the handler.
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(),
ForwardToHandler, message_handler);
}
// ========== engine_method_result.h ==========
namespace internal {
ReplyManager::ReplyManager(BinaryReply reply_handler)
: reply_handler_(std::move(reply_handler)) {
assert(reply_handler_);
}
ReplyManager::~ReplyManager() {
if (reply_handler_) {
// Warn, rather than send a not-implemented response, since the engine may
// no longer be valid at this point.
std::cerr
<< "Warning: Failed to respond to a message. This is a memory leak."
<< std::endl;
}
}
void ReplyManager::SendResponseData(const std::vector<uint8_t>* data) {
if (!reply_handler_) {
std::cerr
<< "Error: Only one of Success, Error, or NotImplemented can be "
"called,"
<< " and it can be called exactly once. Ignoring duplicate result."
<< std::endl;
return;
}
const uint8_t* message = data && !data->empty() ? data->data() : nullptr;
size_t message_size = data ? data->size() : 0;
reply_handler_(message, message_size);
reply_handler_ = nullptr;
}
} // namespace internal
// ========== method_channel.h ==========
namespace {
constexpr char kControlChannelName[] = "dev.flutter/channel-buffers";
constexpr char kResizeMethod[] = "resize";
constexpr char kOverflowMethod[] = "overflow";
} // namespace
namespace internal {
void ResizeChannel(BinaryMessenger* messenger, std::string name, int new_size) {
auto control_channel = std::make_unique<MethodChannel<EncodableValue>>(
messenger, kControlChannelName, &StandardMethodCodec::GetInstance());
// The deserialization logic handles only 32 bits values, see
// https://github.com/flutter/engine/blob/93e8901490e78c7ba7e319cce4470d9c6478c6dc/lib/ui/channel_buffers.dart#L495.
control_channel->InvokeMethod(
kResizeMethod, std::make_unique<EncodableValue>(EncodableList{
EncodableValue(name),
EncodableValue(static_cast<int32_t>(new_size)),
}));
}
void SetChannelWarnsOnOverflow(BinaryMessenger* messenger,
std::string name,
bool warns) {
auto control_channel = std::make_unique<MethodChannel<EncodableValue>>(
messenger, kControlChannelName, &StandardMethodCodec::GetInstance());
control_channel->InvokeMethod(kOverflowMethod,
std::make_unique<EncodableValue>(EncodableList{
EncodableValue(name),
EncodableValue(!warns),
}));
}
} // namespace internal
// ========== texture_registrar_impl.h ==========
TextureRegistrarImpl::TextureRegistrarImpl(
FlutterDesktopTextureRegistrarRef texture_registrar_ref)
: texture_registrar_ref_(texture_registrar_ref) {}
TextureRegistrarImpl::~TextureRegistrarImpl() = default;
int64_t TextureRegistrarImpl::RegisterTexture(TextureVariant* texture) {
FlutterDesktopTextureInfo info = {};
if (auto pixel_buffer_texture = std::get_if<PixelBufferTexture>(texture)) {
info.type = kFlutterDesktopPixelBufferTexture;
info.pixel_buffer_config.user_data = pixel_buffer_texture;
info.pixel_buffer_config.callback =
[](size_t width, size_t height,
void* user_data) -> const FlutterDesktopPixelBuffer* {
auto texture = static_cast<PixelBufferTexture*>(user_data);
return texture->CopyPixelBuffer(width, height);
};
} else if (auto gpu_surface_texture =
std::get_if<GpuSurfaceTexture>(texture)) {
info.type = kFlutterDesktopGpuSurfaceTexture;
info.gpu_surface_config.struct_size =
sizeof(FlutterDesktopGpuSurfaceTextureConfig);
info.gpu_surface_config.type = gpu_surface_texture->surface_type();
info.gpu_surface_config.user_data = gpu_surface_texture;
info.gpu_surface_config.callback =
[](size_t width, size_t height,
void* user_data) -> const FlutterDesktopGpuSurfaceDescriptor* {
auto texture = static_cast<GpuSurfaceTexture*>(user_data);
return texture->ObtainDescriptor(width, height);
};
} else {
std::cerr << "Attempting to register unknown texture variant." << std::endl;
return -1;
}
int64_t texture_id = FlutterDesktopTextureRegistrarRegisterExternalTexture(
texture_registrar_ref_, &info);
return texture_id;
} // namespace flutter
bool TextureRegistrarImpl::MarkTextureFrameAvailable(int64_t texture_id) {
return FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable(
texture_registrar_ref_, texture_id);
}
void TextureRegistrarImpl::UnregisterTexture(int64_t texture_id,
std::function<void()> callback) {
if (callback == nullptr) {
FlutterDesktopTextureRegistrarUnregisterExternalTexture(
texture_registrar_ref_, texture_id, nullptr, nullptr);
return;
}
struct Captures {
std::function<void()> callback;
};
auto captures = new Captures();
captures->callback = std::move(callback);
FlutterDesktopTextureRegistrarUnregisterExternalTexture(
texture_registrar_ref_, texture_id,
[](void* opaque) {
auto captures = reinterpret_cast<Captures*>(opaque);
captures->callback();
delete captures;
},
captures);
}
bool TextureRegistrarImpl::UnregisterTexture(int64_t texture_id) {
UnregisterTexture(texture_id, nullptr);
return true;
}
} // namespace flutter
@@ -0,0 +1,11 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file is deprecated in favor of core_implementations.cc. This is a
// temporary forwarding implementation so that the switch to
// core_implementations.cc isn't an immediate breaking change, allowing for the
// template to be updated to include it and update the template version before
// removing this file.
#include "core_implementations.cc"
@@ -0,0 +1,126 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/flutter/flutter_engine.h"
#include <algorithm>
#include <iostream>
#include "binary_messenger_impl.h"
#include "flutter_windows.h"
namespace flutter {
FlutterEngine::FlutterEngine(const DartProject& project) {
FlutterDesktopEngineProperties c_engine_properties = {};
c_engine_properties.assets_path = project.assets_path().c_str();
c_engine_properties.icu_data_path = project.icu_data_path().c_str();
c_engine_properties.aot_library_path = project.aot_library_path().c_str();
c_engine_properties.dart_entrypoint = project.dart_entrypoint().c_str();
c_engine_properties.gpu_preference =
static_cast<FlutterDesktopGpuPreference>(project.gpu_preference());
c_engine_properties.ui_thread_policy =
static_cast<FlutterDesktopUIThreadPolicy>(project.ui_thread_policy());
const std::vector<std::string>& entrypoint_args =
project.dart_entrypoint_arguments();
std::vector<const char*> entrypoint_argv;
std::transform(
entrypoint_args.begin(), entrypoint_args.end(),
std::back_inserter(entrypoint_argv),
[](const std::string& arg) -> const char* { return arg.c_str(); });
c_engine_properties.dart_entrypoint_argc =
static_cast<int>(entrypoint_argv.size());
c_engine_properties.dart_entrypoint_argv =
entrypoint_argv.empty() ? nullptr : entrypoint_argv.data();
engine_ = FlutterDesktopEngineCreate(&c_engine_properties);
auto core_messenger = FlutterDesktopEngineGetMessenger(engine_);
messenger_ = std::make_unique<BinaryMessengerImpl>(core_messenger);
}
FlutterEngine::~FlutterEngine() {
ShutDown();
}
bool FlutterEngine::Run() {
return Run(nullptr);
}
bool FlutterEngine::Run(const char* entry_point) {
if (!engine_) {
std::cerr << "Cannot run an engine that failed creation." << std::endl;
return false;
}
if (run_succeeded_) {
std::cerr << "Cannot run an engine more than once." << std::endl;
return false;
}
bool run_succeeded = FlutterDesktopEngineRun(engine_, entry_point);
if (!run_succeeded) {
std::cerr << "Failed to start engine." << std::endl;
}
run_succeeded_ = true;
return run_succeeded;
}
void FlutterEngine::ShutDown() {
if (engine_ && owns_engine_) {
FlutterDesktopEngineDestroy(engine_);
}
engine_ = nullptr;
}
std::chrono::nanoseconds FlutterEngine::ProcessMessages() {
return std::chrono::nanoseconds(FlutterDesktopEngineProcessMessages(engine_));
}
void FlutterEngine::ReloadSystemFonts() {
FlutterDesktopEngineReloadSystemFonts(engine_);
}
FlutterDesktopPluginRegistrarRef FlutterEngine::GetRegistrarForPlugin(
const std::string& plugin_name) {
if (!engine_) {
std::cerr << "Cannot get plugin registrar on an engine that isn't running; "
"call Run first."
<< std::endl;
return nullptr;
}
return FlutterDesktopEngineGetPluginRegistrar(engine_, plugin_name.c_str());
}
void FlutterEngine::SetNextFrameCallback(std::function<void()> callback) {
next_frame_callback_ = std::move(callback);
FlutterDesktopEngineSetNextFrameCallback(
engine_,
[](void* user_data) {
FlutterEngine* self = static_cast<FlutterEngine*>(user_data);
self->next_frame_callback_();
self->next_frame_callback_ = nullptr;
},
this);
}
std::optional<LRESULT> FlutterEngine::ProcessExternalWindowMessage(
HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
LRESULT result;
if (FlutterDesktopEngineProcessExternalWindowMessage(
engine_, hwnd, message, wparam, lparam, &result)) {
return result;
}
return std::nullopt;
}
FlutterDesktopEngineRef FlutterEngine::RelinquishEngine() {
owns_engine_ = false;
return engine_;
}
} // namespace flutter
@@ -0,0 +1,53 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/flutter/flutter_view_controller.h"
#include <algorithm>
#include <iostream>
namespace flutter {
FlutterViewController::FlutterViewController(int width,
int height,
const DartProject& project) {
engine_ = std::make_shared<FlutterEngine>(project);
controller_ = FlutterDesktopViewControllerCreate(width, height,
engine_->RelinquishEngine());
if (!controller_) {
std::cerr << "Failed to create view controller." << std::endl;
return;
}
view_ = std::make_unique<FlutterView>(
FlutterDesktopViewControllerGetView(controller_));
}
FlutterViewController::~FlutterViewController() {
if (controller_) {
FlutterDesktopViewControllerDestroy(controller_);
}
}
FlutterViewId FlutterViewController::view_id() const {
auto view_id = FlutterDesktopViewControllerGetViewId(controller_);
return static_cast<FlutterViewId>(view_id);
}
void FlutterViewController::ForceRedraw() {
FlutterDesktopViewControllerForceRedraw(controller_);
}
std::optional<LRESULT> FlutterViewController::HandleTopLevelWindowProc(
HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
LRESULT result;
bool handled = FlutterDesktopViewControllerHandleTopLevelWindowProc(
controller_, hwnd, message, wparam, lparam, &result);
return handled ? result : std::optional<LRESULT>(std::nullopt);
}
} // namespace flutter
@@ -0,0 +1,149 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BASIC_MESSAGE_CHANNEL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BASIC_MESSAGE_CHANNEL_H_
#include <iostream>
#include <string>
#include <utility>
#include "binary_messenger.h"
#include "message_codec.h"
namespace flutter {
namespace internal {
// Internal helper functions used by BasicMessageChannel and MethodChannel.
// Adjusts the number of messages that will get buffered when sending messages
// to channels that aren't fully set up yet. For example, the engine isn't
// running yet or the channel's message handler isn't set up on the Dart side
// yet.
void ResizeChannel(BinaryMessenger* messenger, std::string name, int new_size);
// Defines whether the channel should show warning messages when discarding
// messages due to overflow.
//
// When |warns| is false, the channel is expected to overflow and warning
// messages will not be shown.
void SetChannelWarnsOnOverflow(BinaryMessenger* messenger,
std::string name,
bool warns);
} // namespace internal
class EncodableValue;
// A message reply callback.
//
// Used for submitting a reply back to a Flutter message sender.
template <typename T>
using MessageReply = std::function<void(const T& reply)>;
// A handler for receiving a message from the Flutter engine.
//
// Implementations must asynchronously call reply exactly once with the reply
// to the message.
template <typename T>
using MessageHandler =
std::function<void(const T& message, const MessageReply<T>& reply)>;
// A channel for communicating with the Flutter engine by sending asynchronous
// messages.
template <typename T = EncodableValue>
class BasicMessageChannel {
public:
// Creates an instance that sends and receives method calls on the channel
// named |name|, encoded with |codec| and dispatched via |messenger|.
BasicMessageChannel(BinaryMessenger* messenger,
const std::string& name,
const MessageCodec<T>* codec)
: messenger_(messenger), name_(name), codec_(codec) {}
~BasicMessageChannel() = default;
// Prevent copying.
BasicMessageChannel(BasicMessageChannel const&) = delete;
BasicMessageChannel& operator=(BasicMessageChannel const&) = delete;
// Sends a message to the Flutter engine on this channel.
void Send(const T& message) {
std::unique_ptr<std::vector<uint8_t>> raw_message =
codec_->EncodeMessage(message);
messenger_->Send(name_, raw_message->data(), raw_message->size());
}
// Sends a message to the Flutter engine on this channel expecting a reply.
void Send(const T& message, BinaryReply reply) {
std::unique_ptr<std::vector<uint8_t>> raw_message =
codec_->EncodeMessage(message);
messenger_->Send(name_, raw_message->data(), raw_message->size(),
std::move(reply));
}
// Registers a handler that should be called any time a message is
// received on this channel. A null handler will remove any previous handler.
//
// Note that the BasicMessageChannel does not own the handler, and will not
// unregister it on destruction, so the caller is responsible for
// unregistering explicitly if it should no longer be called.
void SetMessageHandler(const MessageHandler<T>& handler) const {
if (!handler) {
messenger_->SetMessageHandler(name_, nullptr);
return;
}
const auto* codec = codec_;
std::string channel_name = name_;
BinaryMessageHandler binary_handler = [handler, codec, channel_name](
const uint8_t* binary_message,
const size_t binary_message_size,
const BinaryReply& binary_reply) {
// Use this channel's codec to decode the message and build a reply
// handler.
std::unique_ptr<T> message =
codec->DecodeMessage(binary_message, binary_message_size);
if (!message) {
std::cerr << "Unable to decode message on channel " << channel_name
<< std::endl;
binary_reply(nullptr, 0);
return;
}
MessageReply<T> unencoded_reply = [binary_reply,
codec](const T& unencoded_response) {
auto binary_response = codec->EncodeMessage(unencoded_response);
binary_reply(binary_response->data(), binary_response->size());
};
handler(*message, std::move(unencoded_reply));
};
messenger_->SetMessageHandler(name_, std::move(binary_handler));
}
// Adjusts the number of messages that will get buffered when sending messages
// to channels that aren't fully set up yet. For example, the engine isn't
// running yet or the channel's message handler isn't set up on the Dart side
// yet.
void Resize(int new_size) {
internal::ResizeChannel(messenger_, name_, new_size);
}
// Defines whether the channel should show warning messages when discarding
// messages due to overflow.
//
// When |warns| is false, the channel is expected to overflow and warning
// messages will not be shown.
void SetWarnsOnOverflow(bool warns) {
internal::SetChannelWarnsOnOverflow(messenger_, name_, warns);
}
private:
BinaryMessenger* messenger_;
std::string name_;
const MessageCodec<T>* codec_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BASIC_MESSAGE_CHANNEL_H_
@@ -0,0 +1,52 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BINARY_MESSENGER_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BINARY_MESSENGER_H_
#include <functional>
#include <string>
namespace flutter {
// A binary message reply callback.
//
// Used for submitting a binary reply back to a Flutter message sender.
typedef std::function<void(const uint8_t* reply, size_t reply_size)>
BinaryReply;
// A message handler callback.
//
// Used for receiving messages from Flutter and providing an asynchronous reply.
typedef std::function<
void(const uint8_t* message, size_t message_size, BinaryReply reply)>
BinaryMessageHandler;
// A protocol for a class that handles communication of binary data on named
// channels to and from the Flutter engine.
class BinaryMessenger {
public:
virtual ~BinaryMessenger() = default;
// Sends a binary message to the Flutter engine on the specified channel.
//
// If |reply| is provided, it will be called back with the response from the
// engine.
virtual void Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply = nullptr) const = 0;
// Registers a message handler for incoming binary messages from the Flutter
// side on the specified channel.
//
// Replaces any existing handler. Provide a null handler to unregister the
// existing handler.
virtual void SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BINARY_MESSENGER_H_
@@ -0,0 +1,85 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BYTE_STREAMS_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BYTE_STREAMS_H_
// Interfaces for interacting with a stream of bytes, for use in codecs.
namespace flutter {
// An interface for a class that reads from a byte stream.
class ByteStreamReader {
public:
explicit ByteStreamReader() = default;
virtual ~ByteStreamReader() = default;
// Reads and returns the next byte from the stream.
virtual uint8_t ReadByte() = 0;
// Reads the next |length| bytes from the stream into |buffer|. The caller
// is responsible for ensuring that |buffer| is large enough.
virtual void ReadBytes(uint8_t* buffer, size_t length) = 0;
// Advances the read cursor to the next multiple of |alignment| relative to
// the start of the stream, unless it is already aligned.
virtual void ReadAlignment(uint8_t alignment) = 0;
// Reads and returns the next 32-bit integer from the stream.
int32_t ReadInt32() {
int32_t value = 0;
ReadBytes(reinterpret_cast<uint8_t*>(&value), 4);
return value;
}
// Reads and returns the next 64-bit integer from the stream.
int64_t ReadInt64() {
int64_t value = 0;
ReadBytes(reinterpret_cast<uint8_t*>(&value), 8);
return value;
}
// Reads and returns the next 64-bit floating point number from the stream.
double ReadDouble() {
double value = 0;
ReadBytes(reinterpret_cast<uint8_t*>(&value), 8);
return value;
}
};
// An interface for a class that writes to a byte stream.
class ByteStreamWriter {
public:
explicit ByteStreamWriter() = default;
virtual ~ByteStreamWriter() = default;
// Writes |byte| to the stream.
virtual void WriteByte(uint8_t byte) = 0;
// Writes the next |length| bytes from |bytes| to the stream
virtual void WriteBytes(const uint8_t* bytes, size_t length) = 0;
// Writes 0s until the next multiple of |alignment| relative to the start
// of the stream, unless the write positition is already aligned.
virtual void WriteAlignment(uint8_t alignment) = 0;
// Writes the given 32-bit int to the stream.
void WriteInt32(int32_t value) {
WriteBytes(reinterpret_cast<const uint8_t*>(&value), 4);
}
// Writes the given 64-bit int to the stream.
void WriteInt64(int64_t value) {
WriteBytes(reinterpret_cast<const uint8_t*>(&value), 8);
}
// Writes the given 36-bit double to the stream.
void WriteDouble(double value) {
WriteBytes(reinterpret_cast<const uint8_t*>(&value), 8);
}
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BYTE_STREAMS_H_
@@ -0,0 +1,145 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_
#include <string>
#include <vector>
namespace flutter {
// Configures how the Flutter engine selects a GPU.
enum class GpuPreference {
// No preference.
NoPreference,
// Prefer energy efficiency over performance, such as an integrated GPU.
// This falls back to a high performance GPU if no low power GPU is
// available.
LowPowerPreference,
};
// Configures the thread policy for running the UI isolate.
enum class UIThreadPolicy {
// Default value. Currently will run the UI isolate on separate thread,
// later will be changed to running the UI isolate on platform thread.
Default,
// Run the UI isolate on platform thread.
RunOnPlatformThread,
// Run the UI isolate on a separate thread.
RunOnSeparateThread,
};
// A set of Flutter and Dart assets used to initialize a Flutter engine.
class DartProject {
public:
// Creates a DartProject from a series of absolute paths.
// The three paths are:
// - assets_path: Path to the assets directory as built by the Flutter tool.
// - icu_data_path: Path to the icudtl.dat file.
// - aot_library_path: Path to the AOT snapshot file.
//
// The paths may either be absolute or relative to the directory containing
// the running executable.
explicit DartProject(const std::wstring& assets_path,
const std::wstring& icu_data_path,
const std::wstring& aot_library_path) {
assets_path_ = assets_path;
icu_data_path_ = icu_data_path;
aot_library_path_ = aot_library_path;
}
// Creates a DartProject from a directory path. The directory should contain
// the following top-level items:
// - icudtl.dat (provided as a resource by the Flutter tool)
// - flutter_assets (as built by the Flutter tool)
// - app.so, for an AOT build (as built by the Flutter tool)
//
// The path can either be absolute, or relative to the directory containing
// the running executable.
explicit DartProject(const std::wstring& path) {
assets_path_ = path + L"\\flutter_assets";
icu_data_path_ = path + L"\\icudtl.dat";
aot_library_path_ = path + L"\\app.so";
}
~DartProject() = default;
// Sets the Dart entrypoint to the specified value.
//
// If not set, the default entrypoint (main) is used. Custom Dart entrypoints
// must be decorated with `@pragma('vm:entry-point')`.
void set_dart_entrypoint(const std::string& entrypoint) {
if (entrypoint.empty()) {
return;
}
dart_entrypoint_ = entrypoint;
}
// Returns the Dart entrypoint.
const std::string& dart_entrypoint() const { return dart_entrypoint_; }
// Sets the command line arguments that should be passed to the Dart
// entrypoint.
void set_dart_entrypoint_arguments(std::vector<std::string> arguments) {
dart_entrypoint_arguments_ = std::move(arguments);
}
// Returns any command line arguments that should be passed to the Dart
// entrypoint.
const std::vector<std::string>& dart_entrypoint_arguments() const {
return dart_entrypoint_arguments_;
}
// Sets the GPU usage preference for flutter engine.
void set_gpu_preference(GpuPreference gpu_preference) {
gpu_preference_ = gpu_preference;
}
// Returns the project's GPU preference.
// Defaults to NoPreference.
GpuPreference gpu_preference() const { return gpu_preference_; }
// Sets the thread policy for UI isolate.
void set_ui_thread_policy(UIThreadPolicy policy) {
ui_thread_policy_ = policy;
}
// Returns the policy for UI isolate.
// Defaults to UIThreadPolicy::Default.
UIThreadPolicy ui_thread_policy() const { return ui_thread_policy_; }
private:
// Accessors for internals are private, so that they can be changed if more
// flexible options for project structures are needed later without it
// being a breaking change. Provide access to internal classes that need
// them.
friend class FlutterEngine;
friend class FlutterViewController;
friend class DartProjectTest;
const std::wstring& assets_path() const { return assets_path_; }
const std::wstring& icu_data_path() const { return icu_data_path_; }
const std::wstring& aot_library_path() const { return aot_library_path_; }
// The path to the assets directory.
std::wstring assets_path_;
// The path to the ICU data.
std::wstring icu_data_path_;
// The path to the AOT library. This will always return a path, but non-AOT
// builds will not be expected to actually have a library at that path.
std::wstring aot_library_path_;
// The Dart entrypoint to launch.
std::string dart_entrypoint_;
// The list of arguments to pass through to the Dart entrypoint.
std::vector<std::string> dart_entrypoint_arguments_;
// The preference for GPU to be used by flutter engine.
GpuPreference gpu_preference_ = GpuPreference::NoPreference;
// Thread policy for UI isolate.
UIThreadPolicy ui_thread_policy_ = UIThreadPolicy::Default;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_
@@ -0,0 +1,274 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
#include <any>
#include <cassert>
#include <cstdint>
#include <map>
#include <string>
#include <utility>
#include <variant>
#include <vector>
// Unless overridden, attempt to detect the RTTI state from the compiler.
#ifndef FLUTTER_ENABLE_RTTI
#if defined(_MSC_VER)
#ifdef _CPPRTTI
#define FLUTTER_ENABLE_RTTI 1
#endif
#elif defined(__clang__)
#if __has_feature(cxx_rtti)
#define FLUTTER_ENABLE_RTTI 1
#endif
#elif defined(__GNUC__)
#ifdef __GXX_RTTI
#define FLUTTER_ENABLE_RTTI 1
#endif
#endif
#endif // #ifndef FLUTTER_ENABLE_RTTI
namespace flutter {
static_assert(sizeof(double) == 8, "EncodableValue requires a 64-bit double");
// A container for arbitrary types in EncodableValue.
//
// This is used in conjunction with StandardCodecExtension to allow using other
// types with a StandardMethodCodec/StandardMessageCodec. It is implicitly
// convertible to EncodableValue, so constructing an EncodableValue from a
// custom type can generally be written as:
// CustomEncodableValue(MyType(...))
// rather than:
// EncodableValue(CustomEncodableValue(MyType(...)))
//
// For extracting received custom types, it is implicitly convertible to
// std::any. For example:
// const MyType& my_type_value =
// std::any_cast<MyType>(std::get<CustomEncodableValue>(value));
//
// If RTTI is enabled, different extension types can be checked with type():
// if (custom_value->type() == typeid(SomeData)) { ... }
// Clients that wish to disable RTTI would need to decide on another approach
// for distinguishing types (e.g., in StandardCodecExtension::WriteValueOfType)
// if multiple custom types are needed. For instance, wrapping all of the
// extension types in an EncodableValue-style variant, and only ever storing
// that variant in CustomEncodableValue.
class CustomEncodableValue {
public:
explicit CustomEncodableValue(const std::any& value) : value_(value) {}
~CustomEncodableValue() = default;
// Allow implicit conversion to std::any to allow direct use of any_cast.
// NOLINTNEXTLINE(google-explicit-constructor)
operator std::any&() { return value_; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator const std::any&() const { return value_; }
#if defined(FLUTTER_ENABLE_RTTI) && FLUTTER_ENABLE_RTTI
// Passthrough to std::any's type().
const std::type_info& type() const noexcept { return value_.type(); }
#endif
// This operator exists only to provide a stable ordering for use as a
// std::map key, to satisfy the compiler requirements for EncodableValue.
// It does not attempt to provide useful ordering semantics, and using a
// custom value as a map key is not recommended.
bool operator<(const CustomEncodableValue& other) const {
return this < &other;
}
bool operator==(const CustomEncodableValue& other) const {
return this == &other;
}
private:
std::any value_;
};
class EncodableValue;
// Convenience type aliases.
using EncodableList = std::vector<EncodableValue>;
using EncodableMap = std::map<EncodableValue, EncodableValue>;
namespace internal {
// The base class for EncodableValue. Do not use this directly; it exists only
// for EncodableValue to inherit from.
//
// Do not change the order or indexes of the items here; see the comment on
// EncodableValue
using EncodableValueVariant = std::variant<std::monostate,
bool,
int32_t,
int64_t,
double,
std::string,
std::vector<uint8_t>,
std::vector<int32_t>,
std::vector<int64_t>,
std::vector<double>,
EncodableList,
EncodableMap,
CustomEncodableValue,
std::vector<float>>;
} // namespace internal
// An object that can contain any value or collection type supported by
// Flutter's standard method codec.
//
// For details, see:
// https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html
//
// As an example, the following Dart structure:
// {
// 'flag': true,
// 'name': 'Thing',
// 'values': [1, 2.0, 4],
// }
// would correspond to:
// EncodableValue(EncodableMap{
// {EncodableValue("flag"), EncodableValue(true)},
// {EncodableValue("name"), EncodableValue("Thing")},
// {EncodableValue("values"), EncodableValue(EncodableList{
// EncodableValue(1),
// EncodableValue(2.0),
// EncodableValue(4),
// })},
// })
//
// The primary API surface for this object is std::variant. For instance,
// getting a string value from an EncodableValue, with type checking:
// if (std::holds_alternative<std::string>(value)) {
// std::string some_string = std::get<std::string>(value);
// }
//
// The order/indexes of the variant types is part of the API surface, and is
// guaranteed not to change.
//
// The variant types are mapped with Dart types in following ways:
// std::monostate -> null
// bool -> bool
// int32_t -> int
// int64_t -> int
// double -> double
// std::string -> String
// std::vector<uint8_t> -> Uint8List
// std::vector<int32_t> -> Int32List
// std::vector<int64_t> -> Int64List
// std::vector<float> -> Float32List
// std::vector<double> -> Float64List
// EncodableList -> List
// EncodableMap -> Map
class EncodableValue : public internal::EncodableValueVariant {
public:
// Rely on std::variant for most of the constructors/operators.
using super = internal::EncodableValueVariant;
using super::super;
using super::operator=;
explicit EncodableValue() = default;
// Avoid the C++17 pitfall of conversion from char* to bool. Should not be
// needed for C++20.
explicit EncodableValue(const char* string) : super(std::string(string)) {}
EncodableValue& operator=(const char* other) {
*this = std::string(other);
return *this;
}
// Allow implicit conversion from CustomEncodableValue; the only reason to
// make a CustomEncodableValue (which can only be constructed explicitly) is
// to use it with EncodableValue, so the risk of unintended conversions is
// minimal, and it avoids the need for the verbose:
// EncodableValue(CustomEncodableValue(...)).
// NOLINTNEXTLINE(google-explicit-constructor)
EncodableValue(const CustomEncodableValue& v) : super(v) {}
// Override the conversion constructors from std::variant to make them
// explicit, to avoid implicit conversion.
//
// While implicit conversion can be convenient in some cases, it can have very
// surprising effects. E.g., calling a function that takes an EncodableValue
// but accidentally passing an EncodableValue* would, instead of failing to
// compile, go through a pointer->bool->EncodableValue(bool) chain and
// silently call the function with a temp-constructed EncodableValue(true).
template <class T>
constexpr explicit EncodableValue(T&& t) noexcept : super(t) {}
// Returns true if the value is null. Convenience wrapper since unlike the
// other types, std::monostate uses aren't self-documenting.
bool IsNull() const { return std::holds_alternative<std::monostate>(*this); }
// Convenience method to simplify handling objects received from Flutter
// where the values may be larger than 32-bit, since they have the same type
// on the Dart side, but will be either 32-bit or 64-bit here depending on
// the value.
//
// Calling this method if the value doesn't contain either an int32_t or an
// int64_t will throw an exception.
int64_t LongValue() const {
if (std::holds_alternative<int32_t>(*this)) {
return std::get<int32_t>(*this);
}
return std::get<int64_t>(*this);
}
// The C++ Standard Library implementations can get into issues with recursive
// constraint satisfaction when (among other things) objects of this type (which
// is an `std::variant` subclass) are put into containers like `std::vector`.
//
// A definition of `operator<` is provided to break that recursion. However, in
// C++20 with the latest compilers (Clang compilers newer than 20 and the latest
// GCC variants, see https://gcc.godbolt.org/z/KM6n6qane) requiring that that
// the `std::three_way_comparable` constraint be satisfied requires the
// provision of `operator<=>` to do the same thing.
//
// The code below makes this translation unit be safe to include from both C++17
// and C++20 translation units while also using the newest compilers.
//
// The correctness of the compiler's gripes with this code and the subsequent
// need for these workarounds is not fully understood or explored. If you run
// into issues with this code again, the following breadcrumbs may prove
// useful. If you cannot access some or all of these links, the compiler
// explorer link above should serve a reduced test case to base an investigation
// off of.
//
// * b/423885648#comment8
// * b/423885648#comment19
// * cl/542631351
// * cl/542541552
// * https://github.com/flutter/engine/pull/43091
//
#if __cplusplus >= 202002L
friend std::partial_ordering operator<=>(const EncodableValue& lhs,
const EncodableValue& rhs) {
auto& lv = static_cast<const super&>(lhs);
auto& rv = static_cast<const super&>(rhs);
if (lv < rv) {
return std::partial_ordering::less;
}
if (rv < lv) {
return std::partial_ordering::greater;
}
if (lv == rv) {
return std::partial_ordering::equivalent;
}
return std::partial_ordering::unordered;
}
#else // __cplusplus >= 202002L
friend bool operator<(const EncodableValue& lhs, const EncodableValue& rhs) {
return static_cast<const super&>(lhs) < static_cast<const super&>(rhs);
}
#endif // __cplusplus >= 202002L
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
@@ -0,0 +1,86 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENGINE_METHOD_RESULT_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENGINE_METHOD_RESULT_H_
#include <memory>
#include <string>
#include <vector>
#include "binary_messenger.h"
#include "method_codec.h"
#include "method_result.h"
namespace flutter {
namespace internal {
// Manages the one-time sending of response data. This is an internal helper
// class for EngineMethodResult, separated out since the implementation doesn't
// vary based on the template type.
class ReplyManager {
public:
explicit ReplyManager(BinaryReply reply_handler_);
~ReplyManager();
// Prevent copying.
ReplyManager(ReplyManager const&) = delete;
ReplyManager& operator=(ReplyManager const&) = delete;
// Sends the given response data (which must either be nullptr, which
// indicates an unhandled method, or a response serialized with |codec_|) to
// the engine.
void SendResponseData(const std::vector<uint8_t>* data);
private:
BinaryReply reply_handler_;
};
} // namespace internal
// Implemention of MethodResult that sends a response to the Flutter engine
// exactly once, encoded using a given codec.
template <typename T>
class EngineMethodResult : public MethodResult<T> {
public:
// Creates a result object that will send results to |reply_handler|, encoded
// using |codec|. The |codec| pointer must remain valid for as long as this
// object exists.
EngineMethodResult(BinaryReply reply_handler, const MethodCodec<T>* codec)
: reply_manager_(
std::make_unique<internal::ReplyManager>(std::move(reply_handler))),
codec_(codec) {}
~EngineMethodResult() = default;
protected:
// |flutter::MethodResult|
void SuccessInternal(const T* result) override {
std::unique_ptr<std::vector<uint8_t>> data =
codec_->EncodeSuccessEnvelope(result);
reply_manager_->SendResponseData(data.get());
}
// |flutter::MethodResult|
void ErrorInternal(const std::string& error_code,
const std::string& error_message,
const T* error_details) override {
std::unique_ptr<std::vector<uint8_t>> data =
codec_->EncodeErrorEnvelope(error_code, error_message, error_details);
reply_manager_->SendResponseData(data.get());
}
// |flutter::MethodResult|
void NotImplementedInternal() override {
reply_manager_->SendResponseData(nullptr);
}
private:
std::unique_ptr<internal::ReplyManager> reply_manager_;
const MethodCodec<T>* codec_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENGINE_METHOD_RESULT_H_
@@ -0,0 +1,181 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_
#include <iostream>
#include <memory>
#include <string>
#include "binary_messenger.h"
#include "engine_method_result.h"
#include "event_sink.h"
#include "event_stream_handler.h"
namespace flutter {
class EncodableValue;
// A named channel for communicating with the Flutter application using
// asynchronous event streams. Incoming requests for event stream setup are
// decoded from binary on receipt, and C++ responses and events are encoded into
// binary before being transmitted back to Flutter. The MethodCodec used must be
// compatible with the one used by the Flutter application. This can be achieved
// by creating an EventChannel
// ("https://api.flutter.dev/flutter/services/EventChannel-class.html")
// counterpart of this channel on the Dart side.
// The C++ type of stream configuration arguments, events, and error details are
// templated, but only values supported by the specified MethodCodec can be
// used.
template <typename T = EncodableValue>
class EventChannel {
public:
// Creates an instance that sends and receives event handler on the channel
// named |name|, encoded with |codec| and dispatched via |messenger|.
EventChannel(BinaryMessenger* messenger,
const std::string& name,
const MethodCodec<T>* codec)
: messenger_(messenger), name_(name), codec_(codec) {}
~EventChannel() = default;
// Prevent copying.
EventChannel(EventChannel const&) = delete;
EventChannel& operator=(EventChannel const&) = delete;
// Registers a stream handler on this channel.
// If no handler has been registered, any incoming stream setup requests will
// be handled silently by providing an empty stream.
//
// Note that the EventChannel does not own the handler and will not
// unregister it on destruction. The caller is responsible for unregistering
// the handler if it should no longer be called.
void SetStreamHandler(std::unique_ptr<StreamHandler<T>> handler) {
if (!handler) {
messenger_->SetMessageHandler(name_, nullptr);
return;
}
// std::function requires a copyable lambda, so convert to a shared pointer.
// This is safe since only one copy of the shared_pointer will ever be
// accessed.
std::shared_ptr<StreamHandler<T>> shared_handler(handler.release());
const MethodCodec<T>* codec = codec_;
const std::string channel_name = name_;
const BinaryMessenger* messenger = messenger_;
BinaryMessageHandler binary_handler =
[shared_handler, codec, channel_name, messenger,
// Mutable state to track the handler's listening status.
is_listening = false](const uint8_t* message,
const size_t message_size,
const BinaryReply& reply) mutable {
constexpr char kOnListenMethod[] = "listen";
constexpr char kOnCancelMethod[] = "cancel";
std::unique_ptr<MethodCall<T>> method_call =
codec->DecodeMethodCall(message, message_size);
if (!method_call) {
std::cerr
<< "Unable to construct method call from message on channel: "
<< channel_name << std::endl;
reply(nullptr, 0);
return;
}
const std::string& method = method_call->method_name();
if (method.compare(kOnListenMethod) == 0) {
if (is_listening) {
std::unique_ptr<StreamHandlerError<T>> error =
shared_handler->OnCancel(nullptr);
if (error) {
std::cerr << "Failed to cancel existing stream: "
<< (error->error_code) << ", "
<< (error->error_message) << ", "
<< (error->error_details);
}
}
is_listening = true;
std::unique_ptr<std::vector<uint8_t>> result;
auto sink = std::make_unique<EventSinkImplementation>(
messenger, channel_name, codec);
std::unique_ptr<StreamHandlerError<T>> error =
shared_handler->OnListen(method_call->arguments(),
std::move(sink));
if (error) {
result = codec->EncodeErrorEnvelope(error->error_code,
error->error_message,
error->error_details.get());
} else {
result = codec->EncodeSuccessEnvelope();
}
reply(result->data(), result->size());
} else if (method.compare(kOnCancelMethod) == 0) {
std::unique_ptr<std::vector<uint8_t>> result;
if (is_listening) {
std::unique_ptr<StreamHandlerError<T>> error =
shared_handler->OnCancel(method_call->arguments());
if (error) {
result = codec->EncodeErrorEnvelope(error->error_code,
error->error_message,
error->error_details.get());
} else {
result = codec->EncodeSuccessEnvelope();
}
is_listening = false;
} else {
result = codec->EncodeErrorEnvelope(
"error", "No active stream to cancel", nullptr);
}
reply(result->data(), result->size());
} else {
reply(nullptr, 0);
}
};
messenger_->SetMessageHandler(name_, std::move(binary_handler));
}
private:
class EventSinkImplementation : public EventSink<T> {
public:
EventSinkImplementation(const BinaryMessenger* messenger,
const std::string& name,
const MethodCodec<T>* codec)
: messenger_(messenger), name_(name), codec_(codec) {}
~EventSinkImplementation() = default;
// Prevent copying.
EventSinkImplementation(EventSinkImplementation const&) = delete;
EventSinkImplementation& operator=(EventSinkImplementation const&) = delete;
private:
const BinaryMessenger* messenger_;
const std::string name_;
const MethodCodec<T>* codec_;
protected:
void SuccessInternal(const T* event = nullptr) override {
auto result = codec_->EncodeSuccessEnvelope(event);
messenger_->Send(name_, result->data(), result->size());
}
void ErrorInternal(const std::string& error_code,
const std::string& error_message,
const T* error_details) override {
auto result =
codec_->EncodeErrorEnvelope(error_code, error_message, error_details);
messenger_->Send(name_, result->data(), result->size());
}
void EndOfStreamInternal() override { messenger_->Send(name_, nullptr, 0); }
};
BinaryMessenger* messenger_;
const std::string name_;
const MethodCodec<T>* codec_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_
@@ -0,0 +1,62 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_SINK_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_SINK_H_
namespace flutter {
class EncodableValue;
// Event callback. Events to be sent to Flutter application
// act as clients of this interface for sending events.
template <typename T = EncodableValue>
class EventSink {
public:
EventSink() = default;
virtual ~EventSink() = default;
// Prevent copying.
EventSink(EventSink const&) = delete;
EventSink& operator=(EventSink const&) = delete;
// Consumes a successful event
void Success(const T& event) { SuccessInternal(&event); }
// Consumes a successful event.
void Success() { SuccessInternal(nullptr); }
// Consumes an error event.
void Error(const std::string& error_code,
const std::string& error_message,
const T& error_details) {
ErrorInternal(error_code, error_message, &error_details);
}
// Consumes an error event.
void Error(const std::string& error_code,
const std::string& error_message = "") {
ErrorInternal(error_code, error_message, nullptr);
}
// Consumes end of stream. Ensuing calls to Success() or
// Error(), if any, are ignored.
void EndOfStream() { EndOfStreamInternal(); }
protected:
// Implementation of the public interface, to be provided by subclasses.
virtual void SuccessInternal(const T* event = nullptr) = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual void ErrorInternal(const std::string& error_code,
const std::string& error_message,
const T* error_details) = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual void EndOfStreamInternal() = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_SINK_H_
@@ -0,0 +1,77 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_H_
#include <memory>
#include <string>
#include "event_sink.h"
namespace flutter {
class EncodableValue;
template <typename T = EncodableValue>
struct StreamHandlerError {
const std::string error_code;
const std::string error_message;
const std::unique_ptr<T> error_details;
StreamHandlerError(const std::string& error_code,
const std::string& error_message,
std::unique_ptr<T>&& error_details)
: error_code(error_code),
error_message(error_message),
error_details(std::move(error_details)) {}
};
// Handler for stream setup and teardown requests.
// Implementations must be prepared to accept sequences of alternating calls to
// OnListen() and OnCancel(). Implementations should ideally consume no
// resources when the last such call is not OnListen(). In typical situations,
// this means that the implementation should register itself with
// platform-specific event sources OnListen() and deregister again OnCancel().
template <typename T = EncodableValue>
class StreamHandler {
public:
StreamHandler() = default;
virtual ~StreamHandler() = default;
// Prevent copying.
StreamHandler(StreamHandler const&) = delete;
StreamHandler& operator=(StreamHandler const&) = delete;
// Handles a request to set up an event stream. Returns nullptr on success,
// or an error on failure.
// |arguments| is stream configuration arguments and
// |events| is an EventSink for emitting events to the Flutter receiver.
std::unique_ptr<StreamHandlerError<T>> OnListen(
const T* arguments,
std::unique_ptr<EventSink<T>>&& events) {
return OnListenInternal(arguments, std::move(events));
}
// Handles a request to tear down the most recently created event stream.
// Returns nullptr on success, or an error on failure.
// |arguments| is stream configuration arguments.
std::unique_ptr<StreamHandlerError<T>> OnCancel(const T* arguments) {
return OnCancelInternal(arguments);
}
protected:
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<StreamHandlerError<T>> OnListenInternal(
const T* arguments,
std::unique_ptr<EventSink<T>>&& events) = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<StreamHandlerError<T>> OnCancelInternal(
const T* arguments) = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_H_
@@ -0,0 +1,78 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_FUNCTIONS_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_FUNCTIONS_H_
#include <memory>
#include "event_sink.h"
#include "event_stream_handler.h"
namespace flutter {
class EncodableValue;
// Handler types for each of the StreamHandler setup and teardown
// requests.
template <typename T>
using StreamHandlerListen =
std::function<std::unique_ptr<StreamHandlerError<T>>(
const T* arguments,
std::unique_ptr<EventSink<T>>&& events)>;
template <typename T>
using StreamHandlerCancel =
std::function<std::unique_ptr<StreamHandlerError<T>>(const T* arguments)>;
// An implementation of StreamHandler that pass calls through to
// provided function objects.
template <typename T = EncodableValue>
class StreamHandlerFunctions : public StreamHandler<T> {
public:
// Creates a handler object that calls the provided functions
// for the corresponding StreamHandler outcomes.
StreamHandlerFunctions(StreamHandlerListen<T> on_listen,
StreamHandlerCancel<T> on_cancel)
: on_listen_(std::move(on_listen)), on_cancel_(std::move(on_cancel)) {}
virtual ~StreamHandlerFunctions() = default;
// Prevent copying.
StreamHandlerFunctions(StreamHandlerFunctions const&) = delete;
StreamHandlerFunctions& operator=(StreamHandlerFunctions const&) = delete;
protected:
// |flutter::StreamHandler|
std::unique_ptr<StreamHandlerError<T>> OnListenInternal(
const T* arguments,
std::unique_ptr<EventSink<T>>&& events) override {
if (on_listen_) {
return on_listen_(arguments, std::move(events));
}
auto error = std::make_unique<StreamHandlerError<T>>(
"error", "No OnListen handler set", nullptr);
return std::move(error);
}
// |flutter::StreamHandler|
std::unique_ptr<StreamHandlerError<T>> OnCancelInternal(
const T* arguments) override {
if (on_cancel_) {
return on_cancel_(arguments);
}
auto error = std::make_unique<StreamHandlerError<T>>(
"error", "No OnCancel handler set", nullptr);
return std::move(error);
}
StreamHandlerListen<T> on_listen_;
StreamHandlerCancel<T> on_cancel_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_FUNCTIONS_H_
@@ -0,0 +1,128 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_ENGINE_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_ENGINE_H_
#include <flutter_windows.h>
#include <chrono>
#include <memory>
#include <optional>
#include <string>
#include "binary_messenger.h"
#include "dart_project.h"
#include "plugin_registrar.h"
#include "plugin_registry.h"
namespace flutter {
// An instance of a Flutter engine.
//
// In the future, this will be the API surface used for all interactions with
// the engine, rather than having them duplicated on FlutterViewController.
// For now it is only used in the rare case where you need a headless Flutter
// engine.
class FlutterEngine : public PluginRegistry {
public:
// Creates a new engine for running the given project.
explicit FlutterEngine(const DartProject& project);
virtual ~FlutterEngine();
// Prevent copying.
FlutterEngine(FlutterEngine const&) = delete;
FlutterEngine& operator=(FlutterEngine const&) = delete;
// Starts running the engine at the entrypoint function specified in the
// DartProject used to configure the engine, or main() by default.
bool Run();
// Starts running the engine, with an optional entry point.
//
// If provided, entry_point must be the name of a top-level function from the
// same Dart library that contains the app's main() function, and must be
// decorated with `@pragma(vm:entry-point)` to ensure the method is not
// tree-shaken by the Dart compiler. If not provided, defaults to main().
bool Run(const char* entry_point);
// Terminates the running engine.
void ShutDown();
// Processes any pending events in the Flutter engine, and returns the
// nanosecond delay until the next scheduled event (or max, if none).
//
// This should be called on every run of the application-level runloop, and
// a wait for native events in the runloop should never be longer than the
// last return value from this function.
std::chrono::nanoseconds ProcessMessages();
// Tells the engine that the system font list has changed. Should be called
// by clients when OS-level font changes happen (e.g., WM_FONTCHANGE in a
// Win32 application).
void ReloadSystemFonts();
// Tells the engine that the platform brightness value has changed. Should be
// called by clients when OS-level theme changes happen (e.g.,
// WM_DWMCOLORIZATIONCOLORCHANGED in a Win32 application).
void ReloadPlatformBrightness();
// flutter::PluginRegistry:
FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin(
const std::string& plugin_name) override;
// Returns the messenger to use for creating channels to communicate with the
// Flutter engine.
//
// This pointer will remain valid for the lifetime of this instance.
BinaryMessenger* messenger() { return messenger_.get(); }
// Schedule a callback to be called after the next frame is drawn.
//
// This must be called from the platform thread. The callback is executed only
// once on the platform thread.
void SetNextFrameCallback(std::function<void()> callback);
// Called to pass an external window message to the engine for lifecycle
// state updates. Non-Flutter windows must call this method in their WndProc
// in order to be included in the logic for application lifecycle state
// updates. Returns a result if the message should be consumed.
std::optional<LRESULT> ProcessExternalWindowMessage(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam);
private:
// For access to the engine handle.
friend class FlutterViewController;
// Gives up ownership of |engine_|, but keeps a weak reference to it.
//
// This is intended to be used by FlutterViewController, since the underlying
// C API for view controllers takes over engine ownership.
FlutterDesktopEngineRef RelinquishEngine();
// Handle for interacting with the C API's engine reference.
FlutterDesktopEngineRef engine_ = nullptr;
// Messenger for communicating with the engine.
std::unique_ptr<BinaryMessenger> messenger_;
// Whether or not this wrapper owns |engine_|.
bool owns_engine_ = true;
// Whether |Run| has been called successfully.
//
// This is used to improve error messages. This can be false while the engine
// is running if the engine was started by creating a view.
bool run_succeeded_ = false;
// The callback to execute once the next frame is drawn.
std::function<void()> next_frame_callback_ = nullptr;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_ENGINE_H_
@@ -0,0 +1,42 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_H_
#include <flutter_windows.h>
namespace flutter {
// The unique identifier for a view.
typedef int64_t FlutterViewId;
// A view displaying Flutter content.
class FlutterView {
public:
explicit FlutterView(FlutterDesktopViewRef view) : view_(view) {}
// Destroys this reference to the view. The underlying view is not destroyed.
virtual ~FlutterView() = default;
// Prevent copying.
FlutterView(FlutterView const&) = delete;
FlutterView& operator=(FlutterView const&) = delete;
// Returns the backing HWND for the view.
HWND GetNativeWindow() { return FlutterDesktopViewGetHWND(view_); }
// Returns the DXGI adapter used for rendering or nullptr in case of error.
IDXGIAdapter* GetGraphicsAdapter() {
return FlutterDesktopViewGetGraphicsAdapter(view_);
}
private:
// Handle for interacting with the C API's view.
FlutterDesktopViewRef view_ = nullptr;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_H_
@@ -0,0 +1,76 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_
#include <flutter_windows.h>
#include <windows.h>
#include <memory>
#include <optional>
#include "dart_project.h"
#include "flutter_engine.h"
#include "flutter_view.h"
namespace flutter {
// A controller for a view displaying Flutter content.
//
// This is the primary wrapper class for the desktop C API.
// If you use this class, you should not call any of the setup or teardown
// methods in the C API directly, as this class will do that internally.
class FlutterViewController {
public:
// Creates a FlutterView that can be parented into a Windows View hierarchy
// either using HWNDs.
//
// This also creates a new FlutterEngine.
//
// |dart_project| will be used to configure the engine backing this view.
FlutterViewController(int width, int height, const DartProject& project);
virtual ~FlutterViewController();
// Prevent copying.
FlutterViewController(FlutterViewController const&) = delete;
FlutterViewController& operator=(FlutterViewController const&) = delete;
// Returns the view controller's view ID.
FlutterViewId view_id() const;
// Returns the engine running Flutter content in this view.
FlutterEngine* engine() const { return engine_.get(); }
// Returns the view managed by this controller.
FlutterView* view() const { return view_.get(); }
// Requests new frame from the engine and repaints the view.
void ForceRedraw();
// Allows the Flutter engine and any interested plugins an opportunity to
// handle the given message.
//
// If a result is returned, then the message was handled in such a way that
// further handling should not be done.
std::optional<LRESULT> HandleTopLevelWindowProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam);
private:
// Handle for interacting with the C API's view controller, if any.
FlutterDesktopViewControllerRef controller_ = nullptr;
// The backing engine
std::shared_ptr<FlutterEngine> engine_;
// The owned FlutterView.
std::unique_ptr<FlutterView> view_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_
@@ -0,0 +1,62 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_MESSAGE_CODEC_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_MESSAGE_CODEC_H_
#include <memory>
#include <string>
#include <vector>
namespace flutter {
// Translates between a binary message and higher-level method call and
// response/error objects.
template <typename T>
class MessageCodec {
public:
MessageCodec() = default;
virtual ~MessageCodec() = default;
// Prevent copying.
MessageCodec(MessageCodec<T> const&) = delete;
MessageCodec& operator=(MessageCodec<T> const&) = delete;
// Returns the message encoded in |binary_message|, or nullptr if it cannot be
// decoded by this codec.
std::unique_ptr<T> DecodeMessage(const uint8_t* binary_message,
const size_t message_size) const {
return std::move(DecodeMessageInternal(binary_message, message_size));
}
// Returns the message encoded in |binary_message|, or nullptr if it cannot be
// decoded by this codec.
std::unique_ptr<T> DecodeMessage(
const std::vector<uint8_t>& binary_message) const {
size_t size = binary_message.size();
const uint8_t* data = size > 0 ? &binary_message[0] : nullptr;
return std::move(DecodeMessageInternal(data, size));
}
// Returns a binary encoding of the given |message|, or nullptr if the
// message cannot be serialized by this codec.
std::unique_ptr<std::vector<uint8_t>> EncodeMessage(const T& message) const {
return std::move(EncodeMessageInternal(message));
}
protected:
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<T> DecodeMessageInternal(
const uint8_t* binary_message,
const size_t message_size) const = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<std::vector<uint8_t>> EncodeMessageInternal(
const T& message) const = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_MESSAGE_CODEC_H_
@@ -0,0 +1,43 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CALL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CALL_H_
#include <memory>
#include <string>
namespace flutter {
class EncodableValue;
// An object encapsulating a method call from Flutter whose arguments are of
// type T.
template <typename T = EncodableValue>
class MethodCall {
public:
// Creates a MethodCall with the given name and arguments.
MethodCall(const std::string& method_name, std::unique_ptr<T> arguments)
: method_name_(method_name), arguments_(std::move(arguments)) {}
virtual ~MethodCall() = default;
// Prevent copying.
MethodCall(MethodCall<T> const&) = delete;
MethodCall& operator=(MethodCall<T> const&) = delete;
// The name of the method being called.
const std::string& method_name() const { return method_name_; }
// The arguments to the method call, or NULL if there are none.
const T* arguments() const { return arguments_.get(); }
private:
std::string method_name_;
std::unique_ptr<T> arguments_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CALL_H_
@@ -0,0 +1,151 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CHANNEL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CHANNEL_H_
#include <iostream>
#include <string>
#include "basic_message_channel.h"
#include "binary_messenger.h"
#include "engine_method_result.h"
#include "method_call.h"
#include "method_codec.h"
#include "method_result.h"
namespace flutter {
class EncodableValue;
// A handler for receiving a method call from the Flutter engine.
//
// Implementations must asynchronously call exactly one of the methods on
// |result| to indicate the result of the method call.
template <typename T>
using MethodCallHandler =
std::function<void(const MethodCall<T>& call,
std::unique_ptr<MethodResult<T>> result)>;
// A channel for communicating with the Flutter engine using invocation of
// asynchronous methods.
template <typename T = EncodableValue>
class MethodChannel {
public:
// Creates an instance that sends and receives method calls on the channel
// named |name|, encoded with |codec| and dispatched via |messenger|.
MethodChannel(BinaryMessenger* messenger,
const std::string& name,
const MethodCodec<T>* codec)
: messenger_(messenger), name_(name), codec_(codec) {}
~MethodChannel() = default;
// Prevent copying.
MethodChannel(MethodChannel const&) = delete;
MethodChannel& operator=(MethodChannel const&) = delete;
// Sends a message to the Flutter engine on this channel.
//
// If |result| is provided, one of its methods will be invoked with the
// response from the engine.
void InvokeMethod(const std::string& method,
std::unique_ptr<T> arguments,
std::unique_ptr<MethodResult<T>> result = nullptr) {
MethodCall<T> method_call(method, std::move(arguments));
std::unique_ptr<std::vector<uint8_t>> message =
codec_->EncodeMethodCall(method_call);
if (!result) {
messenger_->Send(name_, message->data(), message->size(), nullptr);
return;
}
// std::function requires a copyable lambda, so convert to a shared pointer.
// This is safe since only one copy of the shared_pointer will ever be
// accessed.
std::shared_ptr<MethodResult<T>> shared_result(result.release());
const auto* codec = codec_;
std::string channel_name = name_;
BinaryReply reply_handler = [shared_result, codec, channel_name](
const uint8_t* reply, size_t reply_size) {
if (reply_size == 0) {
shared_result->NotImplemented();
return;
}
// Use this channel's codec to decode and handle the
// reply.
bool decoded = codec->DecodeAndProcessResponseEnvelope(
reply, reply_size, shared_result.get());
if (!decoded) {
std::cerr << "Unable to decode reply to method "
"invocation on channel "
<< channel_name << std::endl;
shared_result->NotImplemented();
}
};
messenger_->Send(name_, message->data(), message->size(),
std::move(reply_handler));
}
// Registers a handler that should be called any time a method call is
// received on this channel. A null handler will remove any previous handler.
//
// The handler will be owned by the underlying BinaryMessageHandler.
// Destroying the MethodChannel will not unregister the handler, so
// the caller is responsible for unregistering explicitly if the handler
// stops being valid before the engine is destroyed.
void SetMethodCallHandler(const MethodCallHandler<T>& handler) const {
if (!handler) {
messenger_->SetMessageHandler(name_, nullptr);
return;
}
const auto* codec = codec_;
std::string channel_name = name_;
BinaryMessageHandler binary_handler = [handler, codec, channel_name](
const uint8_t* message,
size_t message_size,
BinaryReply reply) {
// Use this channel's codec to decode the call and build a result handler.
auto result =
std::make_unique<EngineMethodResult<T>>(std::move(reply), codec);
std::unique_ptr<MethodCall<T>> method_call =
codec->DecodeMethodCall(message, message_size);
if (!method_call) {
std::cerr << "Unable to construct method call from message on channel "
<< channel_name << std::endl;
result->NotImplemented();
return;
}
handler(*method_call, std::move(result));
};
messenger_->SetMessageHandler(name_, std::move(binary_handler));
}
// Adjusts the number of messages that will get buffered when sending messages
// to channels that aren't fully set up yet. For example, the engine isn't
// running yet or the channel's message handler isn't set up on the Dart side
// yet.
void Resize(int new_size) {
internal::ResizeChannel(messenger_, name_, new_size);
}
// Defines whether the channel should show warning messages when discarding
// messages due to overflow.
//
// When |warns| is false, the channel is expected to overflow and warning
// messages will not be shown.
void SetWarnsOnOverflow(bool warns) {
internal::SetChannelWarnsOnOverflow(messenger_, name_, warns);
}
private:
BinaryMessenger* messenger_;
std::string name_;
const MethodCodec<T>* codec_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CHANNEL_H_
@@ -0,0 +1,111 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CODEC_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CODEC_H_
#include <memory>
#include <string>
#include <vector>
#include "method_call.h"
#include "method_result.h"
namespace flutter {
// Translates between a binary message and higher-level method call and
// response/error objects.
template <typename T>
class MethodCodec {
public:
MethodCodec() = default;
virtual ~MethodCodec() = default;
// Prevent copying.
MethodCodec(MethodCodec<T> const&) = delete;
MethodCodec& operator=(MethodCodec<T> const&) = delete;
// Returns the MethodCall encoded in |message|, or nullptr if it cannot be
// decoded.
std::unique_ptr<MethodCall<T>> DecodeMethodCall(const uint8_t* message,
size_t message_size) const {
return std::move(DecodeMethodCallInternal(message, message_size));
}
// Returns the MethodCall encoded in |message|, or nullptr if it cannot be
// decoded.
std::unique_ptr<MethodCall<T>> DecodeMethodCall(
const std::vector<uint8_t>& message) const {
size_t size = message.size();
const uint8_t* data = size > 0 ? &message[0] : nullptr;
return std::move(DecodeMethodCallInternal(data, size));
}
// Returns a binary encoding of the given |method_call|, or nullptr if the
// method call cannot be serialized by this codec.
std::unique_ptr<std::vector<uint8_t>> EncodeMethodCall(
const MethodCall<T>& method_call) const {
return std::move(EncodeMethodCallInternal(method_call));
}
// Returns a binary encoding of |result|. |result| must be a type supported
// by the codec.
std::unique_ptr<std::vector<uint8_t>> EncodeSuccessEnvelope(
const T* result = nullptr) const {
return std::move(EncodeSuccessEnvelopeInternal(result));
}
// Returns a binary encoding of |error|. The |error_details| must be a type
// supported by the codec.
std::unique_ptr<std::vector<uint8_t>> EncodeErrorEnvelope(
const std::string& error_code,
const std::string& error_message = "",
const T* error_details = nullptr) const {
return std::move(
EncodeErrorEnvelopeInternal(error_code, error_message, error_details));
}
// Decodes the response envelope encoded in |response|, calling the
// appropriate method on |result|.
//
// Returns false if |response| cannot be decoded. In that case the caller is
// responsible for calling a |result| method.
bool DecodeAndProcessResponseEnvelope(const uint8_t* response,
size_t response_size,
MethodResult<T>* result) const {
return DecodeAndProcessResponseEnvelopeInternal(response, response_size,
result);
}
protected:
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<MethodCall<T>> DecodeMethodCallInternal(
const uint8_t* message,
size_t message_size) const = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<std::vector<uint8_t>> EncodeMethodCallInternal(
const MethodCall<T>& method_call) const = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<std::vector<uint8_t>> EncodeSuccessEnvelopeInternal(
const T* result) const = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual std::unique_ptr<std::vector<uint8_t>> EncodeErrorEnvelopeInternal(
const std::string& error_code,
const std::string& error_message,
const T* error_details) const = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual bool DecodeAndProcessResponseEnvelopeInternal(
const uint8_t* response,
size_t response_size,
MethodResult<T>* result) const = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CODEC_H_
@@ -0,0 +1,76 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_H_
#include <string>
namespace flutter {
class EncodableValue;
// Encapsulates a result returned from a MethodCall. Only one method should be
// called on any given instance.
template <typename T = EncodableValue>
class MethodResult {
public:
MethodResult() = default;
virtual ~MethodResult() = default;
// Prevent copying.
MethodResult(MethodResult const&) = delete;
MethodResult& operator=(MethodResult const&) = delete;
// Sends a success response, indicating that the call completed successfully
// with the given result.
void Success(const T& result) { SuccessInternal(&result); }
// Sends a success response, indicating that the call completed successfully
// with no result.
void Success() { SuccessInternal(nullptr); }
// Sends an error response, indicating that the call was understood but
// handling failed in some way.
//
// error_code: A string error code describing the error.
// error_message: A user-readable error message.
// error_details: Arbitrary extra details about the error.
void Error(const std::string& error_code,
const std::string& error_message,
const T& error_details) {
ErrorInternal(error_code, error_message, &error_details);
}
// Sends an error response, indicating that the call was understood but
// handling failed in some way.
//
// error_code: A string error code describing the error.
// error_message: A user-readable error message (optional).
void Error(const std::string& error_code,
const std::string& error_message = "") {
ErrorInternal(error_code, error_message, nullptr);
}
// Sends a not-implemented response, indicating that the method either was not
// recognized, or has not been implemented.
void NotImplemented() { NotImplementedInternal(); }
protected:
// Implementation of the public interface, to be provided by subclasses.
virtual void SuccessInternal(const T* result) = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual void ErrorInternal(const std::string& error_code,
const std::string& error_message,
const T* error_details) = 0;
// Implementation of the public interface, to be provided by subclasses.
virtual void NotImplementedInternal() = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_H_
@@ -0,0 +1,80 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_FUNCTIONS_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_FUNCTIONS_H_
#include <functional>
#include <string>
#include <utility>
#include "method_result.h"
namespace flutter {
class EncodableValue;
// Handler types for each of the MethodResult outcomes.
template <typename T>
using ResultHandlerSuccess = std::function<void(const T* result)>;
template <typename T>
using ResultHandlerError = std::function<void(const std::string& error_code,
const std::string& error_message,
const T* error_details)>;
template <typename T>
using ResultHandlerNotImplemented = std::function<void()>;
// An implementation of MethodResult that pass calls through to provided
// function objects, for ease of constructing one-off result handlers.
template <typename T = EncodableValue>
class MethodResultFunctions : public MethodResult<T> {
public:
// Creates a result object that calls the provided functions for the
// corresponding MethodResult outcomes.
MethodResultFunctions(ResultHandlerSuccess<T> on_success,
ResultHandlerError<T> on_error,
ResultHandlerNotImplemented<T> on_not_implemented)
: on_success_(std::move(on_success)),
on_error_(std::move(on_error)),
on_not_implemented_(std::move(on_not_implemented)) {}
virtual ~MethodResultFunctions() = default;
// Prevent copying.
MethodResultFunctions(MethodResultFunctions const&) = delete;
MethodResultFunctions& operator=(MethodResultFunctions const&) = delete;
protected:
// |flutter::MethodResult|
void SuccessInternal(const T* result) override {
if (on_success_) {
on_success_(result);
}
}
// |flutter::MethodResult|
void ErrorInternal(const std::string& error_code,
const std::string& error_message,
const T* error_details) override {
if (on_error_) {
on_error_(error_code, error_message, error_details);
}
}
// |flutter::MethodResult|
void NotImplementedInternal() override {
if (on_not_implemented_) {
on_not_implemented_();
}
}
private:
ResultHandlerSuccess<T> on_success_;
ResultHandlerError<T> on_error_;
ResultHandlerNotImplemented<T> on_not_implemented_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_FUNCTIONS_H_
@@ -0,0 +1,131 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_H_
#include <flutter_plugin_registrar.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include "binary_messenger.h"
#include "texture_registrar.h"
namespace flutter {
class Plugin;
// A object managing the registration of a plugin for various events.
//
// Currently this class has very limited functionality, but is expected to
// expand over time to more closely match the functionality of
// the Flutter mobile plugin APIs' plugin registrars.
class PluginRegistrar {
public:
// Creates a new PluginRegistrar. |core_registrar| and the messenger it
// provides must remain valid as long as this object exists.
explicit PluginRegistrar(FlutterDesktopPluginRegistrarRef core_registrar);
virtual ~PluginRegistrar();
// Prevent copying.
PluginRegistrar(PluginRegistrar const&) = delete;
PluginRegistrar& operator=(PluginRegistrar const&) = delete;
// Returns the messenger to use for creating channels to communicate with the
// Flutter engine.
//
// This pointer will remain valid for the lifetime of this instance.
BinaryMessenger* messenger() { return messenger_.get(); }
// Returns the texture registrar to use for the plugin to render a pixel
// buffer.
TextureRegistrar* texture_registrar() { return texture_registrar_.get(); }
// Takes ownership of |plugin|.
//
// Plugins are not required to call this method if they have other lifetime
// management, but this is a convenient place for plugins to be owned to
// ensure that they stay valid for any registered callbacks.
void AddPlugin(std::unique_ptr<Plugin> plugin);
protected:
FlutterDesktopPluginRegistrarRef registrar() const { return registrar_; }
// Destroys all owned plugins. Subclasses should call this at the beginning of
// their destructors to prevent the possibility of an owned plugin trying to
// access destroyed state during its own destruction.
void ClearPlugins();
private:
// Handle for interacting with the C API's registrar.
FlutterDesktopPluginRegistrarRef registrar_;
std::unique_ptr<BinaryMessenger> messenger_;
std::unique_ptr<TextureRegistrar> texture_registrar_;
// Plugins registered for ownership.
std::set<std::unique_ptr<Plugin>> plugins_;
};
// A plugin that can be registered for ownership by a PluginRegistrar.
class Plugin {
public:
virtual ~Plugin() = default;
};
// A singleton to own PluginRegistrars. This is intended for use in plugins,
// where there is no higher-level object to own a PluginRegistrar that can
// own plugin instances and ensure that they live as long as the engine they
// are registered with.
class PluginRegistrarManager {
public:
static PluginRegistrarManager* GetInstance();
// Prevent copying.
PluginRegistrarManager(PluginRegistrarManager const&) = delete;
PluginRegistrarManager& operator=(PluginRegistrarManager const&) = delete;
// Returns a plugin registrar wrapper of type T, which must be a kind of
// PluginRegistrar, creating it if necessary. The returned registrar will
// live as long as the underlying FlutterDesktopPluginRegistrarRef, so
// can be used to own plugin instances.
//
// Calling this multiple times for the same registrar_ref with different
// template types results in undefined behavior.
template <class T>
T* GetRegistrar(FlutterDesktopPluginRegistrarRef registrar_ref) {
auto insert_result =
registrars_.emplace(registrar_ref, std::make_unique<T>(registrar_ref));
auto& registrar_pair = *(insert_result.first);
FlutterDesktopPluginRegistrarSetDestructionHandler(registrar_pair.first,
OnRegistrarDestroyed);
return static_cast<T*>(registrar_pair.second.get());
}
// Destroys all registrar wrappers created by the manager.
//
// This is intended primarily for use in tests.
void Reset() { registrars_.clear(); }
private:
PluginRegistrarManager();
using WrapperMap = std::map<FlutterDesktopPluginRegistrarRef,
std::unique_ptr<PluginRegistrar>>;
static void OnRegistrarDestroyed(FlutterDesktopPluginRegistrarRef registrar);
WrapperMap* registrars() { return &registrars_; }
WrapperMap registrars_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_H_
@@ -0,0 +1,151 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_WINDOWS_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_WINDOWS_H_
#include <flutter_windows.h>
#include <windows.h>
#include <memory>
#include <optional>
#include "flutter_view.h"
#include "plugin_registrar.h"
namespace flutter {
// A delegate callback for WindowProc delegation.
//
// Implementations should return a value only if they have handled the message
// and want to stop all further handling.
using WindowProcDelegate = std::function<std::optional<
LRESULT>(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)>;
// An extension to PluginRegistrar providing access to Windows-specific
// functionality.
class PluginRegistrarWindows : public PluginRegistrar {
public:
// Creates a new PluginRegistrar. |core_registrar| and the messenger it
// provides must remain valid as long as this object exists.
explicit PluginRegistrarWindows(
FlutterDesktopPluginRegistrarRef core_registrar)
: PluginRegistrar(core_registrar) {
FlutterDesktopViewRef implicit_view =
FlutterDesktopPluginRegistrarGetView(core_registrar);
if (implicit_view) {
implicit_view_ = std::make_unique<FlutterView>(implicit_view);
}
}
virtual ~PluginRegistrarWindows() {
// Must be the first call.
ClearPlugins();
// Explicitly cleared to facilitate destruction order testing.
implicit_view_.reset();
}
// Prevent copying.
PluginRegistrarWindows(PluginRegistrarWindows const&) = delete;
PluginRegistrarWindows& operator=(PluginRegistrarWindows const&) = delete;
// Returns the implicit view, or nullptr if there is no implicit view.
//
// See:
// https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html
//
// DEPRECATED: Use |GetViewById| instead.
FlutterView* GetView() { return implicit_view_.get(); }
// Returns the view with the given ID, or nullptr if the view does not exist.
//
// Destroying the shared pointer destroys the reference to the view; it does
// not destroy the underlying view.
std::shared_ptr<FlutterView> GetViewById(FlutterViewId view_id) const {
FlutterDesktopViewRef view =
FlutterDesktopPluginRegistrarGetViewById(registrar(), view_id);
if (!view) {
return nullptr;
}
return std::make_shared<FlutterView>(view);
}
// Registers |delegate| to receive WindowProc callbacks for the top-level
// window containing this Flutter instance. Returns an ID that can be used to
// unregister the handler.
//
// Delegates are not guaranteed to be called:
// - The application may choose not to delegate WindowProc calls.
// - If multiple plugins are registered, the first one that returns a value
// from the delegate message will "win", and others will not be called.
// The order of delegate calls is not defined.
//
// Delegates should be implemented as narrowly as possible, only returning
// a value in cases where it's important that other delegates not run, to
// minimize the chances of conflicts between plugins.
int RegisterTopLevelWindowProcDelegate(WindowProcDelegate delegate) {
if (window_proc_delegates_.empty()) {
FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(
registrar(), PluginRegistrarWindows::OnTopLevelWindowProc, this);
}
int delegate_id = next_window_proc_delegate_id_++;
window_proc_delegates_.emplace(delegate_id, std::move(delegate));
return delegate_id;
}
// Unregisters a previously registered delegate.
void UnregisterTopLevelWindowProcDelegate(int proc_id) {
window_proc_delegates_.erase(proc_id);
if (window_proc_delegates_.empty()) {
FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate(
registrar(), PluginRegistrarWindows::OnTopLevelWindowProc);
}
}
private:
// A FlutterDesktopWindowProcCallback implementation that forwards back to
// a PluginRegistarWindows instance provided as |user_data|.
static bool OnTopLevelWindowProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam,
void* user_data,
LRESULT* result) {
const auto* registrar = static_cast<PluginRegistrarWindows*>(user_data);
std::optional optional_result = registrar->CallTopLevelWindowProcDelegates(
hwnd, message, wparam, lparam);
if (optional_result) {
*result = *optional_result;
}
return optional_result.has_value();
}
std::optional<LRESULT> CallTopLevelWindowProcDelegates(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) const {
std::optional<LRESULT> result;
for (const auto& pair : window_proc_delegates_) {
result = pair.second(hwnd, message, wparam, lparam);
// Stop as soon as any delegate indicates that it has handled the message.
if (result) {
break;
}
}
return result;
}
// The associated FlutterView, if any.
std::unique_ptr<FlutterView> implicit_view_;
// The next ID to return from RegisterWindowProcDelegate.
int next_window_proc_delegate_id_ = 1;
std::map<int, WindowProcDelegate> window_proc_delegates_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_WINDOWS_H_
@@ -0,0 +1,37 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRY_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRY_H_
#include <string>
#include <flutter_plugin_registrar.h>
namespace flutter {
// Vends PluginRegistrars for named plugins.
//
// Plugins are identified by unique string keys, typically the name of the
// plugin's main class.
class PluginRegistry {
public:
PluginRegistry() = default;
virtual ~PluginRegistry() = default;
// Prevent copying.
PluginRegistry(PluginRegistry const&) = delete;
PluginRegistry& operator=(PluginRegistry const&) = delete;
// Returns the FlutterDesktopPluginRegistrarRef to register a plugin with the
// given name.
//
// The name must be unique across the application.
virtual FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin(
const std::string& plugin_name) = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRY_H_
@@ -0,0 +1,76 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_CODEC_SERIALIZER_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_CODEC_SERIALIZER_H_
#include "byte_streams.h"
#include "encodable_value.h"
namespace flutter {
// Encapsulates the logic for encoding/decoding EncodableValues to/from the
// standard codec binary representation.
//
// This can be subclassed to extend the standard codec with support for new
// types.
class StandardCodecSerializer {
public:
virtual ~StandardCodecSerializer();
// Returns the shared serializer instance.
static const StandardCodecSerializer& GetInstance();
// Prevent copying.
StandardCodecSerializer(StandardCodecSerializer const&) = delete;
StandardCodecSerializer& operator=(StandardCodecSerializer const&) = delete;
// Reads and returns the next value from |stream|.
EncodableValue ReadValue(ByteStreamReader* stream) const;
// Writes the encoding of |value| to |stream|, including the initial type
// discrimination byte.
//
// Can be overridden by a subclass to extend the codec.
virtual void WriteValue(const EncodableValue& value,
ByteStreamWriter* stream) const;
protected:
// Codecs require long-lived serializers, so clients should always use
// GetInstance().
StandardCodecSerializer();
// Reads and returns the next value from |stream|, whose discrimination byte
// was |type|.
//
// The discrimination byte will already have been read from the stream when
// this is called.
//
// Can be overridden by a subclass to extend the codec.
virtual EncodableValue ReadValueOfType(uint8_t type,
ByteStreamReader* stream) const;
// Reads the variable-length size from the current position in |stream|.
size_t ReadSize(ByteStreamReader* stream) const;
// Writes the variable-length size encoding to |stream|.
void WriteSize(size_t size, ByteStreamWriter* stream) const;
private:
// Reads a fixed-type list whose values are of type T from the current
// position in |stream|, and returns it as the corresponding EncodableValue.
// |T| must correspond to one of the supported list value types of
// EncodableValue.
template <typename T>
EncodableValue ReadVector(ByteStreamReader* stream) const;
// Writes |vector| to |stream| as a fixed-type list. |T| must correspond to
// one of the supported list value types of EncodableValue.
template <typename T>
void WriteVector(const std::vector<T> vector, ByteStreamWriter* stream) const;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_CODEC_SERIALIZER_H_
@@ -0,0 +1,57 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_MESSAGE_CODEC_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_MESSAGE_CODEC_H_
#include <memory>
#include "encodable_value.h"
#include "message_codec.h"
#include "standard_codec_serializer.h"
namespace flutter {
// A binary message encoding/decoding mechanism for communications to/from the
// Flutter engine via message channels.
class StandardMessageCodec : public MessageCodec<EncodableValue> {
public:
// Returns an instance of the codec, optionally using a custom serializer to
// add support for more types.
//
// If provided, |serializer| must be long-lived. If no serializer is provided,
// the default will be used.
//
// The instance returned for a given |serializer| will be shared, and
// any instance returned from this will be long-lived, and can be safely
// passed to, e.g., channel constructors.
static const StandardMessageCodec& GetInstance(
const StandardCodecSerializer* serializer = nullptr);
~StandardMessageCodec();
// Prevent copying.
StandardMessageCodec(StandardMessageCodec const&) = delete;
StandardMessageCodec& operator=(StandardMessageCodec const&) = delete;
protected:
// |flutter::MessageCodec|
std::unique_ptr<EncodableValue> DecodeMessageInternal(
const uint8_t* binary_message,
const size_t message_size) const override;
// |flutter::MessageCodec|
std::unique_ptr<std::vector<uint8_t>> EncodeMessageInternal(
const EncodableValue& message) const override;
private:
// Instances should be obtained via GetInstance.
explicit StandardMessageCodec(const StandardCodecSerializer* serializer);
const StandardCodecSerializer* serializer_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_MESSAGE_CODEC_H_
@@ -0,0 +1,73 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_METHOD_CODEC_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_METHOD_CODEC_H_
#include <memory>
#include "encodable_value.h"
#include "method_call.h"
#include "method_codec.h"
#include "standard_codec_serializer.h"
namespace flutter {
// An implementation of MethodCodec that uses a binary serialization.
class StandardMethodCodec : public MethodCodec<EncodableValue> {
public:
// Returns an instance of the codec, optionally using a custom serializer to
// add support for more types.
//
// If provided, |serializer| must be long-lived. If no serializer is provided,
// the default will be used.
//
// The instance returned for a given |extension| will be shared, and
// any instance returned from this will be long-lived, and can be safely
// passed to, e.g., channel constructors.
static const StandardMethodCodec& GetInstance(
const StandardCodecSerializer* serializer = nullptr);
~StandardMethodCodec();
// Prevent copying.
StandardMethodCodec(StandardMethodCodec const&) = delete;
StandardMethodCodec& operator=(StandardMethodCodec const&) = delete;
protected:
// |flutter::MethodCodec|
std::unique_ptr<MethodCall<EncodableValue>> DecodeMethodCallInternal(
const uint8_t* message,
size_t message_size) const override;
// |flutter::MethodCodec|
std::unique_ptr<std::vector<uint8_t>> EncodeMethodCallInternal(
const MethodCall<EncodableValue>& method_call) const override;
// |flutter::MethodCodec|
std::unique_ptr<std::vector<uint8_t>> EncodeSuccessEnvelopeInternal(
const EncodableValue* result) const override;
// |flutter::MethodCodec|
std::unique_ptr<std::vector<uint8_t>> EncodeErrorEnvelopeInternal(
const std::string& error_code,
const std::string& error_message,
const EncodableValue* error_details) const override;
// |flutter::MethodCodec|
bool DecodeAndProcessResponseEnvelopeInternal(
const uint8_t* response,
size_t response_size,
MethodResult<EncodableValue>* result) const override;
private:
// Instances should be obtained via GetInstance.
explicit StandardMethodCodec(const StandardCodecSerializer* serializer);
const StandardCodecSerializer* serializer_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_METHOD_CODEC_H_
@@ -0,0 +1,111 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_
#include <flutter_texture_registrar.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <utility>
#include <variant>
namespace flutter {
// A pixel buffer texture.
class PixelBufferTexture {
public:
// A callback used for retrieving pixel buffers.
typedef std::function<const FlutterDesktopPixelBuffer*(size_t width,
size_t height)>
CopyBufferCallback;
// Creates a pixel buffer texture that uses the provided |copy_buffer_cb| to
// retrieve the buffer.
// As the callback is usually invoked from the render thread, the callee must
// take care of proper synchronization. It also needs to be ensured that the
// returned buffer isn't released prior to unregistering this texture.
explicit PixelBufferTexture(CopyBufferCallback copy_buffer_callback)
: copy_buffer_callback_(std::move(copy_buffer_callback)) {}
// Returns the callback-provided FlutterDesktopPixelBuffer that contains the
// actual pixel data. The intended surface size is specified by |width| and
// |height|.
const FlutterDesktopPixelBuffer* CopyPixelBuffer(size_t width,
size_t height) const {
return copy_buffer_callback_(width, height);
}
private:
const CopyBufferCallback copy_buffer_callback_;
};
// A GPU surface-based texture.
class GpuSurfaceTexture {
public:
// A callback used for retrieving surface descriptors.
typedef std::function<
const FlutterDesktopGpuSurfaceDescriptor*(size_t width, size_t height)>
ObtainDescriptorCallback;
GpuSurfaceTexture(FlutterDesktopGpuSurfaceType surface_type,
ObtainDescriptorCallback obtain_descriptor_callback)
: surface_type_(surface_type),
obtain_descriptor_callback_(std::move(obtain_descriptor_callback)) {}
// Returns the callback-provided FlutterDesktopGpuSurfaceDescriptor that
// contains the surface handle. The intended surface size is specified by
// |width| and |height|.
const FlutterDesktopGpuSurfaceDescriptor* ObtainDescriptor(
size_t width,
size_t height) const {
return obtain_descriptor_callback_(width, height);
}
// Gets the surface type.
FlutterDesktopGpuSurfaceType surface_type() const { return surface_type_; }
private:
const FlutterDesktopGpuSurfaceType surface_type_;
const ObtainDescriptorCallback obtain_descriptor_callback_;
};
// The available texture variants.
// Only PixelBufferTexture is currently implemented.
// Other variants are expected to be added in the future.
typedef std::variant<PixelBufferTexture, GpuSurfaceTexture> TextureVariant;
// An object keeping track of external textures.
//
// Thread safety:
// It's safe to call the member methods from any thread.
class TextureRegistrar {
public:
virtual ~TextureRegistrar() = default;
// Registers a |texture| object and returns the ID for that texture.
virtual int64_t RegisterTexture(TextureVariant* texture) = 0;
// Notifies the flutter engine that the texture object corresponding
// to |texure_id| needs to render a new frame.
//
// For PixelBufferTextures, this will effectively make the engine invoke
// the callback that was provided upon creating the texture.
virtual bool MarkTextureFrameAvailable(int64_t texture_id) = 0;
// Asynchronously unregisters an existing texture object.
// Upon completion, the optional |callback| gets invoked.
virtual void UnregisterTexture(int64_t texture_id,
std::function<void()> callback) = 0;
// Unregisters an existing texture object.
// DEPRECATED: Use UnregisterTexture(texture_id, optional_callback) instead.
virtual bool UnregisterTexture(int64_t texture_id) = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_
@@ -0,0 +1,62 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/flutter/plugin_registrar.h"
#include <iostream>
#include <map>
#include "binary_messenger_impl.h"
#include "include/flutter/engine_method_result.h"
#include "include/flutter/method_channel.h"
#include "texture_registrar_impl.h"
namespace flutter {
// ===== PluginRegistrar =====
PluginRegistrar::PluginRegistrar(FlutterDesktopPluginRegistrarRef registrar)
: registrar_(registrar) {
auto core_messenger = FlutterDesktopPluginRegistrarGetMessenger(registrar_);
messenger_ = std::make_unique<BinaryMessengerImpl>(core_messenger);
auto texture_registrar =
FlutterDesktopRegistrarGetTextureRegistrar(registrar_);
texture_registrar_ =
std::make_unique<TextureRegistrarImpl>(texture_registrar);
}
PluginRegistrar::~PluginRegistrar() {
// This must always be the first call.
ClearPlugins();
// Explicitly cleared to facilitate testing of destruction order.
messenger_.reset();
}
void PluginRegistrar::AddPlugin(std::unique_ptr<Plugin> plugin) {
plugins_.insert(std::move(plugin));
}
void PluginRegistrar::ClearPlugins() {
plugins_.clear();
}
// ===== PluginRegistrarManager =====
// static
PluginRegistrarManager* PluginRegistrarManager::GetInstance() {
static PluginRegistrarManager* instance = new PluginRegistrarManager();
return instance;
}
PluginRegistrarManager::PluginRegistrarManager() = default;
// static
void PluginRegistrarManager::OnRegistrarDestroyed(
FlutterDesktopPluginRegistrarRef registrar) {
GetInstance()->registrars()->erase(registrar);
}
} // namespace flutter
@@ -0,0 +1,9 @@
This code is intended to be built into plugins and applications to provide
higher-level, C++ abstractions for interacting with the Flutter library.
Over time, the goal is to move more of this code into the library in a way that
provides a usable ABI (e.g., does not use standard library in the interfaces).
Note that this wrapper is still in early stages. Expect significant churn in
both the APIs and the structure of the wrapper (e.g., the exact set of files
that need to be built).
@@ -0,0 +1,468 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains what would normally be standard_codec_serializer.cc,
// standard_message_codec.cc, and standard_method_codec.cc. They are grouped
// together to simplify use of the client wrapper, since the common case is
// that any client that needs one of these files needs all three.
#include <cassert>
#include <cstring>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "byte_buffer_streams.h"
#include "include/flutter/standard_codec_serializer.h"
#include "include/flutter/standard_message_codec.h"
#include "include/flutter/standard_method_codec.h"
namespace flutter {
// ===== standard_codec_serializer.h =====
namespace {
// The order/values here must match the constants in message_codecs.dart.
enum class EncodedType {
kNull = 0,
kTrue,
kFalse,
kInt32,
kInt64,
kLargeInt, // No longer used. If encountered, treat as kString.
kFloat64,
kString,
kUInt8List,
kInt32List,
kInt64List,
kFloat64List,
kList,
kMap,
kFloat32List,
};
// Returns the encoded type that should be written when serializing |value|.
EncodedType EncodedTypeForValue(const EncodableValue& value) {
switch (value.index()) {
case 0:
return EncodedType::kNull;
case 1:
return std::get<bool>(value) ? EncodedType::kTrue : EncodedType::kFalse;
case 2:
return EncodedType::kInt32;
case 3:
return EncodedType::kInt64;
case 4:
return EncodedType::kFloat64;
case 5:
return EncodedType::kString;
case 6:
return EncodedType::kUInt8List;
case 7:
return EncodedType::kInt32List;
case 8:
return EncodedType::kInt64List;
case 9:
return EncodedType::kFloat64List;
case 10:
return EncodedType::kList;
case 11:
return EncodedType::kMap;
case 13:
return EncodedType::kFloat32List;
}
assert(false);
return EncodedType::kNull;
}
} // namespace
StandardCodecSerializer::StandardCodecSerializer() = default;
StandardCodecSerializer::~StandardCodecSerializer() = default;
const StandardCodecSerializer& StandardCodecSerializer::GetInstance() {
static StandardCodecSerializer sInstance;
return sInstance;
};
EncodableValue StandardCodecSerializer::ReadValue(
ByteStreamReader* stream) const {
uint8_t type = stream->ReadByte();
return ReadValueOfType(type, stream);
}
void StandardCodecSerializer::WriteValue(const EncodableValue& value,
ByteStreamWriter* stream) const {
stream->WriteByte(static_cast<uint8_t>(EncodedTypeForValue(value)));
// TODO(cbracken): Consider replacing this with std::visit.
switch (value.index()) {
case 0:
case 1:
// Null and bool are encoded directly in the type.
break;
case 2:
stream->WriteInt32(std::get<int32_t>(value));
break;
case 3:
stream->WriteInt64(std::get<int64_t>(value));
break;
case 4:
stream->WriteAlignment(8);
stream->WriteDouble(std::get<double>(value));
break;
case 5: {
const auto& string_value = std::get<std::string>(value);
size_t size = string_value.size();
WriteSize(size, stream);
if (size > 0) {
stream->WriteBytes(
reinterpret_cast<const uint8_t*>(string_value.data()), size);
}
break;
}
case 6:
WriteVector(std::get<std::vector<uint8_t>>(value), stream);
break;
case 7:
WriteVector(std::get<std::vector<int32_t>>(value), stream);
break;
case 8:
WriteVector(std::get<std::vector<int64_t>>(value), stream);
break;
case 9:
WriteVector(std::get<std::vector<double>>(value), stream);
break;
case 10: {
const auto& list = std::get<EncodableList>(value);
WriteSize(list.size(), stream);
for (const auto& item : list) {
WriteValue(item, stream);
}
break;
}
case 11: {
const auto& map = std::get<EncodableMap>(value);
WriteSize(map.size(), stream);
for (const auto& pair : map) {
WriteValue(pair.first, stream);
WriteValue(pair.second, stream);
}
break;
}
case 12:
std::cerr
<< "Unhandled custom type in StandardCodecSerializer::WriteValue. "
<< "Custom types require codec extensions." << std::endl;
break;
case 13: {
WriteVector(std::get<std::vector<float>>(value), stream);
break;
}
}
}
EncodableValue StandardCodecSerializer::ReadValueOfType(
uint8_t type,
ByteStreamReader* stream) const {
switch (static_cast<EncodedType>(type)) {
case EncodedType::kNull:
return EncodableValue();
case EncodedType::kTrue:
return EncodableValue(true);
case EncodedType::kFalse:
return EncodableValue(false);
case EncodedType::kInt32:
return EncodableValue(stream->ReadInt32());
case EncodedType::kInt64:
return EncodableValue(stream->ReadInt64());
case EncodedType::kFloat64:
stream->ReadAlignment(8);
return EncodableValue(stream->ReadDouble());
case EncodedType::kLargeInt:
case EncodedType::kString: {
size_t size = ReadSize(stream);
std::string string_value;
string_value.resize(size);
stream->ReadBytes(reinterpret_cast<uint8_t*>(&string_value[0]), size);
return EncodableValue(string_value);
}
case EncodedType::kUInt8List:
return ReadVector<uint8_t>(stream);
case EncodedType::kInt32List:
return ReadVector<int32_t>(stream);
case EncodedType::kInt64List:
return ReadVector<int64_t>(stream);
case EncodedType::kFloat64List:
return ReadVector<double>(stream);
case EncodedType::kList: {
size_t length = ReadSize(stream);
EncodableList list_value;
list_value.reserve(length);
for (size_t i = 0; i < length; ++i) {
list_value.push_back(ReadValue(stream));
}
return EncodableValue(list_value);
}
case EncodedType::kMap: {
size_t length = ReadSize(stream);
EncodableMap map_value;
for (size_t i = 0; i < length; ++i) {
EncodableValue key = ReadValue(stream);
EncodableValue value = ReadValue(stream);
map_value.emplace(std::move(key), std::move(value));
}
return EncodableValue(map_value);
}
case EncodedType::kFloat32List: {
return ReadVector<float>(stream);
}
}
std::cerr << "Unknown type in StandardCodecSerializer::ReadValueOfType: "
<< static_cast<int>(type) << std::endl;
return EncodableValue();
}
size_t StandardCodecSerializer::ReadSize(ByteStreamReader* stream) const {
uint8_t byte = stream->ReadByte();
if (byte < 254) {
return byte;
} else if (byte == 254) {
uint16_t value = 0;
stream->ReadBytes(reinterpret_cast<uint8_t*>(&value), 2);
return value;
} else {
uint32_t value = 0;
stream->ReadBytes(reinterpret_cast<uint8_t*>(&value), 4);
return value;
}
}
void StandardCodecSerializer::WriteSize(size_t size,
ByteStreamWriter* stream) const {
if (size < 254) {
stream->WriteByte(static_cast<uint8_t>(size));
} else if (size <= 0xffff) {
stream->WriteByte(254);
uint16_t value = static_cast<uint16_t>(size);
stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), 2);
} else {
stream->WriteByte(255);
uint32_t value = static_cast<uint32_t>(size);
stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), 4);
}
}
template <typename T>
EncodableValue StandardCodecSerializer::ReadVector(
ByteStreamReader* stream) const {
size_t count = ReadSize(stream);
std::vector<T> vector;
vector.resize(count);
uint8_t type_size = static_cast<uint8_t>(sizeof(T));
if (type_size > 1) {
stream->ReadAlignment(type_size);
}
stream->ReadBytes(reinterpret_cast<uint8_t*>(vector.data()),
count * type_size);
return EncodableValue(vector);
}
template <typename T>
void StandardCodecSerializer::WriteVector(const std::vector<T> vector,
ByteStreamWriter* stream) const {
size_t count = vector.size();
WriteSize(count, stream);
if (count == 0) {
return;
}
uint8_t type_size = static_cast<uint8_t>(sizeof(T));
if (type_size > 1) {
stream->WriteAlignment(type_size);
}
stream->WriteBytes(reinterpret_cast<const uint8_t*>(vector.data()),
count * type_size);
}
// ===== standard_message_codec.h =====
// static
const StandardMessageCodec& StandardMessageCodec::GetInstance(
const StandardCodecSerializer* serializer) {
if (!serializer) {
serializer = &StandardCodecSerializer::GetInstance();
}
static auto* sInstances = new std::map<const StandardCodecSerializer*,
std::unique_ptr<StandardMessageCodec>>;
auto it = sInstances->find(serializer);
if (it == sInstances->end()) {
// Uses new due to private constructor (to prevent API clients from
// accidentally passing temporary codec instances to channels).
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
auto emplace_result = sInstances->emplace(
serializer, std::unique_ptr<StandardMessageCodec>(
new StandardMessageCodec(serializer)));
it = emplace_result.first;
}
return *(it->second);
}
StandardMessageCodec::StandardMessageCodec(
const StandardCodecSerializer* serializer)
: serializer_(serializer) {}
StandardMessageCodec::~StandardMessageCodec() = default;
std::unique_ptr<EncodableValue> StandardMessageCodec::DecodeMessageInternal(
const uint8_t* binary_message,
size_t message_size) const {
if (!binary_message) {
return std::make_unique<EncodableValue>();
}
ByteBufferStreamReader stream(binary_message, message_size);
return std::make_unique<EncodableValue>(serializer_->ReadValue(&stream));
}
std::unique_ptr<std::vector<uint8_t>>
StandardMessageCodec::EncodeMessageInternal(
const EncodableValue& message) const {
auto encoded = std::make_unique<std::vector<uint8_t>>();
ByteBufferStreamWriter stream(encoded.get());
serializer_->WriteValue(message, &stream);
return encoded;
}
// ===== standard_method_codec.h =====
// static
const StandardMethodCodec& StandardMethodCodec::GetInstance(
const StandardCodecSerializer* serializer) {
if (!serializer) {
serializer = &StandardCodecSerializer::GetInstance();
}
static auto* sInstances = new std::map<const StandardCodecSerializer*,
std::unique_ptr<StandardMethodCodec>>;
auto it = sInstances->find(serializer);
if (it == sInstances->end()) {
// Uses new due to private constructor (to prevent API clients from
// accidentally passing temporary codec instances to channels).
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
auto emplace_result = sInstances->emplace(
serializer, std::unique_ptr<StandardMethodCodec>(
new StandardMethodCodec(serializer)));
it = emplace_result.first;
}
return *(it->second);
}
StandardMethodCodec::StandardMethodCodec(
const StandardCodecSerializer* serializer)
: serializer_(serializer) {}
StandardMethodCodec::~StandardMethodCodec() = default;
std::unique_ptr<MethodCall<EncodableValue>>
StandardMethodCodec::DecodeMethodCallInternal(const uint8_t* message,
size_t message_size) const {
ByteBufferStreamReader stream(message, message_size);
EncodableValue method_name_value = serializer_->ReadValue(&stream);
const auto* method_name = std::get_if<std::string>(&method_name_value);
if (!method_name) {
std::cerr << "Invalid method call; method name is not a string."
<< std::endl;
return nullptr;
}
auto arguments =
std::make_unique<EncodableValue>(serializer_->ReadValue(&stream));
return std::make_unique<MethodCall<EncodableValue>>(*method_name,
std::move(arguments));
}
std::unique_ptr<std::vector<uint8_t>>
StandardMethodCodec::EncodeMethodCallInternal(
const MethodCall<EncodableValue>& method_call) const {
auto encoded = std::make_unique<std::vector<uint8_t>>();
ByteBufferStreamWriter stream(encoded.get());
serializer_->WriteValue(EncodableValue(method_call.method_name()), &stream);
if (method_call.arguments()) {
serializer_->WriteValue(*method_call.arguments(), &stream);
} else {
serializer_->WriteValue(EncodableValue(), &stream);
}
return encoded;
}
std::unique_ptr<std::vector<uint8_t>>
StandardMethodCodec::EncodeSuccessEnvelopeInternal(
const EncodableValue* result) const {
auto encoded = std::make_unique<std::vector<uint8_t>>();
ByteBufferStreamWriter stream(encoded.get());
stream.WriteByte(0);
if (result) {
serializer_->WriteValue(*result, &stream);
} else {
serializer_->WriteValue(EncodableValue(), &stream);
}
return encoded;
}
std::unique_ptr<std::vector<uint8_t>>
StandardMethodCodec::EncodeErrorEnvelopeInternal(
const std::string& error_code,
const std::string& error_message,
const EncodableValue* error_details) const {
auto encoded = std::make_unique<std::vector<uint8_t>>();
ByteBufferStreamWriter stream(encoded.get());
stream.WriteByte(1);
serializer_->WriteValue(EncodableValue(error_code), &stream);
if (error_message.empty()) {
serializer_->WriteValue(EncodableValue(), &stream);
} else {
serializer_->WriteValue(EncodableValue(error_message), &stream);
}
if (error_details) {
serializer_->WriteValue(*error_details, &stream);
} else {
serializer_->WriteValue(EncodableValue(), &stream);
}
return encoded;
}
bool StandardMethodCodec::DecodeAndProcessResponseEnvelopeInternal(
const uint8_t* response,
size_t response_size,
MethodResult<EncodableValue>* result) const {
ByteBufferStreamReader stream(response, response_size);
uint8_t flag = stream.ReadByte();
switch (flag) {
case 0: {
EncodableValue value = serializer_->ReadValue(&stream);
if (value.IsNull()) {
result->Success();
} else {
result->Success(value);
}
return true;
}
case 1: {
EncodableValue code = serializer_->ReadValue(&stream);
EncodableValue message = serializer_->ReadValue(&stream);
EncodableValue details = serializer_->ReadValue(&stream);
const std::string& message_string =
message.IsNull() ? "" : std::get<std::string>(message);
if (details.IsNull()) {
result->Error(std::get<std::string>(code), message_string);
} else {
result->Error(std::get<std::string>(code), message_string, details);
}
return true;
}
default:
return false;
}
}
} // namespace flutter
@@ -0,0 +1,44 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_TEXTURE_REGISTRAR_IMPL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_TEXTURE_REGISTRAR_IMPL_H_
#include "include/flutter/texture_registrar.h"
namespace flutter {
// Wrapper around a FlutterDesktopTextureRegistrarRef that implements the
// TextureRegistrar API.
class TextureRegistrarImpl : public TextureRegistrar {
public:
explicit TextureRegistrarImpl(
FlutterDesktopTextureRegistrarRef texture_registrar_ref);
virtual ~TextureRegistrarImpl();
// Prevent copying.
TextureRegistrarImpl(TextureRegistrarImpl const&) = delete;
TextureRegistrarImpl& operator=(TextureRegistrarImpl const&) = delete;
// |flutter::TextureRegistrar|
int64_t RegisterTexture(TextureVariant* texture) override;
// |flutter::TextureRegistrar|
bool MarkTextureFrameAvailable(int64_t texture_id) override;
// |flutter::TextureRegistrar|
void UnregisterTexture(int64_t texture_id,
std::function<void()> callback) override;
// |flutter::TextureRegistrar|
bool UnregisterTexture(int64_t texture_id) override;
private:
// Handle for interacting with the C API.
FlutterDesktopTextureRegistrarRef texture_registrar_ref_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_TEXTURE_REGISTRAR_IMPL_H_