-
Notifications
You must be signed in to change notification settings - Fork 9.7k
WebView JavaScript channels - iOS implementation. #1139
Conversation
cyanglaz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic looks clean and I didn't find major issues. Added some thoughts about certain code.
| _javaScriptChannelNames = [[NSMutableSet alloc] init]; | ||
|
|
||
| WKUserContentController* userContentController = [[WKUserContentController alloc] init]; | ||
| if (![args[@"javascriptChannelNames"] isKindOfClass:[NSNull class]]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe check if [args[@"javascriptChannelNames"] is not nil as well?
if(![args[@"javascriptChannelNames"] && args[@"javascriptChannelNames"] isKindOfClass:[NSNull class]])
Or if we can be super careful here and add an NSArray type check as well, and then we can drop the NSNull check. Which i think is a better approach. I found some of the code in this classes that I did can be optimized this way as well.
Like below:
// initialize the object to be nil to avoid redundant NSNull check later.
NSArray * javaScriptChannelNames = nil;
// Check if the dictionary value is array class includes a nil check and a NSNull check as well as an array type check, which is cleaner.
if ([args[@"javascriptChannelNames"] isKindOfClass:[NSArray class]]) {
javaScriptChannelNames = args[@"javascriptChannelNames"];
}
// Since we initialized `javaScriptChannelNames` to be nil, this value can either be nil or an array. hence the only nil check, dropping the NSNull check.
if (javaScriptChannelNames) {
[_javaScriptChannelNames addObjectsFromArray:javaScriptChannelNames];
[self registerJavaScriptChannels:_javaScriptChannelNames controller:userContentController];
}
can even make it better if logically we do not want to update the _javaScriptChannelNames and register at all when the [args[@"javascriptChannelNames"] is an empty array.
if (javaScriptChannelNames.count > 0) {
[_javaScriptChannelNames addObjectsFromArray:javaScriptChannelNames];
[self registerJavaScriptChannels:_javaScriptChannelNames controller:userContentController];
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks good point about checking for NSArray.
I believe [foo isKindOfClass:[NSArray class]] doesn't evaluate to true if foo is nil, so I guess this check covers all cases?
As for short-circuiting when the array is empty, I would think the performance gain is insignificant in this case(which doesn't happen many times) so I would choose a little simpler code in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good. and YES [foo isKindOfClass:[NSArray class]] covers all cases.
| FlutterMethodChannel* _channel; | ||
| NSString* _currentUrl; | ||
| // The set of registered JavaScript channel names. | ||
| NSMutableSet* _javaScriptChannelNames; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use a property and be lazily initialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit over doing it this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lazy initializing the set can save memory (insignificant tho); In the case of this class, benefit is minimum since the set is used right after class initialization; I'm ok with not lazy initializing here.
Just a thought, if we do move the code [_javaScriptChannelNames addObjectsFromArray:javaScriptChannelNames]; out of the initiWithFrame method, then we can think about lazy initialize the _javaScriptChannelNames to save some memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't move it out of initWithFrame, as a set of JavaScript channels is passed with the creation params... we immediately need this field initialized...
mklim
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor nits from me, otherwise LGTM modulo any feedback from @cyanglaz .
Is it worth adding unit tests for the obj-c side on this as well?
amirh
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
@cyanglaz PTAL
| _javaScriptChannelNames = [[NSMutableSet alloc] init]; | ||
|
|
||
| WKUserContentController* userContentController = [[WKUserContentController alloc] init]; | ||
| if (![args[@"javascriptChannelNames"] isKindOfClass:[NSNull class]]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks good point about checking for NSArray.
I believe [foo isKindOfClass:[NSArray class]] doesn't evaluate to true if foo is nil, so I guess this check covers all cases?
As for short-circuiting when the array is empty, I would think the performance gain is insignificant in this case(which doesn't happen many times) so I would choose a little simpler code in this case.
| FlutterMethodChannel* _channel; | ||
| NSString* _currentUrl; | ||
| // The set of registered JavaScript channel names. | ||
| NSMutableSet* _javaScriptChannelNames; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit over doing it this way?
|
@mklim for unit tests - ok if I wait to see in what form our e2e plugin test harness manifests? |
Totally. Just a suggestion. |
|
Looks like the build-ipas task has successfully completed on Cirrus but Github didn't pick that up for some reason.. going to land on "yellow" because this is really green. |
iOS implementation of the method channel API for adding and removing JavaScript channels. flutter#1116 adds the Dart side support, the current PR will land first. flutter/flutter#24837
…)" This reverts commit 7aac329.
| @"Can't send a message to an unitialized JavaScript channel."); | ||
| NSDictionary* arguments = @{ | ||
| @"channel" : _javaScriptChannelName, | ||
| @"message" : [NSString stringWithFormat:@"%@", message.body] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if native send json string back flutter, it will got a string that hard to serialized like below.
{
action = do_somethineg;
data = {
key_1 = some_info;
key_2 = "some_info";
};
timestamp = 1570005270866;
token = "jwt_token";
}is it possible to add code to serialize NSDictionary and NSArray before send message.body:
- (NSString *)messageFromBody:(NSString *)body {
NSString *message;
if ([body isKindOfClass:[NSDictionary class]] ||
[body isKindOfClass:[NSArray class]]) {
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:body
options:NSJSONWritingPrettyPrinted
error:nil];
message = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
if (message.length <= 0) {
message = [NSString stringWithFormat:@"%@", body];
}
return message;
}
...
NSDictionary* arguments = @{
@"channel" : _javaScriptChannelName,
@"message" : [self messageFromBody: message.body]
};Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind filing this as an issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya, i'm created HERE

Platform implementation of the method channel API for adding and removing JavaScript channels.
#1116 adds the Dart side support, the current PR will land first.
flutter/flutter#24837