-
Notifications
You must be signed in to change notification settings - Fork 6k
Fix mDNS for iOS13 #13451
Fix mDNS for iOS13 #13451
Conversation
stuartmorgan-g
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.
I'm not really familiar with these APIs so I don't think I can be of much help.
I will say at a high level that if you are going to have this much of the implementation in branches that use the same condition (OS version in this case) it would be much cleaner to have two concrete implementations of an internal interface, one for each path, and then just have the primary class instantiate the right one at initialization, eliminating all the other branching. That avoids weirdness like ivars that are always there but never used in one implementation.
|
Adding @jmagman for some extra Objective C review. Sorry the diff is so ugly now. I refactored this to avoid all of the |
| #include <net/if.h> // nogncheck | ||
| #endif // TARGET_IPHONE_SIMULATOR | ||
| #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE || \ | ||
| FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE |
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.
Does FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE still exist? Should this be FLUTTER_RUNTIME_MODE_JIT_RELEASE? It looks like FLUTTER_RELEASE might do the right thing. That is:
#if FLUTTER_RELEASE
...
#else
...
#endif
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.
Ahh nice one. No, I don't think dynamic is anymore.
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.
I've updated config.gni to set those defines (which is where we set all the other runtime related defines already) instead of in a separate header. /cc @jonahwilliams
|
I've potentially located an iOS 8.1 device to test with. Looking at analytics, we have a very very small number of people who are trying to use |
I don't think you should need a real device. For availability purposes you can build against that SDK and see if you get any warnings/errors. You can copy that SDK to your current version of Xcode, or actually run in Xcode 6, if that even works anymore. |
|
@jmagman I wasn't quite able to get that to work, but I did get things running with an old iPhone on 8.1 - I do see this in the console: But otherwise things are good. Except that mDNS doesn't work at all on that phone (either with the current approach or the previous one), but log scanning does. |
| } | ||
|
|
||
| - (NSString*)serviceName { | ||
| return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]; |
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.
Does NSBundle.mainBundle.bundleIdentifier have what you need?
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.
Done
| // Remove leading "/" | ||
| path = path.substr(1); |
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 we need to use std::string here? Since it's Obj-C -> Obj-C it would be nice to not need to translate between unless there's a good reason.
NSString *path = [url.path stringByReplacingOccurrencesOfString:@"/" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, 1)];
// OR if you don't want any trailing / either
NSString *path = [url.path stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
NSData *data = [path dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary<NSString*,NSData*> *authCode = @{
@"authCode" : data
};
return [NSNetService dataFromTXTRecordDictionary:authCode];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.
Done - slightly different than your suggestion but yeah, that was legacy code from something else.
| #if FLUTTER_RELEASE | ||
|
|
||
| #import "FlutterObservatoryPublisher.h" | ||
| @implementation FlutterObservatoryPublisher { |
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.
Remove empty {}
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.
Done
| const char* registrationType = "_dartobservatory._tcp"; | ||
| const char* domain = "local."; // default domain | ||
| uint16_t port = [[_url port] intValue]; | ||
| uint16_t port = [[url port] intValue]; |
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.
-unsignedShortValue
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.
Done
| // it as a txt record so flutter tools can establish a connection. | ||
| NSString* path = [[url path] substringFromIndex:MIN(1, [[url path] length])]; | ||
| NSData* pathData = [path dataUsingEncoding:NSUTF8StringEncoding]; | ||
| NSDictionary* txtDict = @{ |
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.
Let's use generics on collections:
NSDictionary<NSString*, NSData*>
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.
Done
| } | ||
|
|
||
| - (instancetype)init { | ||
| @synthesize url; |
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 need this @synthesize?
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.
AFAIK yes - because it's from a protocol and not autosynthesized. At any rate, doesn't compile without this.
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.
Oh that make sense.
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.
I think this needs an ivar, how is this not crashing when you use url?
@implementation ObservatoryDNSServiceDelegate {
fml::scoped_nsobject<FlutterObservatoryPublisher> _owner;
DNSServiceRef _dnsServiceRef;
fml::scoped_nsobject<NSURL> _url;
}
@synthesize url = _url;self.url.reset([[[NSURL alloc] initWithString:uri] retain]);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.
From our conversation offline - this doesn't work.
I think this is because fml::scoped_nsobject is a stack allocated C++ object, rather than a pointer or a NSObject. It makes things look really funky compared to how this would be done if we were using ARC (where the property/ivar would just be something like a raw NSURL*). But this syntax compiles and runs.
| @"authCode" : pathData, | ||
| }; | ||
| NSData* txtData = [NSNetService dataFromTXTRecordDictionary:txtDict]; | ||
| url.reset([[[NSURL alloc] initWithString:uri] retain]); |
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.
self.url, or am I missing where this url is coming from?
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.
Done
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.
Undone haha.
url is the synethsized property from the protocol right?
| [weak = _weakFactory->GetWeakPtr(), | ||
| runner = fml::MessageLoop::GetCurrent().GetTaskRunner()](const std::string& uri) { | ||
| if (!uri.empty()) { | ||
| runner->PostTask([weak, uri]() { |
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.
Make a strong pointer in the block so it doesn't dealloc between the null check and the usage
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.
This is the pattern we use all over the place for fml::WeakPtrs - I think it's ok. We can't really get a "strong" reference because we're weakly holding it.
| } | ||
|
|
||
| - (NSURL*)url { | ||
| return [_delegate.get().url copy]; |
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.
I don't think you need a copy since it's not mutable. [_delegate.get().url autorelease]?
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.
And I think it causes an analyzer warning?
Potential leak of an object of type 'id'
Object leaked: allocated object of type 'id' is returned from a method whose name ('url') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa
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.
Done
jmagman
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.
I still find it difficult to read the juxtaposition between Obj-C and C++ memory management, so thanks for your patience, @dnfield. But as far as I can tell, the .mm part LGTM.
Fixes flutter/flutter#41085
Tested manually.
iOS 13 has broken the way we use NSNetService. This uses the C API introduced in iOS 9.3 and works locally.
I've tried to use availability guards to make this still support older versions, but I'm not clear at all on whether this is actually the right way to do things for iOS < 9.3 - and I can't track down a device to test it with. Would be happy for pointers on that.
Also, this code cannot make it into a release build - so if it is wrong, it should only impact developers trying to test on iOS < 9.3.
@stuartmorgan might have good ideas here but he's OOO for a while to come.