Skip to content

Commit a7c25b3

Browse files
cloudwebrtcstuartmorgan
authored andcommitted
[macOS] Add FLEEventChannel (#174)
Adds more parity with mobile Flutter plugin APIs. Fixes #173
1 parent 9098be0 commit a7c25b3

File tree

4 files changed

+218
-0
lines changed

4 files changed

+218
-0
lines changed

library/macos/FLEEventChannel.h

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#import <Foundation/Foundation.h>
16+
17+
#import "FLEBinaryMessenger.h"
18+
#import "FLEMethodCodec.h"
19+
20+
/**
21+
* An event sink callback.
22+
*
23+
* @param event The event.
24+
*/
25+
typedef void (^FLEEventSink)(id _Nullable event);
26+
27+
/**
28+
* A constant used with `FLEEventChannel` to indicate end of stream.
29+
*/
30+
extern NSString const *_Nonnull FLEEndOfEventStream;
31+
32+
/**
33+
* A strategy for exposing an event stream to the Flutter side.
34+
*/
35+
@protocol FLEStreamHandler
36+
37+
/**
38+
* Sets up an event stream and begins emitting events.
39+
*
40+
* Invoked when the first listener is registered with the Stream associated to
41+
* this channel on the Flutter side.
42+
*
43+
* @param arguments Arguments for the stream.
44+
* @param events A callback to asynchronously emit events. Invoke the
45+
* callback with a `FLEMethodError` to emit an error event. Invoke the
46+
* callback with `FLEEndOfEventStream` to indicate that no more
47+
* events will be emitted. Any other value, including `nil` are emitted as
48+
* successful events.
49+
* @return A FLEMethodError instance, if setup fails.
50+
*/
51+
- (nullable FLEMethodError *)onListenWithArguments:(nullable id)arguments
52+
eventSink:(FLEEventSink _Nonnull)events;
53+
54+
/**
55+
* Tears down an event stream.
56+
*
57+
* Invoked when the last listener is deregistered from the Stream associated to
58+
* this channel on the Flutter side.
59+
*
60+
* The channel implementation may call this method with `nil` arguments
61+
* to separate a pair of two consecutive set up requests. Such request pairs
62+
* may occur during Flutter hot restart.
63+
*
64+
* @param arguments Arguments for the stream.
65+
* @return A FLEMethodError instance, if teardown fails.
66+
*/
67+
- (nullable FLEMethodError *)onCancelWithArguments:(nullable id)arguments;
68+
69+
@end
70+
71+
/**
72+
* A channel for communicating with the Flutter side using event streams.
73+
*/
74+
@interface FLEEventChannel : NSObject
75+
76+
/**
77+
* Creates a `FLEEventChannel` with the specified name and binary messenger.
78+
*
79+
* The channel name logically identifies the channel; identically named channels
80+
* interfere with each other's communication.
81+
*
82+
* The binary messenger is a facility for sending raw, binary messages to the
83+
* Flutter side.
84+
*
85+
* The channel uses `FLEMethodCodec` to decode stream setup and
86+
* teardown requests, and to encode event envelopes.
87+
*
88+
* @param name The channel name.
89+
* @param messenger The binary messenger.
90+
* @param codec The method codec.
91+
* @return A new channel.
92+
*/
93+
+ (nonnull instancetype)eventChannelWithName:(nonnull NSString *)name
94+
binaryMessenger:(nonnull id<FLEBinaryMessenger>)messenger
95+
codec:(nonnull id<FLEMethodCodec>)codec;
96+
97+
/**
98+
* Registers a handler for stream setup requests from the Flutter side.
99+
*
100+
* Replaces any existing handler. Use a `nil` handler for unregistering the
101+
* existing handler.
102+
*
103+
* @param handler The stream handler.
104+
*/
105+
- (void)setStreamHandler:(nullable id<FLEStreamHandler>)handler;
106+
107+
@end

library/macos/FLEEventChannel.m

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#import "FLEEventChannel.h"
16+
17+
NSString const *FLEEndOfEventStream = @"EndOfEventStream";
18+
19+
@implementation FLEEventChannel {
20+
NSString *_name;
21+
__weak id<FLEBinaryMessenger> _messenger;
22+
id<FLEMethodCodec> _codec;
23+
}
24+
25+
+ (instancetype)eventChannelWithName:(NSString *)name
26+
binaryMessenger:(id<FLEBinaryMessenger>)messenger
27+
codec:(id<FLEMethodCodec>)codec {
28+
return [[[self class] alloc] initWithName:name binaryMessenger:messenger codec:codec];
29+
}
30+
31+
- (instancetype)initWithName:(NSString *)name
32+
binaryMessenger:(id<FLEBinaryMessenger>)messenger
33+
codec:(id<FLEMethodCodec>)codec {
34+
self = [super init];
35+
if (self) {
36+
_name = [name copy];
37+
_messenger = messenger;
38+
_codec = codec;
39+
}
40+
return self;
41+
}
42+
43+
- (void)setStreamHandler:(NSObject<FLEStreamHandler> *)handler {
44+
if (!handler) {
45+
[_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
46+
return;
47+
}
48+
49+
id<FLEMethodCodec> codec = _codec;
50+
__weak id<FLEBinaryMessenger> messenger = _messenger;
51+
NSString *name = _name;
52+
FLEEventSink eventSink = ^(id event) {
53+
if (event == FLEEndOfEventStream) {
54+
[messenger sendOnChannel:name message:nil];
55+
} else if ([event isKindOfClass:[FLEMethodError class]]) {
56+
[messenger sendOnChannel:name message:[codec encodeErrorEnvelope:(FLEMethodError *)event]];
57+
} else {
58+
[messenger sendOnChannel:name message:[codec encodeSuccessEnvelope:event]];
59+
}
60+
};
61+
62+
__block FLEEventSink currentSink = nil;
63+
FLEBinaryMessageHandler messageHandler = ^(NSData *message, FLEBinaryReply callback) {
64+
FLEMethodCall *call = [codec decodeMethodCall:message];
65+
if ([call.methodName isEqual:@"listen"]) {
66+
if (currentSink) {
67+
FLEMethodError *error = [handler onCancelWithArguments:nil];
68+
if (error) {
69+
NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message,
70+
error.details);
71+
}
72+
}
73+
currentSink = eventSink;
74+
FLEMethodError *error = [handler onListenWithArguments:call.arguments eventSink:currentSink];
75+
if (error) {
76+
callback([codec encodeErrorEnvelope:error]);
77+
} else {
78+
callback([codec encodeSuccessEnvelope:nil]);
79+
}
80+
} else if ([call.methodName isEqual:@"cancel"]) {
81+
if (!currentSink) {
82+
callback([codec
83+
encodeErrorEnvelope:[[FLEMethodError alloc] initWithCode:@"error"
84+
message:@"No active stream to cancel"
85+
details:nil]]);
86+
return;
87+
}
88+
currentSink = nil;
89+
FLEMethodError *error = [handler onCancelWithArguments:call.arguments];
90+
if (error) {
91+
callback([codec encodeErrorEnvelope:error]);
92+
} else {
93+
callback([codec encodeSuccessEnvelope:nil]);
94+
}
95+
} else {
96+
callback(nil);
97+
}
98+
};
99+
[_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];
100+
}
101+
102+
@end

library/macos/FlutterEmbedderMac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#import "FLEBasicMessageChannel.h"
1616
#import "FLEBinaryMessenger.h"
17+
#import "FLEEventChannel.h"
1718
#import "FLEJSONMessageCodec.h"
1819
#import "FLEJSONMethodCodec.h"
1920
#import "FLEMessageCodec.h"

library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
1E2492411FCF50BE00DD3BBB /* FlutterEmbedderMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E2492371FCF50BE00DD3BBB /* FlutterEmbedderMac.h */; settings = {ATTRIBUTES = (Public, ); }; };
3131
1EEF8E071FD1F0C300DD563C /* FLEView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EEF8E051FD1F0C300DD563C /* FLEView.h */; settings = {ATTRIBUTES = (Public, ); }; };
3232
1EEF8E081FD1F0C300DD563C /* FLEView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEF8E061FD1F0C300DD563C /* FLEView.m */; };
33+
2CCADF9A21C74690001B4026 /* FLEEventChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CCADF9821C74690001B4026 /* FLEEventChannel.m */; };
34+
2CCADF9B21C74690001B4026 /* FLEEventChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CCADF9921C74690001B4026 /* FLEEventChannel.h */; settings = {ATTRIBUTES = (Public, ); }; };
3335
3389A6872159359200A27898 /* FLEBinaryMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3389A6862159359200A27898 /* FLEBinaryMessenger.h */; settings = {ATTRIBUTES = (Public, ); }; };
3436
3389A68D215949CB00A27898 /* FLEMethodError.m in Sources */ = {isa = PBXBuildFile; fileRef = 3389A68C215949CB00A27898 /* FLEMethodError.m */; };
3537
3389A68F215949D600A27898 /* FLEMethodError.h in Headers */ = {isa = PBXBuildFile; fileRef = 3389A68E215949D600A27898 /* FLEMethodError.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -90,6 +92,8 @@
9092
1E2492381FCF50BE00DD3BBB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
9193
1EEF8E051FD1F0C300DD563C /* FLEView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEView.h; sourceTree = "<group>"; };
9294
1EEF8E061FD1F0C300DD563C /* FLEView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEView.m; sourceTree = "<group>"; };
95+
2CCADF9821C74690001B4026 /* FLEEventChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEEventChannel.m; sourceTree = "<group>"; };
96+
2CCADF9921C74690001B4026 /* FLEEventChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEEventChannel.h; sourceTree = "<group>"; };
9397
3389A6862159359200A27898 /* FLEBinaryMessenger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEBinaryMessenger.h; sourceTree = "<group>"; };
9498
3389A68C215949CB00A27898 /* FLEMethodError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEMethodError.m; sourceTree = "<group>"; };
9599
3389A68E215949D600A27898 /* FLEMethodError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEMethodError.h; sourceTree = "<group>"; };
@@ -132,6 +136,7 @@
132136
1E2492371FCF50BE00DD3BBB /* FlutterEmbedderMac.h */,
133137
1E2492451FCF536200DD3BBB /* Public */,
134138
33C0FA1821B845EF008F8959 /* FLEBasicMessageChannel.m */,
139+
2CCADF9821C74690001B4026 /* FLEEventChannel.m */,
135140
33C0FA1C21B84810008F8959 /* FLEJSONMessageCodec.m */,
136141
33A87EB520F6BCDB0086D21D /* FLEJSONMethodCodec.m */,
137142
33C0FA2521B84AA4008F8959 /* FLEMethodCall.m */,
@@ -163,6 +168,7 @@
163168
children = (
164169
33C0FA1921B845F0008F8959 /* FLEBasicMessageChannel.h */,
165170
3389A6862159359200A27898 /* FLEBinaryMessenger.h */,
171+
2CCADF9921C74690001B4026 /* FLEEventChannel.h */,
166172
33C0FA1E21B84810008F8959 /* FLEJSONMessageCodec.h */,
167173
33C0FA1D21B84810008F8959 /* FLEJSONMethodCodec.h */,
168174
33C0FA1F21B84810008F8959 /* FLEMessageCodec.h */,
@@ -197,6 +203,7 @@
197203
files = (
198204
33C0FA2621B84AA4008F8959 /* FLEMethodCall.h in Headers */,
199205
1E24923B1FCF50BE00DD3BBB /* FLEPlugin.h in Headers */,
206+
2CCADF9B21C74690001B4026 /* FLEEventChannel.h in Headers */,
200207
3389A6872159359200A27898 /* FLEBinaryMessenger.h in Headers */,
201208
33D7B59920A4F54400296EFC /* FLEMethodChannel.h in Headers */,
202209
1E24923F1FCF50BE00DD3BBB /* FLEViewController.h in Headers */,
@@ -317,6 +324,7 @@
317324
1E24923E1FCF50BE00DD3BBB /* FLETextInputPlugin.m in Sources */,
318325
1EEF8E081FD1F0C300DD563C /* FLEView.m in Sources */,
319326
33A87EB720F6BCDB0086D21D /* FLEJSONMethodCodec.m in Sources */,
327+
2CCADF9A21C74690001B4026 /* FLEEventChannel.m in Sources */,
320328
AA8AE8BA1FD948BA00B6FB31 /* FLETextInputModel.m in Sources */,
321329
);
322330
runOnlyForDeploymentPostprocessing = 0;

0 commit comments

Comments
 (0)