Flutter iOS Embedder
FlutterDartProject.mm File Reference
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
#import <Metal/Metal.h>
#import <UIKit/UIKit.h>
#include <sstream>
#include "flutter/common/constants.h"
#include "flutter/fml/build_config.h"
#include "flutter/shell/common/switches.h"
#import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
#include "flutter/shell/platform/darwin/common/command_line.h"

Go to the source code of this file.

Macros

#define FML_USED_ON_EMBEDDER
 

Functions

static BOOL DoesHardwareSupportWideGamut ()
 
NSNumber *_Nullable FLTEnableWideGamutFromBundle (NSBundle *_Nullable bundle, NSBundle *_Nullable mainBundle)
 
flutter::Settings FLTDefaultSettingsForBundle (NSBundle *bundle, NSProcessInfo *processInfoOrNil)
 

Variables

FLUTTER_ASSERT_ARC const uint8_t kPlatformStrongDill []
 
const intptr_t kPlatformStrongDillSize
 
static const char * kApplicationKernelSnapshotFileName = "kernel_blob.bin"
 

Macro Definition Documentation

◆ FML_USED_ON_EMBEDDER

#define FML_USED_ON_EMBEDDER

Definition at line 5 of file FlutterDartProject.mm.

Function Documentation

◆ DoesHardwareSupportWideGamut()

static BOOL DoesHardwareSupportWideGamut ( )
static

Definition at line 32 of file FlutterDartProject.mm.

32  {
33  static BOOL result = NO;
34  static dispatch_once_t once_token = 0;
35  dispatch_once(&once_token, ^{
36  id<MTLDevice> device = MTLCreateSystemDefaultDevice();
37  result = [device supportsFamily:MTLGPUFamilyApple2];
38  });
39  return result;
40 }

Referenced by FlutterDartProject::defaultBundleIdentifier.

◆ FLTDefaultSettingsForBundle()

flutter::Settings FLTDefaultSettingsForBundle ( NSBundle *  bundle,
NSProcessInfo *  processInfoOrNil 
)

Definition at line 51 of file FlutterDartProject.mm.

