Implemented FlutterEngineGroup and Spawn API. (flutter/engine#22975)

This commit is contained in:
gaaclarke 2020-12-14 17:07:44 -08:00 committed by GitHub
parent 525acfa06b
commit 3d4aa5548a
14 changed files with 417 additions and 23 deletions

View File

@ -946,6 +946,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDel
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngineGroup.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h
@ -964,6 +965,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartPro
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProjectTest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineGroup.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineGroupTest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h

View File

@ -436,6 +436,21 @@ Shell::~Shell() {
platform_latch.Wait();
}
std::unique_ptr<Shell> Shell::Spawn(
Settings settings,
const CreateCallback<PlatformView>& on_create_platform_view,
const CreateCallback<Rasterizer>& on_create_rasterizer) {
RunConfiguration configuration =
RunConfiguration::InferFromSettings(settings);
TaskRunners task_runners = task_runners_;
FML_DCHECK(task_runners.IsValid());
std::unique_ptr<Shell> result(Shell::Create(std::move(task_runners), settings,
on_create_platform_view,
on_create_rasterizer));
result->RunEngine(std::move(configuration));
return result;
}
void Shell::NotifyLowMemoryWarning() const {
auto trace_id = fml::tracing::TraceNonce();
TRACE_EVENT_ASYNC_BEGIN0("flutter", "Shell::NotifyLowMemoryWarning",

View File

@ -220,6 +220,19 @@ class Shell final : public PlatformView::Delegate,
///
~Shell();
//----------------------------------------------------------------------------
/// @brief Creates one Shell from another Shell where the created Shell
/// takes the opportunity to share any internal components it can.
/// This results is a Shell that has a smaller startup time cost
/// and a smaller memory footprint than an Shell created with a
/// Create function.
///
/// @see http://flutter.dev/go/multiple-engines
std::unique_ptr<Shell> Spawn(
Settings settings,
const CreateCallback<PlatformView>& on_create_platform_view,
const CreateCallback<Rasterizer>& on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration.
///

View File

@ -32,6 +32,7 @@
#include "flutter/shell/common/vsync_waiter_fallback.h"
#include "flutter/shell/version/version.h"
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"
#include "third_party/rapidjson/include/rapidjson/writer.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/tonic/converter/dart_converter.h"
@ -42,6 +43,77 @@
namespace flutter {
namespace testing {
namespace {
class MockPlatformViewDelegate : public PlatformView::Delegate {
MOCK_METHOD1(OnPlatformViewCreated, void(std::unique_ptr<Surface> surface));
MOCK_METHOD0(OnPlatformViewDestroyed, void());
MOCK_METHOD1(OnPlatformViewSetNextFrameCallback,
void(const fml::closure& closure));
MOCK_METHOD1(OnPlatformViewSetViewportMetrics,
void(const ViewportMetrics& metrics));
MOCK_METHOD1(OnPlatformViewDispatchPlatformMessage,
void(fml::RefPtr<PlatformMessage> message));
MOCK_METHOD1(OnPlatformViewDispatchPointerDataPacket,
void(std::unique_ptr<PointerDataPacket> packet));
MOCK_METHOD3(OnPlatformViewDispatchSemanticsAction,
void(int32_t id,
SemanticsAction action,
std::vector<uint8_t> args));
MOCK_METHOD1(OnPlatformViewSetSemanticsEnabled, void(bool enabled));
MOCK_METHOD1(OnPlatformViewSetAccessibilityFeatures, void(int32_t flags));
MOCK_METHOD1(OnPlatformViewRegisterTexture,
void(std::shared_ptr<Texture> texture));
MOCK_METHOD1(OnPlatformViewUnregisterTexture, void(int64_t texture_id));
MOCK_METHOD1(OnPlatformViewMarkTextureFrameAvailable,
void(int64_t texture_id));
MOCK_METHOD3(LoadDartDeferredLibrary,
void(intptr_t loading_unit_id,
std::unique_ptr<const fml::Mapping> snapshot_data,
std::unique_ptr<const fml::Mapping> snapshot_instructions));
MOCK_METHOD3(LoadDartDeferredLibraryError,
void(intptr_t loading_unit_id,
const std::string error_message,
bool transient));
MOCK_METHOD1(UpdateAssetManager,
void(std::shared_ptr<AssetManager> asset_manager));
};
class MockSurface : public Surface {
MOCK_METHOD0(IsValid, bool());
MOCK_METHOD1(AcquireFrame,
std::unique_ptr<SurfaceFrame>(const SkISize& size));
MOCK_CONST_METHOD0(GetRootTransformation, SkMatrix());
MOCK_METHOD0(GetContext, GrDirectContext*());
MOCK_METHOD0(MakeRenderContextCurrent, std::unique_ptr<GLContextResult>());
MOCK_METHOD0(ClearRenderContext, bool());
};
class MockPlatformView : public PlatformView {
public:
MockPlatformView(MockPlatformViewDelegate& delegate, TaskRunners task_runners)
: PlatformView(delegate, task_runners) {}
MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr<Surface>());
};
} // namespace
static bool ValidateShell(Shell* shell) {
if (!shell) {
@ -2318,5 +2390,52 @@ TEST_F(ShellTest, AssetManagerMulti) {
}
}
TEST_F(ShellTest, Spawn) {
auto settings = CreateSettingsForFixture();
auto shell = CreateShell(settings);
ASSERT_TRUE(ValidateShell(shell.get()));
auto configuration = RunConfiguration::InferFromSettings(settings);
ASSERT_TRUE(configuration.IsValid());
configuration.SetEntrypoint("fixturesAreFunctionalMain");
fml::AutoResetWaitableEvent main_latch;
AddNativeCallback(
"SayHiFromFixturesAreFunctionalMain",
CREATE_NATIVE_ENTRY([&main_latch](auto args) { main_latch.Signal(); }));
RunEngine(shell.get(), std::move(configuration));
main_latch.Wait();
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
{
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetPlatformTaskRunner(),
[this, &spawner = shell, &latch, settings]() {
MockPlatformViewDelegate platform_view_delegate;
auto spawn = spawner->Spawn(
settings,
[&platform_view_delegate](Shell& shell) {
auto result = std::make_unique<MockPlatformView>(
platform_view_delegate, shell.GetTaskRunners());
ON_CALL(*result, CreateRenderingSurface())
.WillByDefault(::testing::Invoke(
[] { return std::make_unique<MockSurface>(); }));
return result;
},
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); });
ASSERT_NE(nullptr, spawn.get());
ASSERT_TRUE(ValidateShell(spawn.get()));
DestroyShell(std::move(spawn));
latch.Signal();
});
latch.Wait();
}
DestroyShell(std::move(shell));
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
} // namespace testing
} // namespace flutter

View File

@ -28,6 +28,7 @@ _flutter_framework_headers = [
"framework/Headers/FlutterCallbackCache.h",
"framework/Headers/FlutterDartProject.h",
"framework/Headers/FlutterEngine.h",
"framework/Headers/FlutterEngineGroup.h",
"framework/Headers/FlutterHeadlessDartRunner.h",
"framework/Headers/FlutterPlatformViews.h",
"framework/Headers/FlutterPlugin.h",
@ -52,6 +53,7 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterDartProject.mm",
"framework/Source/FlutterDartProject_Internal.h",
"framework/Source/FlutterEngine.mm",
"framework/Source/FlutterEngineGroup.mm",
"framework/Source/FlutterEngine_Internal.h",
"framework/Source/FlutterHeadlessDartRunner.mm",
"framework/Source/FlutterObservatoryPublisher.h",
@ -215,6 +217,7 @@ shared_library("ios_test_flutter") {
"framework/Source/FlutterAppDelegateTest.mm",
"framework/Source/FlutterBinaryMessengerRelayTest.mm",
"framework/Source/FlutterDartProjectTest.mm",
"framework/Source/FlutterEngineGroupTest.mm",
"framework/Source/FlutterEngineTest.mm",
"framework/Source/FlutterPluginAppLifeCycleDelegateTest.m",
"framework/Source/FlutterTextInputPluginTest.m",

View File

@ -12,6 +12,7 @@
#import "FlutterCodecs.h"
#import "FlutterDartProject.h"
#import "FlutterEngine.h"
#import "FlutterEngineGroup.h"
#import "FlutterHeadlessDartRunner.h"
#import "FlutterMacros.h"
#import "FlutterPlatformViews.h"

View File

@ -0,0 +1,45 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Foundation/Foundation.h>
#import "FlutterEngine.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a collection of FlutterEngines who share resources which allows
* them to be created with less time const and occupy less memory than just
* creating multiple FlutterEngines.
*
* Deleting a FlutterEngineGroup doesn't invalidate existing FlutterEngines, but
* it eliminates the possibility to create more FlutterEngines in that group.
*
* @warning This class is a work-in-progress and may change.
* @see https://github.com/flutter/flutter/issues/72009
*/
@interface FlutterEngineGroup : NSObject
- (instancetype)init NS_UNAVAILABLE;
/**
* Initialize a new FlutterEngineGroup.
*
* @param name The name that will present in the threads shared across the
* engines in this group.
* @param project The `FlutterDartProject` that all FlutterEngines in this group
* will be executing.
*/
- (instancetype)initWithName:(NSString*)name
project:(nullable FlutterDartProject*)project NS_DESIGNATED_INITIALIZER;
/**
* Creates a running `FlutterEngine` that shares components with this group.
*
* @see FlutterEngineGroup
*/
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
libraryURI:(nullable NSString*)libraryURI;
@end
NS_ASSUME_NONNULL_END

View File

@ -34,6 +34,7 @@
NSString* const FlutterDefaultDartEntrypoint = nil;
NSString* const FlutterDefaultInitialRoute = nil;
NSString* const FlutterEngineWillDealloc = @"FlutterEngineWillDealloc";
static constexpr int kNumProfilerSamplesPerSec = 5;
@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
@ -54,7 +55,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
@implementation FlutterEngine {
fml::scoped_nsobject<FlutterDartProject> _dartProject;
flutter::ThreadHost _threadHost;
std::shared_ptr<flutter::ThreadHost> _threadHost;
std::unique_ptr<flutter::Shell> _shell;
NSString* _labelPrefix;
std::unique_ptr<fml::WeakPtrFactory<FlutterEngine>> _weakFactory;
@ -64,8 +65,8 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
std::shared_ptr<flutter::FlutterPlatformViewsController> _platformViewsController;
flutter::IOSRenderingAPI _renderingApi;
std::unique_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
std::unique_ptr<flutter::SamplingProfiler> _profiler;
std::shared_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
std::shared_ptr<flutter::SamplingProfiler> _profiler;
// Channels
fml::scoped_nsobject<FlutterPlatformPlugin> _platformPlugin;
@ -181,6 +182,10 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
}
}];
[[NSNotificationCenter defaultCenter] postNotificationName:FlutterEngineWillDealloc
object:self
userInfo:nil];
/// nil out weak references.
[_registrars
enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) {
@ -306,7 +311,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
self.isolateId = nil;
_shell.reset();
_profiler.reset();
_threadHost.Reset();
_threadHost.reset();
_platformViewsController.reset();
}
@ -368,10 +373,10 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
}
- (void)startProfiler {
FML_DCHECK(!_threadHost.name_prefix.empty());
_profiler_metrics = std::make_unique<flutter::ProfilerMetricsIOS>();
_profiler = std::make_unique<flutter::SamplingProfiler>(
_threadHost.name_prefix.c_str(), _threadHost.profiler_thread->GetTaskRunner(),
FML_DCHECK(!_threadHost->name_prefix.empty());
_profiler_metrics = std::make_shared<flutter::ProfilerMetricsIOS>();
_profiler = std::make_shared<flutter::SamplingProfiler>(
_threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(),
[self]() { return self->_profiler_metrics->GenerateSample(); }, kNumProfilerSamplesPerSec);
_profiler->Start();
}
@ -522,6 +527,20 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
threadHostType};
}
static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
if (libraryURI) {
FML_DCHECK(entrypoint) << "Must specify entrypoint if specifying library";
settings->advisory_script_entrypoint = entrypoint.UTF8String;
settings->advisory_script_uri = libraryURI.UTF8String;
} else if (entrypoint) {
settings->advisory_script_entrypoint = entrypoint.UTF8String;
settings->advisory_script_uri = std::string("main.dart");
} else {
settings->advisory_script_entrypoint = std::string("main");
settings->advisory_script_uri = std::string("main.dart");
}
}
- (BOOL)createShell:(NSString*)entrypoint
libraryURI:(NSString*)libraryURI
initialRoute:(NSString*)initialRoute {
@ -537,20 +556,11 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
auto platformData = [_dartProject.get() defaultPlatformData];
if (libraryURI) {
FML_DCHECK(entrypoint) << "Must specify entrypoint if specifying library";
settings.advisory_script_entrypoint = entrypoint.UTF8String;
settings.advisory_script_uri = libraryURI.UTF8String;
} else if (entrypoint) {
settings.advisory_script_entrypoint = entrypoint.UTF8String;
settings.advisory_script_uri = std::string("main.dart");
} else {
settings.advisory_script_entrypoint = std::string("main");
settings.advisory_script_uri = std::string("main.dart");
}
SetEntryPoint(&settings, entrypoint, libraryURI);
NSString* threadLabel = [FlutterEngine generateThreadLabel:_labelPrefix];
_threadHost = [FlutterEngine makeThreadHost:threadLabel];
_threadHost = std::make_shared<flutter::ThreadHost>();
*_threadHost = [FlutterEngine makeThreadHost:threadLabel];
// Lambda captures by pointers to ObjC objects are fine here because the
// create call is synchronous.
@ -566,9 +576,9 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
_threadHost.raster_thread->GetTaskRunner(), // raster
_threadHost.ui_thread->GetTaskRunner(), // ui
_threadHost.io_thread->GetTaskRunner() // io
_threadHost->raster_thread->GetTaskRunner(), // raster
_threadHost->ui_thread->GetTaskRunner(), // ui
_threadHost->io_thread->GetTaskRunner() // io
);
// Create the shell. This is a blocking operation.
@ -921,6 +931,40 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
});
}
- (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
libraryURI:(/*nullable*/ NSString*)libraryURI {
NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
FlutterEngine* result = [[FlutterEngine alloc] initWithName:_labelPrefix
project:_dartProject.get()
allowHeadlessExecution:_allowHeadlessExecution];
flutter::Settings settings = _shell->GetSettings();
SetEntryPoint(&settings, entrypoint, libraryURI);
flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
[self](flutter::Shell& shell) {
[self recreatePlatformViewController];
return std::make_unique<flutter::PlatformViewIOS>(
shell, self->_renderingApi, self->_platformViewsController, shell.GetTaskRunners());
};
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
[](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
std::unique_ptr<flutter::Shell> shell =
_shell->Spawn(std::move(settings), on_create_platform_view, on_create_rasterizer);
result->_threadHost = _threadHost;
result->_profiler = _profiler;
result->_profiler_metrics = _profiler_metrics;
[result setupShell:std::move(shell) withObservatoryPublication:NO];
return result;
}
- (const flutter::ThreadHost&)threadHost {
return *_threadHost;
}
@end
@implementation FlutterEngineRegistrar {

View File

@ -0,0 +1,62 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngineGroup.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h"
@interface FlutterEngineGroup ()
@property(nonatomic, copy) NSString* name;
@property(nonatomic, strong) NSMutableArray<NSValue*>* engines;
@property(nonatomic, strong) FlutterDartProject* project;
@end
@implementation FlutterEngineGroup {
int _enginesCreatedCount;
}
- (instancetype)initWithName:(NSString*)name project:(nullable FlutterDartProject*)project {
self = [super init];
if (self) {
self.name = name;
self.engines = [[NSMutableArray<NSValue*> alloc] init];
self.project = project;
}
return self;
}
- (void)dealloc {
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center removeObserver:self];
[_name release];
[_engines release];
[super dealloc];
}
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
libraryURI:(nullable NSString*)libraryURI {
NSString* engineName = [NSString stringWithFormat:@"%@.%d", self.name, ++_enginesCreatedCount];
FlutterEngine* engine;
if (self.engines.count <= 0) {
engine = [[FlutterEngine alloc] initWithName:engineName project:self.project];
[engine runWithEntrypoint:entrypoint libraryURI:libraryURI];
} else {
FlutterEngine* spawner = (FlutterEngine*)[self.engines[0] pointerValue];
engine = [spawner spawnWithEntrypoint:entrypoint libraryURI:libraryURI];
}
[_engines addObject:[NSValue valueWithPointer:engine]];
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(onEngineWillBeDealloced:)
name:FlutterEngineWillDealloc
object:engine];
return [engine autorelease];
}
- (void)onEngineWillBeDealloced:(NSNotification*)notification {
[_engines removeObject:[NSValue valueWithPointer:notification.object]];
}
@end

View File

@ -0,0 +1,43 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngineGroup.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h"
FLUTTER_ASSERT_ARC
@interface FlutterEngineGroupTest : XCTestCase
@end
@implementation FlutterEngineGroupTest
- (void)testMake {
FlutterEngineGroup* group = [[FlutterEngineGroup alloc] initWithName:@"foo" project:nil];
FlutterEngine* engine = [group makeEngineWithEntrypoint:nil libraryURI:nil];
XCTAssertNotNil(engine);
}
- (void)testSpawn {
FlutterEngineGroup* group = [[FlutterEngineGroup alloc] initWithName:@"foo" project:nil];
FlutterEngine* spawner = [group makeEngineWithEntrypoint:nil libraryURI:nil];
FlutterEngine* spawnee = [group makeEngineWithEntrypoint:nil libraryURI:nil];
XCTAssertNotNil(spawner);
XCTAssertNotNil(spawnee);
XCTAssertEqual(&spawner.threadHost, &spawnee.threadHost);
}
- (void)testDeleteLastEngine {
FlutterEngineGroup* group = [[FlutterEngineGroup alloc] initWithName:@"foo" project:nil];
@autoreleasepool {
FlutterEngine* spawner = [group makeEngineWithEntrypoint:nil libraryURI:nil];
XCTAssertNotNil(spawner);
}
FlutterEngine* spawnee = [group makeEngineWithEntrypoint:nil libraryURI:nil];
XCTAssertNotNil(spawnee);
}
@end

View File

@ -134,4 +134,28 @@ FLUTTER_ASSERT_ARC
[self waitForExpectationsWithTimeout:1 handler:nil];
}
- (void)testSpawn {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
[engine run];
FlutterEngine* spawn = [engine spawnWithEntrypoint:nil libraryURI:nil];
XCTAssertNotNil(spawn);
}
- (void)testDeallocNotification {
XCTestExpectation* deallocNotification = [self expectationWithDescription:@"deallocNotification"];
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
id<NSObject> observer;
@autoreleasepool {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
observer = [center addObserverForName:FlutterEngineWillDealloc
object:engine
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) {
[deallocNotification fulfill];
}];
}
[self waitForExpectationsWithTimeout:1 handler:nil];
[center removeObserver:observer];
}
@end

