Flutter macOS Embedder
FlutterDartProject.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 
7 
8 #include <vector>
9 
11 
12 static NSString* const kICUBundlePath = @"icudtl.dat";
13 static NSString* const kAppBundleIdentifier = @"io.flutter.flutter.app";
14 
15 #pragma mark - Private interface declaration.
16 @interface FlutterDartProject ()
17 /**
18  Get the Flutter assets name path by pass the bundle. If bundle is nil, we use the main bundle as
19  default.
20  */
21 + (NSString*)flutterAssetsNameWithBundle:(NSBundle*)bundle;
22 @end
23 
24 @implementation FlutterDartProject {
25  NSBundle* _dartBundle;
26  NSString* _assetsPath;
27  NSString* _ICUDataPath;
28 }
29 
30 - (instancetype)init {
31  return [self initWithPrecompiledDartBundle:nil];
32 }
33 
34 - (instancetype)initWithPrecompiledDartBundle:(NSBundle*)bundle {
35  self = [super init];
36  NSAssert(self, @"Super init cannot be nil");
37 
39  if (_dartBundle == nil) {
40  // The bundle isn't loaded and can't be found by bundle ID. Find it by path.
41  _dartBundle = [NSBundle bundleWithURL:[NSBundle.mainBundle.privateFrameworksURL
42  URLByAppendingPathComponent:@"App.framework"]];
43  }
44  if (!_dartBundle.isLoaded) {
45  [_dartBundle load];
46  }
47  _dartEntrypointArguments = [[NSProcessInfo processInfo] arguments];
48  // Remove the first element as it's the binary name
49  _dartEntrypointArguments = [_dartEntrypointArguments
50  subarrayWithRange:NSMakeRange(1, _dartEntrypointArguments.count - 1)];
51  return self;
52 }
53 
54 - (instancetype)initWithAssetsPath:(NSString*)assets ICUDataPath:(NSString*)icuPath {
55  self = [super init];
56  NSAssert(self, @"Super init cannot be nil");
57  _assetsPath = assets;
58  _ICUDataPath = icuPath;
59  return self;
60 }
61 
62 - (BOOL)enableImpeller {
63  NSNumber* enableImpeller =
64  [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTEnableImpeller"];
65  if (enableImpeller != nil) {
66  return enableImpeller.boolValue;
67  }
68  return NO;
69 }
70 
71 - (BOOL)enableFlutterGPU {
72  NSNumber* enableFlutterGPU =
73  [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTEnableFlutterGPU"];
74  if (enableFlutterGPU != nil) {
75  return enableFlutterGPU.boolValue;
76  }
77  return NO;
78 }
79 
80 - (NSString*)assetsPath {
81  if (_assetsPath) {
82  return _assetsPath;
83  }
84 
85  // If there's no App.framework, fall back to checking the main bundle for assets.
86  NSBundle* assetBundle = _dartBundle ?: [NSBundle mainBundle];
87  NSString* flutterAssetsName = [assetBundle objectForInfoDictionaryKey:@"FLTAssetsPath"];
88  if (flutterAssetsName == nil) {
89  flutterAssetsName = @"flutter_assets";
90  }
91  NSString* path = [assetBundle pathForResource:flutterAssetsName ofType:@""];
92  if (!path) {
93  NSLog(@"Failed to find path for \"%@\"", flutterAssetsName);
94  }
95  return path;
96 }
97 
98 - (NSString*)ICUDataPath {
99  if (_ICUDataPath) {
100  return _ICUDataPath;
101  }
102 
103  NSString* path = [[NSBundle bundleForClass:[self class]] pathForResource:kICUBundlePath
104  ofType:nil];
105  if (!path) {
106  NSLog(@"Failed to find path for \"%@\"", kICUBundlePath);
107  }
108  return path;
109 }
110 
111 + (NSString*)flutterAssetsNameWithBundle:(NSBundle*)bundle {
112  if (bundle == nil) {
114  }
115  if (bundle == nil) {
116  bundle = [NSBundle mainBundle];
117  }
118  NSString* flutterAssetsName = [bundle objectForInfoDictionaryKey:@"FLTAssetsPath"];
119  if (flutterAssetsName == nil) {
120  flutterAssetsName = @"Contents/Frameworks/App.framework/Resources/flutter_assets";
121  }
122  return flutterAssetsName;
123 }
124 
125 + (NSString*)lookupKeyForAsset:(NSString*)asset {
126  return [self lookupKeyForAsset:asset fromBundle:nil];
127 }
128 
129 + (NSString*)lookupKeyForAsset:(NSString*)asset fromBundle:(nullable NSBundle*)bundle {
130  NSString* flutterAssetsName = [FlutterDartProject flutterAssetsNameWithBundle:bundle];
131  return [NSString stringWithFormat:@"%@/%@", flutterAssetsName, asset];
132 }
133 
134 + (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
135  return [self lookupKeyForAsset:asset fromPackage:package fromBundle:nil];
136 }
137 
138 + (NSString*)lookupKeyForAsset:(NSString*)asset
139  fromPackage:(NSString*)package
140  fromBundle:(nullable NSBundle*)bundle {
141  return [self lookupKeyForAsset:[NSString stringWithFormat:@"packages/%@/%@", package, asset]
142  fromBundle:bundle];
143 }
144 
145 + (NSString*)defaultBundleIdentifier {
146  return kAppBundleIdentifier;
147 }
148 
149 @end
static NSString *const kAppBundleIdentifier
static NSString *const kICUBundlePath
NSString * _ICUDataPath
NSString * _assetsPath
NSBundle * FLTFrameworkBundleWithIdentifier(NSString *flutterFrameworkBundleID)