51  {
52  auto command_line = flutter::CommandLineFromNSProcessInfo(processInfoOrNil);
53 
54  // Precedence:
55  // 1. Settings from the specified NSBundle.
56  // 2. Settings passed explicitly via command-line arguments.
57  // 3. Settings from the NSBundle with the default bundle ID.
58  // 4. Settings from the main NSBundle and default values.
59 
60  NSBundle* mainBundle = FLTGetApplicationBundle();
61  NSBundle* engineBundle = [NSBundle bundleForClass:[FlutterDartProject class]];
62 
63  bool hasExplicitBundle = bundle != nil;
64  if (bundle == nil) {
65  bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
66  }
67 
68  auto settings = flutter::SettingsFromCommandLine(command_line, true);
69 
70  settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
71  fml::TaskQueueId queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
72  fml::MessageLoopTaskQueues::GetInstance()->AddTaskObserver(queue_id, key, callback);
73  return queue_id;
74  };
75 
76  settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
77  fml::MessageLoopTaskQueues::GetInstance()->RemoveTaskObserver(queue_id, key);
78  };
79 
80  settings.log_message_callback = [](const std::string& tag, const std::string& message) {
81  std::stringstream stream;
82  if (!tag.empty()) {
83  stream << tag << ": ";
84  }
85  stream << message;
86  std::string log = stream.str();
87  [FlutterLogger logDirect:[NSString stringWithUTF8String:log.c_str()]];
88  };
89 
90  settings.enable_platform_isolates = true;
91 
92  // The command line arguments may not always be complete. If they aren't, attempt to fill in
93  // defaults.
94 
95  // Flutter ships the ICU data file in the bundle of the engine. Look for it there.
96  if (settings.icu_data_path.empty()) {
97  NSString* icuDataPath = [engineBundle pathForResource:@"icudtl" ofType:@"dat"];
98  if (icuDataPath.length > 0) {
99  settings.icu_data_path = icuDataPath.UTF8String;
100  }
101  }
102 
103  if (flutter::DartVM::IsRunningPrecompiledCode()) {
104  if (hasExplicitBundle) {
105  NSString* executablePath = bundle.executablePath;
106  if ([[NSFileManager defaultManager] fileExistsAtPath:executablePath]) {
107  settings.application_library_paths.push_back(executablePath.UTF8String);
108  }
109  }
110 
111  // No application bundle specified. Try a known location from the main bundle's Info.plist.
112  if (settings.application_library_paths.empty()) {
113  NSString* libraryName = [mainBundle objectForInfoDictionaryKey:@"FLTLibraryPath"];
114  NSString* libraryPath = [mainBundle pathForResource:libraryName ofType:@""];
115  if (libraryPath.length > 0) {
116  NSString* executablePath = [NSBundle bundleWithPath:libraryPath].executablePath;
117  if (executablePath.length > 0) {
118  settings.application_library_paths.push_back(executablePath.UTF8String);
119  }
120  }
121  }
122 
123  // In case the application bundle is still not specified, look for the App.framework in the
124  // Frameworks directory.
125  if (settings.application_library_paths.empty()) {
126  NSString* applicationFrameworkPath = [mainBundle pathForResource:@"Frameworks/App.framework"
127  ofType:@""];
128  if (applicationFrameworkPath.length > 0) {
129  NSString* executablePath =
130  [NSBundle bundleWithPath:applicationFrameworkPath].executablePath;
131  if (executablePath.length > 0) {
132  settings.application_library_paths.push_back(executablePath.UTF8String);
133  }
134  }
135  }
136  }
137 
138  // Checks to see if the flutter assets directory is already present.
139  if (settings.assets_path.empty()) {
140  NSString* assetsPath = FLTAssetsPathFromBundle(bundle);
141 
142  if (assetsPath.length == 0) {
143  NSLog(@"Failed to find assets path for \"%@\"", bundle);
144  } else {
145  settings.assets_path = assetsPath.UTF8String;
146 
147  // Check if there is an application kernel snapshot in the assets directory we could
148  // potentially use. Looking for the snapshot makes sense only if we have a VM that can use
149  // it.
150  if (!flutter::DartVM::IsRunningPrecompiledCode()) {
151  NSURL* applicationKernelSnapshotURL =
152  [NSURL URLWithString:@(kApplicationKernelSnapshotFileName)
153  relativeToURL:[NSURL fileURLWithPath:assetsPath]];
154  NSError* error;
155  if ([applicationKernelSnapshotURL checkResourceIsReachableAndReturnError:&error]) {
156  settings.application_kernel_asset = applicationKernelSnapshotURL.path.UTF8String;
157  } else {
158  NSLog(@"Failed to find snapshot at %@: %@", applicationKernelSnapshotURL.path, error);
159  }
160  }
161  }
162  }
163 
164  // Domain network configuration
165  // Disabled in https://github.com/flutter/flutter/issues/72723.
166  // Re-enable in https://github.com/flutter/flutter/issues/54448.
167  settings.may_insecurely_connect_to_all_domains = true;
168  settings.domain_network_policy = "";
169 
170  // Whether to enable wide gamut colors.
171 #if TARGET_OS_SIMULATOR
172  // As of Xcode 14.1, the wide gamut surface pixel formats are not supported by
173  // the simulator.
174  settings.enable_wide_gamut = false;
175  // Removes unused function warning.
177 #else
178  NSNumber* nsEnableWideGamut = FLTEnableWideGamutFromBundle(bundle, mainBundle);
179  BOOL enableWideGamut =
180  (nsEnableWideGamut ? nsEnableWideGamut.boolValue : YES) && DoesHardwareSupportWideGamut();
181  settings.enable_wide_gamut = enableWideGamut;
182 #endif
183 
184  NSNumber* nsAntialiasLines = [mainBundle objectForInfoDictionaryKey:@"FLTAntialiasLines"];
185  settings.impeller_antialiased_lines = (nsAntialiasLines ? nsAntialiasLines.boolValue : NO);
186 
187  settings.warn_on_impeller_opt_out = true;
188 
189  NSNumber* nsEnableSDFs = [mainBundle objectForInfoDictionaryKey:@"FLTEnableSDFs"];
190  settings.impeller_use_sdfs = (nsEnableSDFs ? nsEnableSDFs.boolValue : NO);
191 
192  NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTTraceSystrace"];
193  // Change the default only if the option is present.
194  if (enableTraceSystrace != nil) {
195  settings.trace_systrace = enableTraceSystrace.boolValue;
196  }
197 
198  NSNumber* profileMicrotasks = [mainBundle objectForInfoDictionaryKey:@"FLTProfileMicrotasks"];
199  // Change the default only if the option is present.
200  if (profileMicrotasks != nil) {
201  settings.profile_microtasks = profileMicrotasks.boolValue;
202  }
203 
204  NSNumber* enableDartAsserts = [mainBundle objectForInfoDictionaryKey:@"FLTEnableDartAsserts"];
205  if (enableDartAsserts != nil) {
206  settings.dart_flags.push_back("--enable-asserts");
207  }
208 
209  NSNumber* enableDartProfiling = [mainBundle objectForInfoDictionaryKey:@"FLTEnableDartProfiling"];
210  // Change the default only if the option is present.
211  if (enableDartProfiling != nil) {
212  settings.enable_dart_profiling = enableDartProfiling.boolValue;
213  }
214 
215  NSNumber* profileStartup = [mainBundle objectForInfoDictionaryKey:@"FLTProfileStartup"];
216  // Change the default only if the option is present.
217  if (profileStartup != nil) {
218  settings.profile_startup = profileStartup.boolValue;
219  }
220 
221  // Leak Dart VM settings, set whether leave or clean up the VM after the last shell shuts down.
222  NSNumber* leakDartVM = [mainBundle objectForInfoDictionaryKey:@"FLTLeakDartVM"];
223  // It will change the default leak_vm value in settings only if the key exists.
224  if (leakDartVM != nil) {
225  settings.leak_vm = leakDartVM.boolValue;
226  }
227 
228  NSNumber* enableMergedPlatformUIThread =
229  [mainBundle objectForInfoDictionaryKey:@"FLTEnableMergedPlatformUIThread"];
230  if (enableMergedPlatformUIThread != nil) {
231  FML_CHECK(enableMergedPlatformUIThread.boolValue)
232  << "FLTEnableMergedPlatformUIThread=false is no longer allowed.";
233  }
234 
235  NSNumber* enableFlutterGPU = [mainBundle objectForInfoDictionaryKey:@"FLTEnableFlutterGPU"];
236  if (enableFlutterGPU != nil) {
237  settings.enable_flutter_gpu = enableFlutterGPU.boolValue;
238  }
239 
240 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
241  // There are no ownership concerns here as all mappings are owned by the
242  // embedder and not the engine.
243  auto make_mapping_callback = [](const uint8_t* mapping, size_t size) {
244  return [mapping, size]() { return std::make_unique<fml::NonOwnedMapping>(mapping, size); };
245  };
246 
247  settings.dart_library_sources_kernel =
248  make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize);
249 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
250 
251  // If we even support setting this e.g. from the command line or the plist,
252  // we should let the user override it.
253  // Otherwise, we want to set this to a value that will avoid having the OS
254  // kill us. On most iOS devices, that happens somewhere near half
255  // the available memory.
256  // The VM expects this value to be in megabytes.
257  if (settings.old_gen_heap_size <= 0) {
258  settings.old_gen_heap_size = std::round([NSProcessInfo processInfo].physicalMemory * .48 /
259  flutter::kMegaByteSizeInBytes);
260  }
261 
262  // This is the formula Android uses.
263  // https://android.googlesource.com/platform/frameworks/base/+/39ae5bac216757bc201490f4c7b8c0f63006c6cd/libs/hwui/renderthread/CacheManager.cpp#45
264  CGFloat scale = [UIScreen mainScreen].scale;
265  CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width * scale;
266  CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height * scale;
267  settings.resource_cache_max_bytes_threshold = screenWidth * screenHeight * 12 * 4;
268 
269  // Whether to enable ios embedder api.
270  NSNumber* enable_embedder_api =
271  [mainBundle objectForInfoDictionaryKey:@"FLTEnableIOSEmbedderAPI"];
272  // Change the default only if the option is present.
273  if (enable_embedder_api) {
274  settings.enable_embedder_api = enable_embedder_api.boolValue;
275  }
276 
277  return settings;
278 }
NSNumber *_Nullable FLTEnableWideGamutFromBundle(NSBundle *_Nullable bundle, NSBundle *_Nullable mainBundle)
static const char * kApplicationKernelSnapshotFileName
const intptr_t kPlatformStrongDillSize
FLUTTER_ASSERT_ARC const uint8_t kPlatformStrongDill[]
static BOOL DoesHardwareSupportWideGamut()
NSBundle * FLTGetApplicationBundle()
NSBundle * FLTFrameworkBundleWithIdentifier(NSString *flutterFrameworkBundleID)
NSString * FLTAssetsPathFromBundle(NSBundle *bundle)
fml::CommandLine CommandLineFromNSProcessInfo(NSProcessInfo *processInfoOrNil=nil)
Definition: command_line.mm:13

