FlutterDartProject.mm 8.6 KB
Newer Older
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#define FML_USED_ON_EMBEDDER

7
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
8

9 10 11 12
#include "flutter/common/task_runners.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/runtime/dart_vm.h"
13
#include "flutter/shell/common/shell.h"
14
#include "flutter/shell/common/switches.h"
15 16 17
#include "flutter/shell/platform/darwin/common/command_line.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"

18
static const char* kScriptSnapshotFileName = "snapshot_blob.bin";
19 20 21 22 23 24 25 26 27
static const char* kVMKernelSnapshotFileName = "platform.dill";
static const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin";

static blink::Settings DefaultSettingsForProcess() {
  auto command_line = shell::CommandLineFromNSProcessInfo();

  // Settings passed in explicitly via command line arguments take priority.
  auto settings = shell::SettingsFromCommandLine(command_line);

28
  settings.task_observer_add = [](intptr_t key, fml::closure callback) {
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
    fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
  };

  settings.task_observer_remove = [](intptr_t key) {
    fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
  };

  // The command line arguments may not always be complete. If they aren't, attempt to fill in
  // defaults.

  // Flutter ships the ICU data file in the the bundle of the engine. Look for it there.
  if (settings.icu_data_path.size() == 0) {
    NSBundle* bundle = [NSBundle bundleForClass:[FlutterViewController class]];
    NSString* icuDataPath = [bundle pathForResource:@"icudtl" ofType:@"dat"];
    if (icuDataPath.length > 0) {
      settings.icu_data_path = icuDataPath.UTF8String;
    }
46 47
  }

48 49 50 51 52 53 54 55 56 57
  if (blink::DartVM::IsRunningPrecompiledCode()) {
    // The application bundle could be specified in the Info.plist.
    if (settings.application_library_path.size() == 0) {
      NSString* libraryName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTLibraryPath"];
      NSString* libraryPath = [[NSBundle mainBundle] pathForResource:libraryName ofType:nil];
      if (libraryPath.length > 0) {
        settings.application_library_path =
            [NSBundle bundleWithPath:libraryPath].executablePath.UTF8String;
      }
    }
58

59 60 61 62 63 64 65 66 67 68 69
    // In case the application bundle is still not specified, look for the App.framework in the
    // Frameworks directory.
    if (settings.application_library_path.size() == 0) {
      NSString* applicationFrameworkPath =
          [[NSBundle mainBundle] pathForResource:@"Frameworks/App.framework" ofType:@""];
      if (applicationFrameworkPath.length > 0) {
        settings.application_library_path =
            [NSBundle bundleWithPath:applicationFrameworkPath].executablePath.UTF8String;
      }
    }
  }
70

71 72
  // Checks to see if the flutter assets directory is already present.
  if (settings.assets_path.size() == 0) {
73 74 75 76 77
    // The kernel assets will not be present in the Flutter frameworks bundle since it is not user
    // editable. Instead, look inside the main bundle.
    NSBundle* bundle = [NSBundle mainBundle];
    NSString* assets_directory_name = [FlutterDartProject flutterAssetsName:bundle];
    NSString* assetsPath = [bundle pathForResource:assets_directory_name ofType:@""];
78 79 80 81 82

    if (assetsPath.length > 0) {
      settings.assets_path = assetsPath.UTF8String;

      if (!blink::DartVM::IsRunningPrecompiledCode()) {
83 84 85 86 87 88 89 90 91 92 93
        // Looking for the various script and kernel snapshot buffers only makes sense if we have a
        // VM that can use these buffers.
        {
          // Check if there is a script snapshot in the assets directory we could potentially use.
          NSURL* scriptSnapshotURL = [NSURL URLWithString:@(kScriptSnapshotFileName)
                                            relativeToURL:[NSURL fileURLWithPath:assetsPath]];
          if ([[NSFileManager defaultManager] fileExistsAtPath:scriptSnapshotURL.path]) {
            settings.script_snapshot_path = scriptSnapshotURL.path.UTF8String;
          }
        }

94 95 96 97 98 99
        {
          // Check if there is a VM kernel snapshot in the assets directory we could potentially
          // use.
          NSURL* vmKernelSnapshotURL = [NSURL URLWithString:@(kVMKernelSnapshotFileName)
                                              relativeToURL:[NSURL fileURLWithPath:assetsPath]];
          if ([[NSFileManager defaultManager] fileExistsAtPath:vmKernelSnapshotURL.path]) {
100
            settings.platform_kernel_path = vmKernelSnapshotURL.path.UTF8String;
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
          }
        }

        {
          // Check if there is an application kernel snapshot in the assets directory we could
          // potentially use.
          NSURL* applicationKernelSnapshotURL =
              [NSURL URLWithString:@(kApplicationKernelSnapshotFileName)
                     relativeToURL:[NSURL fileURLWithPath:assetsPath]];
          if ([[NSFileManager defaultManager] fileExistsAtPath:applicationKernelSnapshotURL.path]) {
            settings.application_kernel_asset = applicationKernelSnapshotURL.path.UTF8String;
          }
        }
      }
    }
  }

  return settings;
119 120
}

