Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
5ca5e261
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
5ca5e261
编写于
10月 23, 2020
作者:
R
Robert Ancell
提交者:
GitHub
10月 22, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add FlEventChannel (#21316)
Related to
https://github.com/flutter/flutter/issues/65270
上级
6bc70e4a
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
832 addition
and
0 deletion
+832
-0
ci/licenses_golden/licenses_flutter
ci/licenses_golden/licenses_flutter
+3
-0
shell/platform/linux/BUILD.gn
shell/platform/linux/BUILD.gn
+3
-0
shell/platform/linux/fl_event_channel.cc
shell/platform/linux/fl_event_channel.cc
+244
-0
shell/platform/linux/fl_event_channel_test.cc
shell/platform/linux/fl_event_channel_test.cc
+390
-0
shell/platform/linux/public/flutter_linux/fl_event_channel.h
shell/platform/linux/public/flutter_linux/fl_event_channel.h
+187
-0
shell/platform/linux/public/flutter_linux/flutter_linux.h
shell/platform/linux/public/flutter_linux/flutter_linux.h
+1
-0
shell/platform/linux/testing/mock_engine.cc
shell/platform/linux/testing/mock_engine.cc
+4
-0
未找到文件。
ci/licenses_golden/licenses_flutter
浏览文件 @
5ca5e261
...
...
@@ -1292,6 +1292,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project_private.h
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
FILE: ../../../flutter/shell/platform/linux/fl_event_channel.cc
FILE: ../../../flutter/shell/platform/linux/fl_event_channel_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc
...
...
@@ -1343,6 +1345,7 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_event_channel.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h
...
...
shell/platform/linux/BUILD.gn
浏览文件 @
5ca5e261
...
...
@@ -47,6 +47,7 @@ _public_headers = [
"public/flutter_linux/fl_binary_messenger.h",
"public/flutter_linux/fl_dart_project.h",
"public/flutter_linux/fl_engine.h",
"public/flutter_linux/fl_event_channel.h",
"public/flutter_linux/fl_json_message_codec.h",
"public/flutter_linux/fl_json_method_codec.h",
"public/flutter_linux/fl_message_codec.h",
...
...
@@ -92,6 +93,7 @@ source_set("flutter_linux_sources") {
"fl_binary_messenger.cc",
"fl_dart_project.cc",
"fl_engine.cc",
"fl_event_channel.cc",
"fl_json_message_codec.cc",
"fl_json_method_codec.cc",
"fl_key_event_plugin.cc",
...
...
@@ -154,6 +156,7 @@ executable("flutter_linux_unittests") {
"fl_binary_codec_test.cc",
"fl_binary_messenger_test.cc",
"fl_dart_project_test.cc",
"fl_event_channel_test.cc",
"fl_json_message_codec_test.cc",
"fl_json_method_codec_test.cc",
"fl_key_event_plugin_test.cc",
...
...
shell/platform/linux/fl_event_channel.cc
0 → 100644
浏览文件 @
5ca5e261
// 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 "flutter/shell/platform/linux/public/flutter_linux/fl_event_channel.h"
#include <gmodule.h>
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
static
constexpr
char
kListenMethod
[]
=
"listen"
;
static
constexpr
char
kCancelMethod
[]
=
"cancel"
;
static
constexpr
char
kEventRequestError
[]
=
"error"
;
struct
_FlEventChannel
{
GObject
parent_instance
;
// Messenger to communicate on.
FlBinaryMessenger
*
messenger
;
// Channel name.
gchar
*
name
;
// Codec to en/decode messages.
FlMethodCodec
*
codec
;
// Function called when the stream is listened to / cancelled.
FlEventChannelHandler
listen_handler
;
FlEventChannelHandler
cancel_handler
;
gpointer
handler_data
;
GDestroyNotify
handler_data_destroy_notify
;
};
struct
_FlEventChannelResponseHandle
{
GObject
parent_instance
;
FlBinaryMessengerResponseHandle
*
response_handle
;
};
// Added here to stop the compiler from optimising this function away.
G_MODULE_EXPORT
GType
fl_event_channel_get_type
();
G_DEFINE_TYPE
(
FlEventChannel
,
fl_event_channel
,
G_TYPE_OBJECT
)
// Handle method calls from the Dart side of the channel.
static
FlMethodErrorResponse
*
handle_method_call
(
FlEventChannel
*
self
,
const
gchar
*
name
,
FlValue
*
args
)
{
FlEventChannelHandler
handler
;
if
(
g_strcmp0
(
name
,
kListenMethod
)
==
0
)
{
handler
=
self
->
listen_handler
;
}
else
if
(
g_strcmp0
(
name
,
kCancelMethod
)
==
0
)
{
handler
=
self
->
cancel_handler
;
}
else
{
g_autofree
gchar
*
message
=
g_strdup_printf
(
"Unknown event channel request '%s'"
,
name
);
return
fl_method_error_response_new
(
kEventRequestError
,
message
,
nullptr
);
}
// If not handled, just accept requests.
if
(
handler
==
nullptr
)
{
return
nullptr
;
}
return
handler
(
self
,
args
,
self
->
handler_data
);
}
// Called when a binary message is received on this channel.
static
void
message_cb
(
FlBinaryMessenger
*
messenger
,
const
gchar
*
channel
,
GBytes
*
message
,
FlBinaryMessengerResponseHandle
*
response_handle
,
gpointer
user_data
)
{
FlEventChannel
*
self
=
FL_EVENT_CHANNEL
(
user_data
);
g_autofree
gchar
*
name
=
nullptr
;
g_autoptr
(
GError
)
error
=
nullptr
;
g_autoptr
(
FlValue
)
args
=
nullptr
;
if
(
!
fl_method_codec_decode_method_call
(
self
->
codec
,
message
,
&
name
,
&
args
,
&
error
))
{
g_warning
(
"Failed to decode message on event channel %s: %s"
,
self
->
name
,
error
->
message
);
fl_binary_messenger_send_response
(
messenger
,
response_handle
,
nullptr
,
nullptr
);
return
;
}
g_autoptr
(
FlMethodErrorResponse
)
response
=
handle_method_call
(
self
,
name
,
args
);
g_autoptr
(
GBytes
)
data
=
nullptr
;
if
(
response
==
nullptr
)
{
g_autoptr
(
GError
)
codec_error
=
nullptr
;
data
=
fl_method_codec_encode_success_envelope
(
self
->
codec
,
nullptr
,
&
codec_error
);
if
(
data
==
nullptr
)
{
g_warning
(
"Failed to encode event channel %s success response: %s"
,
self
->
name
,
codec_error
->
message
);
}
}
else
{
g_autoptr
(
GError
)
codec_error
=
nullptr
;
data
=
fl_method_codec_encode_error_envelope
(
self
->
codec
,
fl_method_error_response_get_code
(
response
),
fl_method_error_response_get_message
(
response
),
fl_method_error_response_get_details
(
response
),
&
codec_error
);
if
(
data
==
nullptr
)
{
g_warning
(
"Failed to encode event channel %s error response: %s"
,
self
->
name
,
codec_error
->
message
);
}
}
if
(
!
fl_binary_messenger_send_response
(
messenger
,
response_handle
,
data
,
&
error
))
{
g_warning
(
"Failed to send event channel response: %s"
,
error
->
message
);
}
}
// Removes handlers and their associated data.
static
void
remove_handlers
(
FlEventChannel
*
self
)
{
if
(
self
->
handler_data_destroy_notify
!=
nullptr
)
{
self
->
handler_data_destroy_notify
(
self
->
handler_data
);
}
self
->
listen_handler
=
nullptr
;
self
->
cancel_handler
=
nullptr
;
self
->
handler_data
=
nullptr
;
self
->
handler_data_destroy_notify
=
nullptr
;
}
// Called when the channel handler is closed.
static
void
channel_closed_cb
(
gpointer
user_data
)
{
g_autoptr
(
FlEventChannel
)
self
=
FL_EVENT_CHANNEL
(
user_data
);
remove_handlers
(
self
);
}
static
void
fl_event_channel_dispose
(
GObject
*
object
)
{
FlEventChannel
*
self
=
FL_EVENT_CHANNEL
(
object
);
if
(
self
->
messenger
!=
nullptr
)
{
fl_binary_messenger_set_message_handler_on_channel
(
self
->
messenger
,
self
->
name
,
nullptr
,
nullptr
,
nullptr
);
}
g_clear_object
(
&
self
->
messenger
);
g_clear_pointer
(
&
self
->
name
,
g_free
);
g_clear_object
(
&
self
->
codec
);
remove_handlers
(
self
);
G_OBJECT_CLASS
(
fl_event_channel_parent_class
)
->
dispose
(
object
);
}
static
void
fl_event_channel_class_init
(
FlEventChannelClass
*
klass
)
{
G_OBJECT_CLASS
(
klass
)
->
dispose
=
fl_event_channel_dispose
;
}
static
void
fl_event_channel_init
(
FlEventChannel
*
self
)
{}
G_MODULE_EXPORT
FlEventChannel
*
fl_event_channel_new
(
FlBinaryMessenger
*
messenger
,
const
gchar
*
name
,
FlMethodCodec
*
codec
)
{
g_return_val_if_fail
(
FL_IS_BINARY_MESSENGER
(
messenger
),
nullptr
);
g_return_val_if_fail
(
name
!=
nullptr
,
nullptr
);
g_return_val_if_fail
(
FL_IS_METHOD_CODEC
(
codec
),
nullptr
);
FlEventChannel
*
self
=
FL_EVENT_CHANNEL
(
g_object_new
(
fl_event_channel_get_type
(),
nullptr
));
self
->
messenger
=
FL_BINARY_MESSENGER
(
g_object_ref
(
messenger
));
self
->
name
=
g_strdup
(
name
);
self
->
codec
=
FL_METHOD_CODEC
(
g_object_ref
(
codec
));
fl_binary_messenger_set_message_handler_on_channel
(
self
->
messenger
,
self
->
name
,
message_cb
,
g_object_ref
(
self
),
channel_closed_cb
);
return
self
;
}
G_MODULE_EXPORT
void
fl_event_channel_set_stream_handlers
(
FlEventChannel
*
self
,
FlEventChannelHandler
listen_handler
,
FlEventChannelHandler
cancel_handler
,
gpointer
user_data
,
GDestroyNotify
destroy_notify
)
{
g_return_if_fail
(
FL_IS_EVENT_CHANNEL
(
self
));
remove_handlers
(
self
);
self
->
listen_handler
=
listen_handler
;
self
->
cancel_handler
=
cancel_handler
;
self
->
handler_data
=
user_data
;
self
->
handler_data_destroy_notify
=
destroy_notify
;
}
G_MODULE_EXPORT
gboolean
fl_event_channel_send
(
FlEventChannel
*
self
,
FlValue
*
event
,
GCancellable
*
cancellable
,
GError
**
error
)
{
g_return_val_if_fail
(
FL_IS_EVENT_CHANNEL
(
self
),
FALSE
);
g_return_val_if_fail
(
event
!=
nullptr
,
FALSE
);
g_autoptr
(
GBytes
)
data
=
fl_method_codec_encode_success_envelope
(
self
->
codec
,
event
,
error
);
if
(
data
==
nullptr
)
{
return
FALSE
;
}
fl_binary_messenger_send_on_channel
(
self
->
messenger
,
self
->
name
,
data
,
cancellable
,
nullptr
,
nullptr
);
return
TRUE
;
}
G_MODULE_EXPORT
gboolean
fl_event_channel_send_error
(
FlEventChannel
*
self
,
const
gchar
*
code
,
const
gchar
*
message
,
FlValue
*
details
,
GCancellable
*
cancellable
,
GError
**
error
)
{
g_return_val_if_fail
(
FL_IS_EVENT_CHANNEL
(
self
),
FALSE
);
g_return_val_if_fail
(
code
!=
nullptr
,
FALSE
);
g_return_val_if_fail
(
message
!=
nullptr
,
FALSE
);
g_autoptr
(
GBytes
)
data
=
fl_method_codec_encode_error_envelope
(
self
->
codec
,
code
,
message
,
details
,
error
);
if
(
data
==
nullptr
)
{
return
FALSE
;
}
fl_binary_messenger_send_on_channel
(
self
->
messenger
,
self
->
name
,
data
,
cancellable
,
nullptr
,
nullptr
);
return
TRUE
;
}
G_MODULE_EXPORT
gboolean
fl_event_channel_send_end_of_stream
(
FlEventChannel
*
self
,
GCancellable
*
cancellable
,
GError
**
error
)
{
g_return_val_if_fail
(
FL_IS_EVENT_CHANNEL
(
self
),
FALSE
);
fl_binary_messenger_send_on_channel
(
self
->
messenger
,
self
->
name
,
nullptr
,
cancellable
,
nullptr
,
nullptr
);
return
TRUE
;
}
shell/platform/linux/fl_event_channel_test.cc
0 → 100644
浏览文件 @
5ca5e261
// 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.
// Included first as it collides with the X11 headers.
#include "gtest/gtest.h"
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_event_channel.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
#include "flutter/shell/platform/linux/testing/mock_renderer.h"
// Data passed in tests.
typedef
struct
{
GMainLoop
*
loop
;
int
count
;
}
TestData
;
// Creates a mock engine that responds to platform messages.
static
FlEngine
*
make_mock_engine
()
{
g_autoptr
(
FlDartProject
)
project
=
fl_dart_project_new
();
g_autoptr
(
FlMockRenderer
)
renderer
=
fl_mock_renderer_new
();
g_autoptr
(
FlEngine
)
engine
=
fl_engine_new
(
project
,
FL_RENDERER
(
renderer
));
g_autoptr
(
GError
)
engine_error
=
nullptr
;
EXPECT_TRUE
(
fl_engine_start
(
engine
,
&
engine_error
));
EXPECT_EQ
(
engine_error
,
nullptr
);
return
static_cast
<
FlEngine
*>
(
g_object_ref
(
engine
));
}
// Triggers the engine to start listening to the channel.
static
void
listen_channel
(
FlBinaryMessenger
*
messenger
,
FlValue
*
args
)
{
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
g_autoptr
(
FlMethodChannel
)
channel
=
fl_method_channel_new
(
messenger
,
"test/standard-method"
,
FL_METHOD_CODEC
(
codec
));
// Trigger the engine to make a method call.
g_autoptr
(
FlValue
)
invoke_args
=
fl_value_new_list
();
fl_value_append_take
(
invoke_args
,
fl_value_new_string
(
"test/standard-event"
));
fl_value_append_take
(
invoke_args
,
fl_value_new_string
(
"listen"
));
fl_value_append
(
invoke_args
,
args
!=
nullptr
?
fl_value_ref
(
args
)
:
fl_value_new_null
());
fl_method_channel_invoke_method
(
channel
,
"InvokeMethod"
,
invoke_args
,
nullptr
,
nullptr
,
nullptr
);
}
// Triggers the engine to cancel the subscription to the channel.
static
void
cancel_channel
(
FlBinaryMessenger
*
messenger
,
FlValue
*
args
)
{
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
g_autoptr
(
FlMethodChannel
)
channel
=
fl_method_channel_new
(
messenger
,
"test/standard-method"
,
FL_METHOD_CODEC
(
codec
));
// Trigger the engine to make a method call.
g_autoptr
(
FlValue
)
invoke_args
=
fl_value_new_list
();
fl_value_append_take
(
invoke_args
,
fl_value_new_string
(
"test/standard-event"
));
fl_value_append_take
(
invoke_args
,
fl_value_new_string
(
"cancel"
));
fl_value_append_take
(
invoke_args
,
args
!=
nullptr
?
fl_value_ref
(
args
)
:
fl_value_new_null
());
fl_method_channel_invoke_method
(
channel
,
"InvokeMethod"
,
invoke_args
,
nullptr
,
nullptr
,
nullptr
);
}
// Called when when the remote end starts listening on the channel.
static
FlMethodErrorResponse
*
listen_listen_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
EXPECT_EQ
(
fl_value_get_type
(
args
),
FL_VALUE_TYPE_NULL
);
g_main_loop_quit
(
static_cast
<
GMainLoop
*>
(
user_data
));
return
nullptr
;
}
// Checks we detect a listen event.
TEST
(
FlEventChannelTest
,
Listen
)
{
g_autoptr
(
GMainLoop
)
loop
=
g_main_loop_new
(
nullptr
,
0
);
g_autoptr
(
FlEngine
)
engine
=
make_mock_engine
();
FlBinaryMessenger
*
messenger
=
fl_binary_messenger_new
(
engine
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
FlEventChannel
*
channel
=
fl_event_channel_new
(
messenger
,
"test/standard-event"
,
FL_METHOD_CODEC
(
codec
));
fl_event_channel_set_stream_handlers
(
channel
,
listen_listen_cb
,
nullptr
,
loop
,
nullptr
);
listen_channel
(
messenger
,
nullptr
);
// Blocks here until listen_listen_cb called.
g_main_loop_run
(
loop
);
// Manually unref because the compiler complains 'channel' is unused.
g_object_unref
(
channel
);
}
// Called when when the remote end starts listening on the channel.
static
FlMethodErrorResponse
*
listen_exception_listen_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
return
fl_method_error_response_new
(
"LISTEN-ERROR"
,
"LISTEN-ERROR-MESSAGE"
,
nullptr
);
}
// Called when a the test engine notifies us what response we sent in the
// ListenException test.
static
void
listen_exception_response_cb
(
FlBinaryMessenger
*
messenger
,
const
gchar
*
channel
,
GBytes
*
message
,
FlBinaryMessengerResponseHandle
*
response_handle
,
gpointer
user_data
)
{
fl_binary_messenger_send_response
(
messenger
,
response_handle
,
nullptr
,
nullptr
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
g_autoptr
(
GError
)
error
=
nullptr
;
g_autoptr
(
FlMethodResponse
)
response
=
fl_method_codec_decode_response
(
FL_METHOD_CODEC
(
codec
),
message
,
&
error
);
EXPECT_NE
(
response
,
nullptr
);
EXPECT_EQ
(
error
,
nullptr
);
EXPECT_TRUE
(
FL_IS_METHOD_ERROR_RESPONSE
(
response
));
EXPECT_STREQ
(
fl_method_error_response_get_code
(
FL_METHOD_ERROR_RESPONSE
(
response
)),
"LISTEN-ERROR"
);
EXPECT_STREQ
(
fl_method_error_response_get_message
(
FL_METHOD_ERROR_RESPONSE
(
response
)),
"LISTEN-ERROR-MESSAGE"
);
g_main_loop_quit
(
static_cast
<
GMainLoop
*>
(
user_data
));
}
// Checks we can generate a listen exception.
TEST
(
FlEventChannelTest
,
ListenException
)
{
g_autoptr
(
GMainLoop
)
loop
=
g_main_loop_new
(
nullptr
,
0
);
g_autoptr
(
FlEngine
)
engine
=
make_mock_engine
();
FlBinaryMessenger
*
messenger
=
fl_binary_messenger_new
(
engine
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
FlEventChannel
*
channel
=
fl_event_channel_new
(
messenger
,
"test/standard-event"
,
FL_METHOD_CODEC
(
codec
));
fl_event_channel_set_stream_handlers
(
channel
,
listen_exception_listen_cb
,
nullptr
,
loop
,
nullptr
);
// Listen for response to the engine.
fl_binary_messenger_set_message_handler_on_channel
(
messenger
,
"test/responses"
,
listen_exception_response_cb
,
loop
,
nullptr
);
listen_channel
(
messenger
,
nullptr
);
// Blocks here until listen_exception_response_cb called.
g_main_loop_run
(
loop
);
// Manually unref because the compiler complains 'channel' is unused.
g_object_unref
(
channel
);
}
// Called when when the remote end cancels their subscription.
static
FlMethodErrorResponse
*
cancel_cancel_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
EXPECT_EQ
(
fl_value_get_type
(
args
),
FL_VALUE_TYPE_NULL
);
g_main_loop_quit
(
static_cast
<
GMainLoop
*>
(
user_data
));
return
nullptr
;
}
// Checks we detect a cancel event.
TEST
(
FlEventChannelTest
,
Cancel
)
{
g_autoptr
(
GMainLoop
)
loop
=
g_main_loop_new
(
nullptr
,
0
);
g_autoptr
(
FlEngine
)
engine
=
make_mock_engine
();
FlBinaryMessenger
*
messenger
=
fl_binary_messenger_new
(
engine
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
FlEventChannel
*
channel
=
fl_event_channel_new
(
messenger
,
"test/standard-event"
,
FL_METHOD_CODEC
(
codec
));
fl_event_channel_set_stream_handlers
(
channel
,
nullptr
,
cancel_cancel_cb
,
loop
,
nullptr
);
listen_channel
(
messenger
,
nullptr
);
cancel_channel
(
messenger
,
nullptr
);
// Blocks here until cancel_cancel_cb called.
g_main_loop_run
(
loop
);
// Manually unref because the compiler complains 'channel' is unused.
g_object_unref
(
channel
);
}
// Called when when the remote end cancels their subscription.
static
FlMethodErrorResponse
*
cancel_exception_cancel_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
return
fl_method_error_response_new
(
"CANCEL-ERROR"
,
"CANCEL-ERROR-MESSAGE"
,
nullptr
);
}
// Called when a the test engine notifies us what response we sent in the
// CancelException test.
static
void
cancel_exception_response_cb
(
FlBinaryMessenger
*
messenger
,
const
gchar
*
channel
,
GBytes
*
message
,
FlBinaryMessengerResponseHandle
*
response_handle
,
gpointer
user_data
)
{
TestData
*
data
=
static_cast
<
TestData
*>
(
user_data
);
fl_binary_messenger_send_response
(
messenger
,
response_handle
,
nullptr
,
nullptr
);
data
->
count
++
;
if
(
data
->
count
==
2
)
{
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
g_autoptr
(
GError
)
error
=
nullptr
;
g_autoptr
(
FlMethodResponse
)
response
=
fl_method_codec_decode_response
(
FL_METHOD_CODEC
(
codec
),
message
,
&
error
);
EXPECT_NE
(
response
,
nullptr
);
EXPECT_EQ
(
error
,
nullptr
);
EXPECT_TRUE
(
FL_IS_METHOD_ERROR_RESPONSE
(
response
));
EXPECT_STREQ
(
fl_method_error_response_get_code
(
FL_METHOD_ERROR_RESPONSE
(
response
)),
"CANCEL-ERROR"
);
EXPECT_STREQ
(
fl_method_error_response_get_message
(
FL_METHOD_ERROR_RESPONSE
(
response
)),
"CANCEL-ERROR-MESSAGE"
);
g_main_loop_quit
(
data
->
loop
);
}
}
// Checks we can generate a cancel exception.
TEST
(
FlEventChannelTest
,
CancelException
)
{
g_autoptr
(
GMainLoop
)
loop
=
g_main_loop_new
(
nullptr
,
0
);
TestData
data
;
data
.
loop
=
loop
;
data
.
count
=
0
;
g_autoptr
(
FlEngine
)
engine
=
make_mock_engine
();
FlBinaryMessenger
*
messenger
=
fl_binary_messenger_new
(
engine
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
FlEventChannel
*
channel
=
fl_event_channel_new
(
messenger
,
"test/standard-event"
,
FL_METHOD_CODEC
(
codec
));
fl_event_channel_set_stream_handlers
(
channel
,
nullptr
,
cancel_exception_cancel_cb
,
&
data
,
nullptr
);
// Listen for response to the engine.
fl_binary_messenger_set_message_handler_on_channel
(
messenger
,
"test/responses"
,
cancel_exception_response_cb
,
&
data
,
nullptr
);
listen_channel
(
messenger
,
nullptr
);
cancel_channel
(
messenger
,
nullptr
);
// Blocks here until cancel_exception_response_cb called.
g_main_loop_run
(
loop
);
// Manually unref because the compiler complains 'channel' is unused.
g_object_unref
(
channel
);
}
// Called when when the remote end starts listening on the channel.
static
FlMethodErrorResponse
*
args_listen_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
g_autoptr
(
FlValue
)
expected_args
=
fl_value_new_string
(
"LISTEN-ARGS"
);
EXPECT_TRUE
(
fl_value_equal
(
args
,
expected_args
));
return
nullptr
;
}
// Called when when the remote end cancels their subscription.
static
FlMethodErrorResponse
*
args_cancel_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
g_autoptr
(
FlValue
)
expected_args
=
fl_value_new_string
(
"CANCEL-ARGS"
);
EXPECT_TRUE
(
fl_value_equal
(
args
,
expected_args
));
g_main_loop_quit
(
static_cast
<
GMainLoop
*>
(
user_data
));
return
nullptr
;
}
// Checks args are passed to listen/cancel.
TEST
(
FlEventChannelTest
,
Args
)
{
g_autoptr
(
GMainLoop
)
loop
=
g_main_loop_new
(
nullptr
,
0
);
g_autoptr
(
FlEngine
)
engine
=
make_mock_engine
();
FlBinaryMessenger
*
messenger
=
fl_binary_messenger_new
(
engine
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
FlEventChannel
*
channel
=
fl_event_channel_new
(
messenger
,
"test/standard-event"
,
FL_METHOD_CODEC
(
codec
));
fl_event_channel_set_stream_handlers
(
channel
,
args_listen_cb
,
args_cancel_cb
,
loop
,
nullptr
);
g_autoptr
(
FlValue
)
listen_args
=
fl_value_new_string
(
"LISTEN-ARGS"
);
listen_channel
(
messenger
,
listen_args
);
g_autoptr
(
FlValue
)
cancel_args
=
fl_value_new_string
(
"CANCEL-ARGS"
);
cancel_channel
(
messenger
,
cancel_args
);
// Blocks here until args_cancel_cb called.
g_main_loop_run
(
loop
);
// Manually unref because the compiler complains 'channel' is unused.
g_object_unref
(
channel
);
}
// Called when when the remote end starts listening on the channel.
static
FlMethodErrorResponse
*
send_events_listen_cb
(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
)
{
// Send some events.
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
g_autoptr
(
FlValue
)
event
=
fl_value_new_int
(
i
);
g_autoptr
(
GError
)
error
=
nullptr
;
EXPECT_TRUE
(
fl_event_channel_send
(
channel
,
event
,
nullptr
,
&
error
));
EXPECT_EQ
(
error
,
nullptr
);
}
return
nullptr
;
}
// Called when a the test engine notifies us what event we sent in the
// Test test.
static
void
send_events_events_cb
(
FlBinaryMessenger
*
messenger
,
const
gchar
*
channel
,
GBytes
*
message
,
FlBinaryMessengerResponseHandle
*
response_handle
,
gpointer
user_data
)
{
TestData
*
data
=
static_cast
<
TestData
*>
(
user_data
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
g_autoptr
(
GError
)
error
=
nullptr
;
g_autoptr
(
FlMethodResponse
)
response
=
fl_method_codec_decode_response
(
FL_METHOD_CODEC
(
codec
),
message
,
&
error
);
EXPECT_NE
(
response
,
nullptr
);
EXPECT_EQ
(
error
,
nullptr
);
FlValue
*
result
=
fl_method_response_get_result
(
response
,
&
error
);
EXPECT_NE
(
result
,
nullptr
);
EXPECT_EQ
(
error
,
nullptr
);
EXPECT_EQ
(
fl_value_get_type
(
result
),
FL_VALUE_TYPE_INT
);
EXPECT_EQ
(
fl_value_get_int
(
result
),
data
->
count
);
data
->
count
++
;
fl_binary_messenger_send_response
(
messenger
,
response_handle
,
nullptr
,
nullptr
);
// Got all the results!
if
(
data
->
count
==
5
)
{
g_main_loop_quit
(
data
->
loop
);
}
}
// Checks can send events.
TEST
(
FlEventChannelTest
,
Test
)
{
g_autoptr
(
GMainLoop
)
loop
=
g_main_loop_new
(
nullptr
,
0
);
TestData
data
;
data
.
loop
=
loop
;
data
.
count
=
0
;
g_autoptr
(
FlEngine
)
engine
=
make_mock_engine
();
FlBinaryMessenger
*
messenger
=
fl_binary_messenger_new
(
engine
);
g_autoptr
(
FlStandardMethodCodec
)
codec
=
fl_standard_method_codec_new
();
FlEventChannel
*
channel
=
fl_event_channel_new
(
messenger
,
"test/standard-event"
,
FL_METHOD_CODEC
(
codec
));
fl_event_channel_set_stream_handlers
(
channel
,
send_events_listen_cb
,
nullptr
,
&
data
,
nullptr
);
// Listen for events from the engine.
fl_binary_messenger_set_message_handler_on_channel
(
messenger
,
"test/events"
,
send_events_events_cb
,
&
data
,
nullptr
);
listen_channel
(
messenger
,
nullptr
);
cancel_channel
(
messenger
,
nullptr
);
// Blocks here until send_events_events_cb receives the last event.
g_main_loop_run
(
loop
);
// Manually unref because the compiler complains 'channel' is unused.
g_object_unref
(
channel
);
}
shell/platform/linux/public/flutter_linux/fl_event_channel.h
0 → 100644
浏览文件 @
5ca5e261
// 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_LINUX_FL_EVENT_CHANNEL_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_EVENT_CHANNEL_H_
#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
#error "Only <flutter_linux/flutter_linux.h> can be included directly."
#endif
#include <gio/gio.h>
#include <glib-object.h>
#include "fl_binary_messenger.h"
#include "fl_method_channel.h"
#include "fl_method_response.h"
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE
(
FlEventChannel
,
fl_event_channel
,
FL
,
EVENT_CHANNEL
,
GObject
)
/**
* FlEventChannel:
*
* #FlEventChannel is an object that allows sending
* an events stream to Dart code over platform channels.
*
* The following example shows how to send events on a channel:
*
* |[<!-- language="C" -->
* static FlEventChannel *channel = NULL;
* static gboolean send_events = FALSE;
*
* static void event_occurs_cb (FooEvent *event) {
* if (send_events) {
* g_autoptr(FlValue) message = foo_event_to_value (event);
* g_autoptr(GError) error = NULL;
* if (!fl_event_channel_send (channel, message, NULL, &error)) {
* g_warning ("Failed to send event: %s", error->message);
* }
* }
* }
*
* static FlMethodErrorResponse* listen_cb (FlEventChannel* channel,
* FlValue *args,
* gpointer user_data) {
* send_events = TRUE;
* return NULL;
* }
*
* static FlMethodErrorResponse* cancel_cb (GObject *object,
* FlValue *args,
* gpointer user_data) {
* send_events = FALSE;
* return NULL;
* }
*
* static void setup_channel () {
* g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new ();
* channel = fl_event_channel_new (messenger, "flutter/foo",
* FL_METHOD_CODEC (codec));
* fl_event_channel_set_stream_handlers (channel, listen_cb, cancel_cb,
* NULL, NULL);
* }
* ]|
*
* #FlEventChannel matches the EventChannel class in the Flutter
* services library.
*/
/**
* FlEventChannelHandler:
* @channel: an #FlEventChannel.
* @args: arguments passed from the Dart end of the channel.
* @user_data: (closure): data provided when registering this handler.
*
* Function called when the stream is listened to or cancelled.
*
* Returns: (transfer full): an #FlMethodErrorResponse or %NULL if no error.
*/
typedef
FlMethodErrorResponse
*
(
*
FlEventChannelHandler
)(
FlEventChannel
*
channel
,
FlValue
*
args
,
gpointer
user_data
);
/**
* fl_event_channel_new:
* @messenger: an #FlBinaryMessenger.
* @name: a channel name.
* @codec: the message codec.
*
* Creates an event channel. @codec must match the codec used on the Dart
* end of the channel.
*
* Returns: a new #FlEventChannel.
*/
FlEventChannel
*
fl_event_channel_new
(
FlBinaryMessenger
*
messenger
,
const
gchar
*
name
,
FlMethodCodec
*
codec
);
/**
* fl_event_channel_set_stream_handlers:
* @channel: an #FlEventChannel.
* @listen_handler: (allow-none): function to call when the Dart side of the
* channel starts listening to the stream.
* @cancel_handler: (allow-none): function to call when the Dart side of the
* channel cancels their subscription to the stream.
* @user_data: (closure): user data to pass to @listen_handler and
* @cancel_handler.
* @destroy_notify: (allow-none): a function which gets called to free
* @user_data, or %NULL.
*
* Sets the functions called when the Dart side requests the stream to start and
* finish.
*
* The handlers are removed if the channel is closed or is replaced by another
* handler, set @destroy_notify if you want to detect this.
*/
void
fl_event_channel_set_stream_handlers
(
FlEventChannel
*
channel
,
FlEventChannelHandler
listen_handler
,
FlEventChannelHandler
cancel_handler
,
gpointer
user_data
,
GDestroyNotify
destroy_notify
);
/**
* fl_event_channel_send:
* @channel: an #FlEventChannel.
* @event: event to send, must match what the #FlMethodCodec supports.
* @cancellable: (allow-none): a #GCancellable or %NULL.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Sends an event on the channel.
* Events should only be sent once the channel is being listened to.
*
* Returns: %TRUE if successful.
*/
gboolean
fl_event_channel_send
(
FlEventChannel
*
channel
,
FlValue
*
event
,
GCancellable
*
cancellable
,
GError
**
error
);
/**
* fl_event_channel_send_error:
* @channel: an #FlEventChannel.
* @code: error code to send.
* @message: error message to send.
* @details: (allow-none): error details or %NULL.
* @cancellable: (allow-none): a #GCancellable or %NULL.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Sends an error on the channel.
* Errors should only be sent once the channel is being listened to.
*
* Returns: %TRUE if successful.
*/
gboolean
fl_event_channel_send_error
(
FlEventChannel
*
channel
,
const
gchar
*
code
,
const
gchar
*
message
,
FlValue
*
details
,
GCancellable
*
cancellable
,
GError
**
error
);
/**
* fl_event_channel_send_end_of_stream:
* @channel: an #FlEventChannel.
* @cancellable: (allow-none): a #GCancellable or %NULL.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Indicates the stream has completed.
* It is a programmer error to send any more events after calling this.
*
* Returns: %TRUE if successful.
*/
gboolean
fl_event_channel_send_end_of_stream
(
FlEventChannel
*
channel
,
GCancellable
*
cancellable
,
GError
**
error
);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_EVENT_CHANNEL_H_
shell/platform/linux/public/flutter_linux/flutter_linux.h
浏览文件 @
5ca5e261
...
...
@@ -12,6 +12,7 @@
#include <flutter_linux/fl_binary_messenger.h>
#include <flutter_linux/fl_dart_project.h>
#include <flutter_linux/fl_engine.h>
#include <flutter_linux/fl_event_channel.h>
#include <flutter_linux/fl_json_message_codec.h>
#include <flutter_linux/fl_json_method_codec.h>
#include <flutter_linux/fl_message_codec.h>
...
...
shell/platform/linux/testing/mock_engine.cc
浏览文件 @
5ca5e261
...
...
@@ -294,6 +294,10 @@ FlutterEngineResult FlutterEngineSendPlatformMessage(
// Sends a null response.
send_response
(
engine
,
message
->
channel
,
message
->
response_handle
,
nullptr
,
0
);
}
else
if
(
strcmp
(
message
->
channel
,
"test/standard-event"
)
==
0
)
{
// Send a message so the shell can check the events sent.
send_message
(
engine
,
"test/events"
,
message
->
message
,
message
->
message_size
);
}
else
if
(
strcmp
(
message
->
channel
,
"test/failure"
)
==
0
)
{
// Generates an internal error.
return
kInternalInconsistency
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录