◆ FLTEnableWideGamutFromBundle()

NSNumber* _Nullable FLTEnableWideGamutFromBundle ( NSBundle *_Nullable  bundle,
NSBundle *_Nullable  mainBundle 
)

Returns the value of the FLTEnableWideGamut key from the given bundle, falling back to the main bundle if not found in the first. If both bundles are the same object, the value is read once.

Definition at line 42 of file FlutterDartProject.mm.

43  {
44  NSNumber* nsEnableWideGamut = [bundle objectForInfoDictionaryKey:@"FLTEnableWideGamut"];
45  if (nsEnableWideGamut == nil && bundle != mainBundle) {
46  nsEnableWideGamut = [mainBundle objectForInfoDictionaryKey:@"FLTEnableWideGamut"];
47  }
48  return nsEnableWideGamut;
49 }

Referenced by FlutterDartProject::defaultBundleIdentifier.

Variable Documentation

◆ kApplicationKernelSnapshotFileName

const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin"
static

Definition at line 30 of file FlutterDartProject.mm.

Referenced by FlutterDartProject::defaultBundleIdentifier.

◆ kPlatformStrongDill

FLUTTER_ASSERT_ARC const uint8_t kPlatformStrongDill[]
extern

◆ kPlatformStrongDillSize

const intptr_t kPlatformStrongDillSize
extern