121 122 123
@implementation FlutterDartProject {
  fml::scoped_nsobject<NSBundle> _precompiledDartBundle;
  blink::Settings _settings;
124 125
}

126 127 128
#pragma mark - Override base class designated initializers

- (instancetype)init {
129
  return [self initWithFlutterAssets:nil dartMain:nil packages:nil];
130 131 132 133 134 135 136 137
}

#pragma mark - Designated initializers

- (instancetype)initWithPrecompiledDartBundle:(NSBundle*)bundle {
  self = [super init];

  if (self) {
138
    _precompiledDartBundle.reset([bundle retain]);
139

140 141 142 143 144 145 146 147
    _settings = DefaultSettingsForProcess();

    if (bundle != nil) {
      NSString* executablePath = _precompiledDartBundle.get().executablePath;
      if ([[NSFileManager defaultManager] fileExistsAtPath:executablePath]) {
        _settings.application_library_path = executablePath.UTF8String;
      }
    }
148 149 150 151 152
  }

  return self;
}

153 154 155
- (instancetype)initWithFlutterAssets:(NSURL*)flutterAssetsURL
                             dartMain:(NSURL*)dartMainURL
                             packages:(NSURL*)dartPackages {
156 157 158
  self = [super init];

  if (self) {
159
    _settings = DefaultSettingsForProcess();
160

161 162 163 164 165 166 167
    if ([[NSFileManager defaultManager] fileExistsAtPath:dartMainURL.path]) {
      _settings.main_dart_file_path = dartMainURL.path.UTF8String;
    }

    if ([[NSFileManager defaultManager] fileExistsAtPath:dartPackages.path]) {
      _settings.packages_file_path = dartPackages.path.UTF8String;
    }
168 169 170 171 172
  }

  return self;
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
- (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssetsURL {
  self = [super init];

  if (self) {
    _settings = DefaultSettingsForProcess();

    if ([[NSFileManager defaultManager] fileExistsAtPath:flutterAssetsURL.path]) {
      _settings.assets_path = flutterAssetsURL.path.UTF8String;

      NSURL* scriptSnapshotPath =
          [NSURL URLWithString:@(kScriptSnapshotFileName) relativeToURL:flutterAssetsURL];
      if ([[NSFileManager defaultManager] fileExistsAtPath:scriptSnapshotPath.path]) {
        _settings.script_snapshot_path = scriptSnapshotPath.path.UTF8String;
      }
    }
  }

  return self;
}

193 194 195
#pragma mark - Convenience initializers

- (instancetype)initFromDefaultSourceForConfiguration {
196 197
  if (blink::DartVM::IsRunningPrecompiledCode()) {
    return [self initWithPrecompiledDartBundle:nil];
198
  } else {
199
    return [self initWithFlutterAssets:nil dartMain:nil packages:nil];
200
  }
201
}
202

203 204 205
- (const blink::Settings&)settings {
  return _settings;
}
206

207 208
- (shell::RunConfiguration)runConfiguration {
  return shell::RunConfiguration::InferFromSettings(_settings);
209 210
}

211 212
#pragma mark - Assets-related utilities

213
+ (NSString*)flutterAssetsName:(NSBundle*)bundle {
214 215 216 217
  NSString* flutterAssetsName = [bundle objectForInfoDictionaryKey:@"FLTAssetsPath"];
  if (flutterAssetsName == nil) {
    // Default to "flutter_assets"
    flutterAssetsName = @"flutter_assets";
218
  }
219 220
  return flutterAssetsName;
}
221

222 223
+ (NSString*)pathForFlutterAssetsFromBundle:(NSBundle*)bundle {
  NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName:bundle];
224
  return [bundle pathForResource:flutterAssetsName ofType:nil];
225 226
}

227
+ (NSString*)lookupKeyForAsset:(NSString*)asset {
228
  NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName:[NSBundle mainBundle]];
229 230 231 232 233 234 235
  return [NSString stringWithFormat:@"%@/%@", flutterAssetsName, asset];
}

+ (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
  return [self lookupKeyForAsset:[NSString stringWithFormat:@"packages/%@/%@", package, asset]];
}

236
@end