Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 4cc0f56

Browse files
committed
Made JavaScriptChannelRegistry available
1 parent 76b2a02 commit 4cc0f56

File tree

6 files changed

+201
-0
lines changed

6 files changed

+201
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:meta/meta.dart';
6+
7+
import 'types/javascript_channel.dart';
8+
import 'types/javascript_message.dart';
9+
10+
/// Utility class for managing named JavaScript channels and forwarding incoming
11+
/// messages on the correct channel.
12+
@sealed
13+
class JavaScriptChannelRegistry {
14+
/// Constructs a [JavaScriptChannelRegistry] initializing it with the given
15+
/// set of [JavaScriptChannel]s.
16+
JavaScriptChannelRegistry(Set<JavaScriptChannel>? channels) {
17+
updateJavaScriptChannelsFromSet(channels);
18+
}
19+
20+
/// Maps a channel name to a channel.
21+
final Map<String, JavaScriptChannel> channels = <String, JavaScriptChannel>{};
22+
23+
/// Invoked when a JavaScript channel message is received.
24+
void onJavaScriptChannelMessage(String channel, String message) {
25+
final JavaScriptChannel? javaScriptChannel = channels[channel];
26+
27+
if (javaScriptChannel == null) {
28+
throw ArgumentError('No channel registered with name $channel.');
29+
}
30+
31+
javaScriptChannel.onMessageReceived(JavaScriptMessage(message: message));
32+
}
33+
34+
/// Updates the set of [JavaScriptChannel]s with the new set.
35+
void updateJavaScriptChannelsFromSet(Set<JavaScriptChannel>? channels) {
36+
this.channels.clear();
37+
if (channels == null) {
38+
return;
39+
}
40+
41+
for (final JavaScriptChannel channel in channels) {
42+
this.channels[channel.name] = channel;
43+
}
44+
}
45+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'javascript_message.dart';
6+
7+
/// Callback type for handling messages sent from JavaScript running in a web view.
8+
typedef JavaScriptMessageHandler = void Function(JavaScriptMessage message);
9+
10+
final RegExp _validChannelNames = RegExp(r'^[a-zA-Z_][a-zA-Z0-9_]*$');
11+
12+
/// A named channel for receiving messaged from JavaScript code running inside a web view.
13+
class JavaScriptChannel {
14+
/// Constructs a JavaScript channel.
15+
///
16+
/// The parameters `name` and `onMessageReceived` must not be null.
17+
JavaScriptChannel({
18+
required this.name,
19+
required this.onMessageReceived,
20+
}) : assert(name != null),
21+
assert(onMessageReceived != null),
22+
assert(_validChannelNames.hasMatch(name));
23+
24+
/// The channel's name.
25+
///
26+
/// The name must start with a letter or underscore(_), followed by any
27+
/// combination of alphabetic characters plus digits.
28+
///
29+
/// Note that any JavaScript existing `window` property with this name will be
30+
/// overriden.
31+
final String name;
32+
33+
/// A callback that's invoked when a message is received through the channel.
34+
final JavaScriptMessageHandler onMessageReceived;
35+
}

packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/types.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
export 'javascript_channel.dart';
56
export 'javascript_message.dart';
67
export 'javascript_mode.dart';
78
export 'load_request_params.dart';

packages/webview_flutter/webview_flutter_platform_interface/lib/v4/webview_flutter_platform_interface.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
export 'src/javascript_channel_registry.dart';
56
export 'src/navigation_callback_delegate.dart';
67
export 'src/types/types.dart';
78
export 'src/webview_controller_delegate.dart';

packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ environment:
1313
dependencies:
1414
flutter:
1515
sdk: flutter
16+
meta: ^1.7.0
1617
plugin_platform_interface: ^2.1.0
1718

1819
dev_dependencies:
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter_test/flutter_test.dart';
6+
import 'package:webview_flutter_platform_interface/v4/src/javaScript_channel_registry.dart';
7+
import 'package:webview_flutter_platform_interface/v4/src/types/types.dart';
8+
9+
void main() {
10+
final Map<String, String> _log = <String, String>{};
11+
final Set<JavaScriptChannel> _channels = <JavaScriptChannel>{
12+
JavaScriptChannel(
13+
name: 'js_channel_1',
14+
onMessageReceived: (JavaScriptMessage message) =>
15+
_log['js_channel_1'] = message.message,
16+
),
17+
JavaScriptChannel(
18+
name: 'js_channel_2',
19+
onMessageReceived: (JavaScriptMessage message) =>
20+
_log['js_channel_2'] = message.message,
21+
),
22+
JavaScriptChannel(
23+
name: 'js_channel_3',
24+
onMessageReceived: (JavaScriptMessage message) =>
25+
_log['js_channel_3'] = message.message,
26+
),
27+
};
28+
29+
tearDown(() {
30+
_log.clear();
31+
});
32+
33+
test('ctor should initialize with channels.', () {
34+
final JavaScriptChannelRegistry registry =
35+
JavaScriptChannelRegistry(_channels);
36+
37+
expect(registry.channels.length, 3);
38+
for (final JavaScriptChannel channel in _channels) {
39+
expect(registry.channels[channel.name], channel);
40+
}
41+
});
42+
43+
test('onJavaScriptChannelMessage should forward message on correct channel.',
44+
() {
45+
final JavaScriptChannelRegistry registry =
46+
JavaScriptChannelRegistry(_channels);
47+
48+
registry.onJavaScriptChannelMessage(
49+
'js_channel_2',
50+
'test message on channel 2',
51+
);
52+
53+
expect(
54+
_log,
55+
containsPair(
56+
'js_channel_2',
57+
'test message on channel 2',
58+
));
59+
});
60+
61+
test(
62+
'onJavaScriptChannelMessage should throw ArgumentError when message arrives on non-existing channel.',
63+
() {
64+
final JavaScriptChannelRegistry registry =
65+
JavaScriptChannelRegistry(_channels);
66+
67+
expect(
68+
() => registry.onJavaScriptChannelMessage(
69+
'js_channel_4',
70+
'test message on channel 2',
71+
),
72+
throwsA(
73+
isA<ArgumentError>().having((ArgumentError error) => error.message,
74+
'message', 'No channel registered with name js_channel_4.'),
75+
));
76+
});
77+
78+
test(
79+
'updateJavaScriptChannelsFromSet should clear all channels when null is supplied.',
80+
() {
81+
final JavaScriptChannelRegistry registry =
82+
JavaScriptChannelRegistry(_channels);
83+
84+
expect(registry.channels.length, 3);
85+
86+
registry.updateJavaScriptChannelsFromSet(null);
87+
88+
expect(registry.channels, isEmpty);
89+
});
90+
91+
test('updateJavaScriptChannelsFromSet should update registry with new set.',
92+
() {
93+
final JavaScriptChannelRegistry registry =
94+
JavaScriptChannelRegistry(_channels);
95+
96+
expect(registry.channels.length, 3);
97+
98+
final Set<JavaScriptChannel> newChannels = <JavaScriptChannel>{
99+
JavaScriptChannel(
100+
name: 'new_js_channel_1',
101+
onMessageReceived: (JavaScriptMessage message) =>
102+
_log['new_js_channel_1'] = message.message,
103+
),
104+
JavaScriptChannel(
105+
name: 'new_js_channel_2',
106+
onMessageReceived: (JavaScriptMessage message) =>
107+
_log['new_js_channel_2'] = message.message,
108+
),
109+
};
110+
111+
registry.updateJavaScriptChannelsFromSet(newChannels);
112+
113+
expect(registry.channels.length, 2);
114+
for (final JavaScriptChannel channel in newChannels) {
115+
expect(registry.channels[channel.name], channel);
116+
}
117+
});
118+
}

0 commit comments

Comments
 (0)