5 #define FML_USED_ON_EMBEDDER
12 - (instancetype)initWithEnableVMServicePublication:(BOOL)enableVMServicePublication {
17 #else // FLUTTER_RELEASE
19 #import <TargetConditionals.h>
42 #include "flutter/fml/logging.h"
43 #include "flutter/fml/memory/weak_ptr.h"
44 #include "flutter/fml/message_loop.h"
45 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
46 #include "flutter/runtime/dart_service_isolate.h"
49 - (void)publishServiceProtocolPort:(NSURL*)uri;
54 + (NSData*)createTxtData:(NSURL*)url;
56 @property(readonly,
class) NSString* serviceName;
57 @property(readonly) fml::scoped_nsobject<NSObject<FlutterDartVMServicePublisherDelegate>> delegate;
58 @property(nonatomic, readwrite) NSURL*
url;
59 @property(readonly) BOOL enableVMServicePublication;
67 DNSServiceRef _dnsServiceRef;
73 DNSServiceRefDeallocate(_dnsServiceRef);
74 _dnsServiceRef = NULL;
82 - (void)publishServiceProtocolPort:(NSURL*)url {
84 FML_LOG(INFO) <<
"Publish Service Protocol Port";
85 DNSServiceFlags flags = kDNSServiceFlagsDefault;
86 #if TARGET_IPHONE_SIMULATOR
88 uint32_t interfaceIndex = if_nametoindex(
"lo0");
89 #else // TARGET_IPHONE_SIMULATOR
91 uint32_t interfaceIndex = 0;
92 #endif // TARGET_IPHONE_SIMULATOR
93 const char* registrationType =
"_dartVmService._tcp";
94 const char* legacyRegistrationType =
"_dartobservatory._tcp";
96 const char* domain =
"local.";
97 uint16_t port = [[url port] unsignedShortValue];
100 int err = DNSServiceRegister(&_dnsServiceRef, flags, interfaceIndex,
102 registrationType, domain, NULL, htons(port), txtData.length,
103 txtData.bytes, RegistrationCallback, NULL);
106 DNSServiceSetDispatchQueue(_dnsServiceRef, dispatch_get_main_queue());
116 legacyRegistrationType, domain, NULL, htons(port), txtData.length,
117 txtData.bytes, RegistrationCallback, NULL);
124 FML_LOG(ERROR) <<
"Failed to register Dart VM Service port with mDNS with error " << err <<
".";
125 if (@available(iOS 14.0, *)) {
126 FML_LOG(ERROR) <<
"On iOS 14+, local network broadcast in apps need to be declared in "
127 <<
"the app's Info.plist. Debug and profile Flutter apps and modules host "
128 <<
"VM services on the local network to support debugging features such "
129 <<
"as hot reload and DevTools. To make your Flutter app or module "
130 <<
"attachable and debuggable, add a '" << registrationType <<
"' value "
131 <<
"to the 'NSBonjourServices' key in your Info.plist for the Debug/"
132 <<
"Profile configurations. "
133 <<
"For more information, see "
134 <<
"https://flutter.dev/docs/development/add-to-app/ios/"
135 "project-setup#local-network-privacy-permissions";
139 static void DNSSD_API RegistrationCallback(DNSServiceRef sdRef,
140 DNSServiceFlags flags,
141 DNSServiceErrorType errorCode,
146 if (errorCode == kDNSServiceErr_NoError) {
147 FML_DLOG(INFO) <<
"FlutterDartVMServicePublisher is ready!";
148 }
else if (errorCode == kDNSServiceErr_PolicyDenied) {
150 <<
"Could not register as server for FlutterDartVMServicePublisher, permission "
151 <<
"denied. Check your 'Local Network' permissions for this app in the Privacy section of "
152 <<
"the system Settings.";
154 FML_LOG(ERROR) <<
"Could not register as server for FlutterDartVMServicePublisher. Check your "
155 "network settings and relaunch the application.";
162 flutter::DartServiceIsolate::CallbackHandle _callbackHandle;
163 std::unique_ptr<fml::WeakPtrFactory<FlutterDartVMServicePublisher>>
_weakFactory;
166 - (instancetype)initWithEnableVMServicePublication:(BOOL)enableVMServicePublication {
168 NSAssert(
self,
@"Super must not return null on init.");
171 _enableVMServicePublication = enableVMServicePublication;
172 _weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterDartVMServicePublisher>>(
self);
174 fml::MessageLoop::EnsureInitializedForCurrentThread();
176 _callbackHandle = flutter::DartServiceIsolate::AddServerStatusCallback(
178 runner = fml::MessageLoop::GetCurrent().GetTaskRunner()](
const std::string& uri) {
180 runner->PostTask([weak, uri]() {
184 NSURL* url = [[[NSURL alloc]
185 initWithString:[NSString stringWithUTF8String:uri.c_str()]] autorelease];
186 weak.get().url = url;
187 if (weak.get().enableVMServicePublication) {
188 [[weak.get() delegate] publishServiceProtocolPort:url];
198 + (NSString*)serviceName {
199 return NSBundle.mainBundle.bundleIdentifier;
202 + (NSData*)createTxtData:(NSURL*)url {
205 NSString* path = [[url path] substringFromIndex:MIN(1, [[url path] length])];
206 NSData* pathData = [path dataUsingEncoding:NSUTF8StringEncoding];
207 NSDictionary<NSString*, NSData*>* txtDict = @{
208 @"authCode" : pathData,
210 return [NSNetService dataFromTXTRecordDictionary:txtDict];
218 [_delegate stopService];
221 flutter::DartServiceIsolate::RemoveServerStatusCallback(_callbackHandle);
226 #endif // FLUTTER_RELEASE