View File

@ -22,6 +22,8 @@
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
extern NSString* const FlutterEngineWillDealloc;
@interface FlutterEngine () <FlutterViewEngineDelegate>
- (flutter::Shell&)shell;
@ -49,6 +51,16 @@
- (flutter::PlatformViewIOS*)iosPlatformView;
- (void)waitForFirstFrame:(NSTimeInterval)timeout callback:(void (^)(BOOL didTimeout))callback;
/**
* Creates one running FlutterEngine from another, sharing components between them.
*
* This results in a faster creation time and a smaller memory footprint engine.
* This should only be called on a FlutterEngine that is running.
*/
- (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
libraryURI:(/*nullable*/ NSString*)libraryURI;
@end
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERENGINE_INTERNAL_H_

View File

@ -5,11 +5,20 @@
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
extern NSString* const FlutterEngineWillDealloc;
@class FlutterBinaryMessengerRelay;
namespace flutter {
class ThreadHost;
}
// Category to add test-only visibility.
@interface FlutterEngine (Test) <FlutterBinaryMessenger>
- (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger;
- (flutter::IOSRenderingAPI)platformViewsRenderingAPI;
- (void)waitForFirstFrame:(NSTimeInterval)timeout callback:(void (^)(BOOL didTimeout))callback;
- (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
libraryURI:(/*nullable*/ NSString*)libraryURI;
- (const flutter::ThreadHost&)threadHost;
@end

View File

@ -47,6 +47,7 @@ FlutterCallbackCache.html
FlutterCallbackInformation.html
FlutterDartProject.html
FlutterEngine.html
FlutterEngineGroup.html
FlutterError.html
FlutterEventChannel.html
FlutterHeadlessDartRunner.html