5 #define FML_USED_ON_EMBEDDER
12 - (instancetype)initWithEnableVMServicePublication:(BOOL)enableVMServicePublication {
19 #import <TargetConditionals.h>
42 #include "flutter/fml/logging.h"
43 #include "flutter/fml/message_loop.h"
44 #include "flutter/runtime/dart_service_isolate.h"
45 #import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
51 - (void)publishServiceProtocolPort:(NSURL*)uri;
56 + (NSData*)createTxtData:(NSURL*)url;
58 @property(readonly,
class) NSString* serviceName;
59 @property(readonly) NSObject<FlutterDartVMServicePublisherDelegate>* delegate;
60 @property(nonatomic, readwrite) NSURL*
url;
61 @property(readonly) BOOL enableVMServicePublication;
69 DNSServiceRef _dnsServiceRef;
74 DNSServiceRefDeallocate(_dnsServiceRef);
75 _dnsServiceRef = NULL;
79 - (void)publishServiceProtocolPort:(NSURL*)url {
80 DNSServiceFlags flags = kDNSServiceFlagsDefault;
81 #if TARGET_IPHONE_SIMULATOR
83 uint32_t interfaceIndex = if_nametoindex(
"lo0");
86 uint32_t interfaceIndex = 0;
88 const char* registrationType =
"_dartVmService._tcp";
90 const char* domain =
"local.";
91 uint16_t port = [[url port] unsignedShortValue];
94 int err = DNSServiceRegister(&_dnsServiceRef, flags, interfaceIndex,
96 registrationType, domain, NULL, htons(port), txtData.length,
97 txtData.bytes, RegistrationCallback, NULL);
100 DNSServiceSetDispatchQueue(_dnsServiceRef, dispatch_get_main_queue());
104 NSString* errorMessage = [NSString
105 stringWithFormat:@"Failed to register Dart VM Service port with mDNS with error %d.", err];
106 [FlutterLogger logError:errorMessage];
107 if (@available(iOS 14.0, *)) {
108 errorMessage = [NSString
109 stringWithFormat:@"On iOS 14+, local network broadcast in apps need to be declared in "
110 "the app's Info.plist. Debug and profile Flutter apps and modules host "
111 "VM services on the local network to support debugging features such "
112 "as hot reload and DevTools. To make your Flutter app or module "
113 "attachable and debuggable, add a '%s' value to the 'NSBonjourServices' "
114 "key in your Info.plist for the Debug/Profile configurations. For more "
115 "information, see https://docs.flutter.cn/development/add-to-app/ios/"
116 "project-setup#local-network-privacy-permissions",
118 [FlutterLogger logError:errorMessage];
122 static void DNSSD_API RegistrationCallback(DNSServiceRef sdRef,
123 DNSServiceFlags flags,
124 DNSServiceErrorType errorCode,
129 if (errorCode == kDNSServiceErr_NoError) {
130 FML_DLOG(INFO) <<
"FlutterDartVMServicePublisher is ready!";
131 }
else if (errorCode == kDNSServiceErr_PolicyDenied) {
135 #if TARGET_IPHONE_SIMULATOR
137 <<
"Could not register as server for FlutterDartVMServicePublisher, permission "
138 <<
"denied. Check your 'Local Network' permissions for this app in the Privacy section of "
139 <<
"the system Settings.";
141 [FlutterLogger logError:@"Could not register as server for FlutterDartVMServicePublisher, "
142 "permission denied. Check your 'Local Network' permissions for this "
143 "app in the Privacy section of the system Settings."];
146 [FlutterLogger logError:@"Could not register as server for FlutterDartVMServicePublisher. "
147 "Check your network settings and relaunch the application."];
154 flutter::DartServiceIsolate::CallbackHandle _callbackHandle;
157 - (instancetype)initWithEnableVMServicePublication:(BOOL)enableVMServicePublication {
159 NSAssert(
self,
@"Super must not return null on init.");
162 _enableVMServicePublication = enableVMServicePublication;
163 __weak __typeof(
self) weakSelf =
self;
165 fml::MessageLoop::EnsureInitializedForCurrentThread();
167 _callbackHandle =
flutter::DartServiceIsolate::AddServerStatusCallback(
168 [weakSelf, runner =
fml::MessageLoop::GetCurrent().GetTaskRunner()](const std::
string& uri) {
170 runner->PostTask([weakSelf, uri]() {
176 [[NSURL alloc] initWithString:[NSString stringWithUTF8String:uri.c_str()]];
177 strongSelf.
url = url;
178 if (strongSelf.enableVMServicePublication) {
179 [[strongSelf delegate] publishServiceProtocolPort:url];
189 + (NSString*)serviceName {
190 return NSBundle.mainBundle.bundleIdentifier;
193 + (NSData*)createTxtData:(NSURL*)url {
196 NSString* path = [[url path] substringFromIndex:MIN(1, [[url path] length])];
197 NSData* pathData = [path dataUsingEncoding:NSUTF8StringEncoding];
198 NSDictionary<NSString*, NSData*>* txtDict = @{
199 @"authCode" : pathData,
201 return [NSNetService dataFromTXTRecordDictionary:txtDict];
205 [_delegate stopService];
207 flutter::DartServiceIsolate::RemoveServerStatusCallback(_callbackHandle);