From d8672baaa265af69650dee6e0d9b40767f42effa Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 30 Oct 2018 18:04:18 -0700 Subject: [PATCH] Ensure Simulator publishes mDNS records (#6696) * Ensure Simulator publishes mDNS records on loopback interface. --- .../Source/FlutterObservatoryPublisher.mm | 81 ++++++++++++++++--- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.mm b/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.mm index 495a7c72ac8f3..73490540a61b9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.mm @@ -4,6 +4,16 @@ #define FML_USED_ON_EMBEDDER +#import + +// NSNetService works fine on physical devices, but doesn't expose the services to regular mDNS +// queries on the Simulator. We can work around this by using the lower level C API, but that's +// only available from iOS 9.3+/macOS 10.11.4+. +#if TARGET_IPHONE_SIMULATOR +#include // nogncheck +#include // nogncheck +#endif // TARGET_IPHONE_SIMLUATOR + #import "FlutterObservatoryPublisher.h" #include "flutter/fml/logging.h" @@ -26,7 +36,11 @@ @interface FlutterObservatoryPublisher () @end @implementation FlutterObservatoryPublisher { +#if TARGET_IPHONE_SIMULATOR + DNSServiceRef _dnsServiceRef; +#else // TARGET_IPHONE_SIMULATOR fml::scoped_nsobject _netService; +#endif // TARGET_IPHONE_SIMULATOR blink::DartServiceIsolate::CallbackHandle _callbackHandle; std::unique_ptr> _weakFactory; @@ -54,14 +68,29 @@ - (instancetype)init { } - (void)dealloc { +#if TARGET_IPHONE_SIMULATOR + if (_dnsServiceRef) { + DNSServiceRefDeallocate(_dnsServiceRef); + _dnsServiceRef = NULL; + } +#else // TARGET_IPHONE_SIMULATOR [_netService.get() stop]; +#endif // TARGET_IPHONE_SIMULATOR + blink::DartServiceIsolate::RemoveServerStatusCallback(std::move(_callbackHandle)); [super dealloc]; } - (void)publishServiceProtocolPort:(std::string)uri { +#if TARGET_IPHONE_SIMULATOR + if (_dnsServiceRef) { + DNSServiceRefDeallocate(_dnsServiceRef); + _dnsServiceRef = NULL; + } +#else // TARGET_IPHONE_SIMULATOR + [_netService.get() stop]; +#endif // TARGET_IPHONE_SIMULATOR if (uri.empty()) { - [_netService.get() stop]; return; } // uri comes in as something like 'http://127.0.0.1:XXXXX/' where XXXXX is the port @@ -69,28 +98,37 @@ - (void)publishServiceProtocolPort:(std::string)uri { NSURL* url = [[[NSURL alloc] initWithString:[NSString stringWithUTF8String:uri.c_str()]] autorelease]; - // DNS name has to be a max of 63 bytes. Prefer to cut off the app name rather than - // the device hostName. e.g. 'io.flutter.example@someones-iphone', or - // 'ongAppNameBecauseThisCouldHappenAtSomePoint@somelongname-iphone' - NSString* serviceName = [NSString - stringWithFormat:@"%@@%@", - [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"], - [NSProcessInfo processInfo].hostName]; - if ([serviceName length] > 63) { - serviceName = [serviceName substringFromIndex:[serviceName length] - 63]; - } + NSString* serviceName = + [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]; +#if TARGET_IPHONE_SIMULATOR + DNSServiceFlags flags = kDNSServiceFlagsDefault; + uint32_t interfaceIndex = if_nametoindex("lo0"); + const char* registrationType = "_dartobservatory._tcp"; + const char* domain = "local."; // default domain + uint16_t port = [[url port] intValue]; + + int err = DNSServiceRegister(&_dnsServiceRef, flags, interfaceIndex, [serviceName UTF8String], + registrationType, domain, NULL, htons(port), 0, NULL, + registrationCallback, NULL); + + if (err != 0) { + FML_LOG(ERROR) << "Failed to register observatory port with mDNS."; + } else { + DNSServiceProcessResult(_dnsServiceRef); + } +#else // TARGET_IPHONE_SIMULATOR _netService.reset([[NSNetService alloc] initWithDomain:@"local." type:@"_dartobservatory._tcp." name:serviceName port:[[url port] intValue]]); - [_netService.get() setDelegate:self]; [_netService.get() publish]; +#endif // TARGET_IPHONE_SIMULATOR } - (void)netServiceDidPublish:(NSNetService*)sender { - FML_DLOG(INFO) << "FlutterObservatoryPublisher is ready!"; + FML_LOG(INFO) << "FlutterObservatoryPublisher is ready!"; } - (void)netService:(NSNetService*)sender didNotPublish:(NSDictionary*)errorDict { @@ -98,6 +136,23 @@ - (void)netService:(NSNetService*)sender didNotPublish:(NSDictionary*)errorDict "network settings and relaunch the application."; } +#if TARGET_IPHONE_SIMULATOR +static void DNSSD_API registrationCallback(DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char* name, + const char* regType, + const char* domain, + void* context) { + if (errorCode == kDNSServiceErr_NoError) { + FML_LOG(ERROR) << "FlutterObservatoryPublisher is ready!"; + } else { + FML_LOG(ERROR) << "Could not register as server for FlutterObservatoryPublisher. Check your " + "network settings and relaunch the application."; + } +} +#endif // TARGET_IPHONE_SIMULATOR + #endif // FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && FLUTTER_RUNTIME_MODE != // FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE