Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
FlutterDartVMServicePublisher.mm
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#define FML_USED_ON_EMBEDDER
6
8
9#if FLUTTER_RELEASE
10
12- (instancetype)initWithEnableVMServicePublication:(BOOL)enableVMServicePublication {
13 return [super init];
14}
15@end
16
17#else // FLUTTER_RELEASE
18
19#import <TargetConditionals.h>
20// NSNetService works fine on physical devices before iOS 13.2.
21// However, it doesn't expose the services to regular mDNS
22// queries on the Simulator or on iOS 13.2+ devices.
23//
24// When debugging issues with this implementation, the following is helpful:
25//
26// 1) Running `dns-sd -Z _dartVmService`. This is a built-in macOS tool that
27// can find advertized observatories using this method. If dns-sd can't find
28// it, then the VM service is not getting advertised over any network
29// interface that the host machine has access to.
30// 2) The Python zeroconf package. The dns-sd tool can sometimes see things
31// that aren't advertizing over a network interface - for example, simulators
32// using NSNetService has been observed using dns-sd, but doesn't show up in
33// the Python package (which is a high quality socket based implementation).
34// If that happens, this code should be tweaked such that it shows up in both
35// dns-sd's output and Python zeroconf's detection.
36// 3) The Dart multicast_dns package, which is what Flutter uses to find the
37// port and auth code. If the advertizement shows up in dns-sd and Python
38// zeroconf but not multicast_dns, then it is a bug in multicast_dns.
39#include <dns_sd.h>
40#include <net/if.h>
41
42#include "flutter/fml/logging.h"
45#import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
47
49
50@protocol FlutterDartVMServicePublisherDelegate
51- (void)publishServiceProtocolPort:(NSURL*)uri;
52- (void)stopService;
53@end
54
56+ (NSData*)createTxtData:(NSURL*)url;
57
58@property(readonly, class) NSString* serviceName;
59@property(readonly) NSObject<FlutterDartVMServicePublisherDelegate>* delegate;
60@property(nonatomic, readwrite) NSURL* url;
61@property(readonly) BOOL enableVMServicePublication;
62
63@end
64
66@end
67
68@implementation DartVMServiceDNSServiceDelegate {
69 DNSServiceRef _dnsServiceRef;
70}
71
72- (void)stopService {
73 if (_dnsServiceRef) {
74 DNSServiceRefDeallocate(_dnsServiceRef);
75 _dnsServiceRef = NULL;
76 }
77}
78
79- (void)publishServiceProtocolPort:(NSURL*)url {
80 DNSServiceFlags flags = kDNSServiceFlagsDefault;
81#if TARGET_IPHONE_SIMULATOR
82 // Simulator needs to use local loopback explicitly to work.
83 uint32_t interfaceIndex = if_nametoindex("lo0");
84#else // TARGET_IPHONE_SIMULATOR
85 // Physical devices need to request all interfaces.
86 uint32_t interfaceIndex = 0;
87#endif // TARGET_IPHONE_SIMULATOR
88 const char* registrationType = "_dartVmService._tcp";
89
90 const char* domain = "local."; // default domain
91 uint16_t port = [[url port] unsignedShortValue];
92
93 NSData* txtData = [FlutterDartVMServicePublisher createTxtData:url];
94 int err = DNSServiceRegister(&_dnsServiceRef, flags, interfaceIndex,
95 FlutterDartVMServicePublisher.serviceName.UTF8String,
96 registrationType, domain, NULL, htons(port), txtData.length,
97 txtData.bytes, RegistrationCallback, NULL);
98
99 if (err == 0) {
100 DNSServiceSetDispatchQueue(_dnsServiceRef, dispatch_get_main_queue());
101 return;
102 }
103
104 NSString* errorMessage = [NSString
105 stringWithFormat:@"Failed to register Dart VM Service port with mDNS with error %d.", err];
106 [FlutterLogger logError:errorMessage];
107 errorMessage = [NSString
108 stringWithFormat:@"On iOS 14+, local network broadcast in apps need to be declared in "
109 "the app's Info.plist. Debug and profile Flutter apps and modules host "
110 "VM services on the local network to support debugging features such "
111 "as hot reload and DevTools. To make your Flutter app or module "
112 "attachable and debuggable, add a '%s' value to the 'NSBonjourServices' "
113 "key in your Info.plist for the Debug/Profile configurations. For more "
114 "information, see https://docs.flutter.dev/development/add-to-app/ios/"
115 "project-setup#local-network-privacy-permissions",
116 registrationType];
117 [FlutterLogger logError:errorMessage];
118}
119
120static void DNSSD_API RegistrationCallback(DNSServiceRef sdRef,
121 DNSServiceFlags flags,
122 DNSServiceErrorType errorCode,
123 const char* name,
124 const char* regType,
125 const char* domain,
126 void* context) {
127 if (errorCode == kDNSServiceErr_NoError) {
128 FML_DLOG(INFO) << "FlutterDartVMServicePublisher is ready!";
129 } else if (errorCode == kDNSServiceErr_PolicyDenied) {
130 // Local Network permissions on simulators stopped working in macOS 15.4 and will always return
131 // kDNSServiceErr_PolicyDenied. See
132 // https://github.com/flutter/flutter/issues/166333#issuecomment-2786720560.
133#if TARGET_IPHONE_SIMULATOR
134 FML_DLOG(WARNING)
135 << "Could not register as server for FlutterDartVMServicePublisher, permission "
136 << "denied. Check your 'Local Network' permissions for this app in the Privacy section of "
137 << "the system Settings.";
138#else // TARGET_IPHONE_SIMULATOR
139 [FlutterLogger logError:@"Could not register as server for FlutterDartVMServicePublisher, "
140 "permission denied. Check your 'Local Network' permissions for this "
141 "app in the Privacy section of the system Settings."];
142#endif // TARGET_IPHONE_SIMULATOR
143 } else {
144 [FlutterLogger logError:@"Could not register as server for FlutterDartVMServicePublisher. "
145 "Check your network settings and relaunch the application."];
146 }
147}
148
149@end
150
151@implementation FlutterDartVMServicePublisher {
153}
154
155- (instancetype)initWithEnableVMServicePublication:(BOOL)enableVMServicePublication {
156 self = [super init];
157 NSAssert(self, @"Super must not return null on init.");
158
159 _delegate = [[DartVMServiceDNSServiceDelegate alloc] init];
160 _enableVMServicePublication = enableVMServicePublication;
161 __weak __typeof(self) weakSelf = self;
162
164
166 [weakSelf, runner = fml::MessageLoop::GetCurrent().GetTaskRunner()](const std::string& uri) {
167 if (!uri.empty()) {
168 runner->PostTask([weakSelf, uri]() {
169 FlutterDartVMServicePublisher* strongSelf = weakSelf;
170 // uri comes in as something like 'http://127.0.0.1:XXXXX/' where XXXXX is the port
171 // number.
172 if (strongSelf) {
173 NSURL* url =
174 [[NSURL alloc] initWithString:[NSString stringWithUTF8String:uri.c_str()]];
175 strongSelf.url = url;
176 if (strongSelf.enableVMServicePublication) {
177 [[strongSelf delegate] publishServiceProtocolPort:url];
178 }
179 }
180 });
181 }
182 });
183
184 return self;
185}
186
187+ (NSString*)serviceName {
188 return NSBundle.mainBundle.bundleIdentifier;
189}
190
191+ (NSData*)createTxtData:(NSURL*)url {
192 // Check to see if there's an authentication code. If there is, we'll provide
193 // it as a txt record so flutter tools can establish a connection.
194 NSString* path = [[url path] substringFromIndex:MIN(1, [[url path] length])];
195 NSData* pathData = [path dataUsingEncoding:NSUTF8StringEncoding];
196 NSDictionary<NSString*, NSData*>* txtDict = @{
197 @"authCode" : pathData,
198 };
199 return [NSNetService dataFromTXTRecordDictionary:txtDict];
200}
201
202- (void)dealloc {
203 [_delegate stopService];
204
206}
207@end
208
209#endif // FLUTTER_RELEASE
static CallbackHandle AddServerStatusCallback(const DartVMServiceServerStateCallback &callback)
Add a callback that will get invoked when the VM Service starts up. If the VM Service has already sta...
static bool RemoveServerStatusCallback(CallbackHandle handle)
Removed a callback previously registered via AddServiceStatusCallback.
static void EnsureInitializedForCurrentThread()
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
#define FML_DLOG(severity)
Definition logging.h:121
const char * name
Definition fuchsia.cc:50
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
std::shared_ptr< ContextGLES > context
int BOOL