Flutter iOS Embedder
FlutterEngineTest.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 #import <Foundation/Foundation.h>
6 #import <OCMock/OCMock.h>
7 #import <XCTest/XCTest.h>
8 
9 #import <objc/runtime.h>
10 
11 #import "flutter/common/settings.h"
12 #include "flutter/fml/synchronization/sync_switch.h"
20 
22 
24 @property(nonatomic) BOOL ensureSemanticsEnabledCalled;
25 @end
26 
27 @implementation FlutterEngineSpy
28 
29 - (void)ensureSemanticsEnabled {
30  _ensureSemanticsEnabledCalled = YES;
31 }
32 
33 @end
34 
36 
37 @end
38 
39 /// FlutterBinaryMessengerRelay used for testing that setting FlutterEngine.binaryMessenger to
40 /// the current instance doesn't trigger a use-after-free bug.
41 ///
42 /// See: testSetBinaryMessengerToSameBinaryMessenger
44 @property(nonatomic, assign) BOOL failOnDealloc;
45 @end
46 
47 @implementation FakeBinaryMessengerRelay
48 - (void)dealloc {
49  if (_failOnDealloc) {
50  XCTFail("FakeBinaryMessageRelay should not be deallocated");
51  }
52 }
53 @end
54 
55 @interface FlutterEngineTest : XCTestCase
56 @end
57 
58 @implementation FlutterEngineTest
59 
60 - (void)setUp {
61 }
62 
63 - (void)tearDown {
64 }
65 
66 - (void)testCreate {
67  FlutterDartProject* project = [[FlutterDartProject alloc] init];
68  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
69  XCTAssertNotNil(engine);
70 }
71 
72 - (void)testInfoPlist {
73  // Check the embedded Flutter.framework Info.plist, not the linked dylib.
74  NSURL* flutterFrameworkURL =
75  [NSBundle.mainBundle.privateFrameworksURL URLByAppendingPathComponent:@"Flutter.framework"];
76  NSBundle* flutterBundle = [NSBundle bundleWithURL:flutterFrameworkURL];
77  XCTAssertEqualObjects(flutterBundle.bundleIdentifier, @"io.flutter.flutter");
78 
79  NSDictionary<NSString*, id>* infoDictionary = flutterBundle.infoDictionary;
80 
81  // OS version can have one, two, or three digits: "8", "8.0", "8.0.0"
82  NSError* regexError = NULL;
83  NSRegularExpression* osVersionRegex =
84  [NSRegularExpression regularExpressionWithPattern:@"((0|[1-9]\\d*)\\.)*(0|[1-9]\\d*)"
85  options:NSRegularExpressionCaseInsensitive
86  error:&regexError];
87  XCTAssertNil(regexError);
88 
89  // Smoke test the test regex.
90  NSString* testString = @"9";
91  NSUInteger versionMatches =
92  [osVersionRegex numberOfMatchesInString:testString
93  options:NSMatchingAnchored
94  range:NSMakeRange(0, testString.length)];
95  XCTAssertEqual(versionMatches, 1UL);
96  testString = @"9.1";
97  versionMatches = [osVersionRegex numberOfMatchesInString:testString
98  options:NSMatchingAnchored
99  range:NSMakeRange(0, testString.length)];
100  XCTAssertEqual(versionMatches, 1UL);
101  testString = @"9.0.1";
102  versionMatches = [osVersionRegex numberOfMatchesInString:testString
103  options:NSMatchingAnchored
104  range:NSMakeRange(0, testString.length)];
105  XCTAssertEqual(versionMatches, 1UL);
106  testString = @".0.1";
107  versionMatches = [osVersionRegex numberOfMatchesInString:testString
108  options:NSMatchingAnchored
109  range:NSMakeRange(0, testString.length)];
110  XCTAssertEqual(versionMatches, 0UL);
111 
112  // Test Info.plist values.
113  NSString* minimumOSVersion = infoDictionary[@"MinimumOSVersion"];
114  versionMatches = [osVersionRegex numberOfMatchesInString:minimumOSVersion
115  options:NSMatchingAnchored
116  range:NSMakeRange(0, minimumOSVersion.length)];
117  XCTAssertEqual(versionMatches, 1UL);
118 
119  // SHA length is 40.
120  XCTAssertEqual(((NSString*)infoDictionary[@"FlutterEngine"]).length, 40UL);
121 
122  // {clang_version} placeholder is 15 characters. The clang string version
123  // is longer than that, so check if the placeholder has been replaced, without
124  // actually checking a literal string, which could be different on various machines.
125  XCTAssertTrue(((NSString*)infoDictionary[@"ClangVersion"]).length > 15UL);
126 }
127 
128 - (void)testDeallocated {
129  __weak FlutterEngine* weakEngine = nil;
130  @autoreleasepool {
131  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
132  weakEngine = engine;
133  [engine run];
134  XCTAssertNotNil(weakEngine);
135  }
136  XCTAssertNil(weakEngine);
137 }
138 
139 - (void)testSendMessageBeforeRun {
140  FlutterDartProject* project = [[FlutterDartProject alloc] init];
141  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
142  XCTAssertNotNil(engine);
143  XCTAssertThrows([engine.binaryMessenger
144  sendOnChannel:@"foo"
145  message:[@"bar" dataUsingEncoding:NSUTF8StringEncoding]
146  binaryReply:nil]);
147 }
148 
149 - (void)testSetMessageHandlerBeforeRun {
150  FlutterDartProject* project = [[FlutterDartProject alloc] init];
151  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
152  XCTAssertNotNil(engine);
153  XCTAssertThrows([engine.binaryMessenger
154  setMessageHandlerOnChannel:@"foo"
155  binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply){
156 
157  }]);
158 }
159 
160 - (void)testNilSetMessageHandlerBeforeRun {
161  FlutterDartProject* project = [[FlutterDartProject alloc] init];
162  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
163  XCTAssertNotNil(engine);
164  XCTAssertNoThrow([engine.binaryMessenger setMessageHandlerOnChannel:@"foo"
165  binaryMessageHandler:nil]);
166 }
167 
168 - (void)testNotifyPluginOfDealloc {
169  id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
170  OCMStub([plugin detachFromEngineForRegistrar:[OCMArg any]]);
171  {
172  FlutterDartProject* project = [[FlutterDartProject alloc] init];
173  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"engine" project:project];
174  NSObject<FlutterPluginRegistrar>* registrar = [engine registrarForPlugin:@"plugin"];
175  [registrar publish:plugin];
176  engine = nil;
177  }
178  OCMVerify([plugin detachFromEngineForRegistrar:[OCMArg any]]);
179 }
180 
181 - (void)testSetBinaryMessengerToSameBinaryMessenger {
182  FakeBinaryMessengerRelay* fakeBinaryMessenger = [[FakeBinaryMessengerRelay alloc] init];
183 
184  FlutterEngine* engine = [[FlutterEngine alloc] init];
185  [engine setBinaryMessenger:fakeBinaryMessenger];
186 
187  // Verify that the setter doesn't free the old messenger before setting the new messenger.
188  fakeBinaryMessenger.failOnDealloc = YES;
189  [engine setBinaryMessenger:fakeBinaryMessenger];
190 
191  // Don't fail when ARC releases the binary messenger.
192  fakeBinaryMessenger.failOnDealloc = NO;
193 }
194 
195 - (void)testRunningInitialRouteSendsNavigationMessage {
196  id mockBinaryMessenger = OCMClassMock([FlutterBinaryMessengerRelay class]);
197 
198  FlutterEngine* engine = [[FlutterEngine alloc] init];
199  [engine setBinaryMessenger:mockBinaryMessenger];
200 
201  // Run with an initial route.
202  [engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"];
203 
204  // Now check that an encoded method call has been made on the binary messenger to set the
205  // initial route to "test".
206  FlutterMethodCall* setInitialRouteMethodCall =
207  [FlutterMethodCall methodCallWithMethodName:@"setInitialRoute" arguments:@"test"];
208  NSData* encodedSetInitialRouteMethod =
209  [[FlutterJSONMethodCodec sharedInstance] encodeMethodCall:setInitialRouteMethodCall];
210  OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/navigation"
211  message:encodedSetInitialRouteMethod]);
212 }
213 
214 - (void)testInitialRouteSettingsSendsNavigationMessage {
215  id mockBinaryMessenger = OCMClassMock([FlutterBinaryMessengerRelay class]);
216 
217  auto settings = FLTDefaultSettingsForBundle();
218  settings.route = "test";
219  FlutterDartProject* project = [[FlutterDartProject alloc] initWithSettings:settings];
220  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
221  [engine setBinaryMessenger:mockBinaryMessenger];
222  [engine run];
223 
224  // Now check that an encoded method call has been made on the binary messenger to set the
225  // initial route to "test".
226  FlutterMethodCall* setInitialRouteMethodCall =
227  [FlutterMethodCall methodCallWithMethodName:@"setInitialRoute" arguments:@"test"];
228  NSData* encodedSetInitialRouteMethod =
229  [[FlutterJSONMethodCodec sharedInstance] encodeMethodCall:setInitialRouteMethodCall];
230  OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/navigation"
231  message:encodedSetInitialRouteMethod]);
232 }
233 
234 - (void)testPlatformViewsControllerRenderingMetalBackend {
235  FlutterEngine* engine = [[FlutterEngine alloc] init];
236  [engine run];
237  flutter::IOSRenderingAPI renderingApi = [engine platformViewsRenderingAPI];
238 
239  XCTAssertEqual(renderingApi, flutter::IOSRenderingAPI::kMetal);
240 }
241 
242 - (void)testPlatformViewsControllerRenderingSoftware {
243  auto settings = FLTDefaultSettingsForBundle();
244  settings.enable_software_rendering = true;
245  FlutterDartProject* project = [[FlutterDartProject alloc] initWithSettings:settings];
246  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
247  [engine run];
248  flutter::IOSRenderingAPI renderingApi = [engine platformViewsRenderingAPI];
249 
250  XCTAssertEqual(renderingApi, flutter::IOSRenderingAPI::kSoftware);
251 }
252 
253 - (void)testWaitForFirstFrameTimeout {
254  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
255  [engine run];
256  XCTestExpectation* timeoutFirstFrame = [self expectationWithDescription:@"timeoutFirstFrame"];
257  [engine waitForFirstFrame:0.1
258  callback:^(BOOL didTimeout) {
259  if (timeoutFirstFrame) {
260  [timeoutFirstFrame fulfill];
261  }
262  }];
263  [self waitForExpectationsWithTimeout:5 handler:nil];
264 }
265 
266 - (void)testSpawn {
267  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
268  [engine run];
269  FlutterEngine* spawn = [engine spawnWithEntrypoint:nil
270  libraryURI:nil
271  initialRoute:nil
272  entrypointArgs:nil];
273  XCTAssertNotNil(spawn);
274 }
275 
276 - (void)testDeallocNotification {
277  XCTestExpectation* deallocNotification = [self expectationWithDescription:@"deallocNotification"];
278  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
279  id<NSObject> observer;
280  @autoreleasepool {
281  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
282  observer = [center addObserverForName:kFlutterEngineWillDealloc
283  object:engine
284  queue:[NSOperationQueue mainQueue]
285  usingBlock:^(NSNotification* note) {
286  [deallocNotification fulfill];
287  }];
288  }
289  [self waitForExpectationsWithTimeout:1 handler:nil];
290  [center removeObserver:observer];
291 }
292 
293 - (void)testSetHandlerAfterRun {
294  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
295  XCTestExpectation* gotMessage = [self expectationWithDescription:@"gotMessage"];
296  dispatch_async(dispatch_get_main_queue(), ^{
297  NSObject<FlutterPluginRegistrar>* registrar = [engine registrarForPlugin:@"foo"];
298  fml::AutoResetWaitableEvent latch;
299  [engine run];
300  flutter::Shell& shell = engine.shell;
301  engine.shell.GetTaskRunners().GetUITaskRunner()->PostTask([&latch, &shell] {
302  flutter::Engine::Delegate& delegate = shell;
303  auto message = std::make_unique<flutter::PlatformMessage>("foo", nullptr);
304  delegate.OnEngineHandlePlatformMessage(std::move(message));
305  latch.Signal();
306  });
307  latch.Wait();
308  [registrar.messenger setMessageHandlerOnChannel:@"foo"
309  binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
310  [gotMessage fulfill];
311  }];
312  });
313  [self waitForExpectationsWithTimeout:1 handler:nil];
314 }
315 
316 - (void)testThreadPrioritySetCorrectly {
317  XCTestExpectation* prioritiesSet = [self expectationWithDescription:@"prioritiesSet"];
318  prioritiesSet.expectedFulfillmentCount = 3;
319 
320  IMP mockSetThreadPriority =
321  imp_implementationWithBlock(^(NSThread* thread, double threadPriority) {
322  if ([thread.name hasSuffix:@".ui"]) {
323  XCTAssertEqual(threadPriority, 1.0);
324  [prioritiesSet fulfill];
325  } else if ([thread.name hasSuffix:@".raster"]) {
326  XCTAssertEqual(threadPriority, 1.0);
327  [prioritiesSet fulfill];
328  } else if ([thread.name hasSuffix:@".io"]) {
329  XCTAssertEqual(threadPriority, 0.5);
330  [prioritiesSet fulfill];
331  }
332  });
333  Method method = class_getInstanceMethod([NSThread class], @selector(setThreadPriority:));
334  IMP originalSetThreadPriority = method_getImplementation(method);
335  method_setImplementation(method, mockSetThreadPriority);
336 
337  FlutterEngine* engine = [[FlutterEngine alloc] init];
338  [engine run];
339  [self waitForExpectationsWithTimeout:1 handler:nil];
340 
341  method_setImplementation(method, originalSetThreadPriority);
342 }
343 
344 - (void)testCanEnableDisableEmbedderAPIThroughInfoPlist {
345  {
346  // Not enable embedder API by default
347  auto settings = FLTDefaultSettingsForBundle();
348  settings.enable_software_rendering = true;
349  FlutterDartProject* project = [[FlutterDartProject alloc] initWithSettings:settings];
350  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
351  XCTAssertFalse(engine.enableEmbedderAPI);
352  }
353  {
354  // Enable embedder api
355  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
356  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableIOSEmbedderAPI"])
357  .andReturn(@"YES");
358  auto settings = FLTDefaultSettingsForBundle();
359  settings.enable_software_rendering = true;
360  FlutterDartProject* project = [[FlutterDartProject alloc] initWithSettings:settings];
361  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
362  XCTAssertTrue(engine.enableEmbedderAPI);
363  }
364 }
365 
366 - (void)testFlutterTextInputViewDidResignFirstResponderWillCallTextInputClientConnectionClosed {
367  id mockBinaryMessenger = OCMClassMock([FlutterBinaryMessengerRelay class]);
368  FlutterEngine* engine = [[FlutterEngine alloc] init];
369  [engine setBinaryMessenger:mockBinaryMessenger];
370  [engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"];
371  [engine flutterTextInputView:nil didResignFirstResponderWithTextInputClient:1];
372  FlutterMethodCall* methodCall =
373  [FlutterMethodCall methodCallWithMethodName:@"TextInputClient.onConnectionClosed"
374  arguments:@[ @(1) ]];
375  NSData* encodedMethodCall = [[FlutterJSONMethodCodec sharedInstance] encodeMethodCall:methodCall];
376  OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/textinput" message:encodedMethodCall]);
377 }
378 
379 - (void)testFlutterEngineUpdatesDisplays {
380  FlutterEngine* engine = [[FlutterEngine alloc] init];
381  id mockEngine = OCMPartialMock(engine);
382 
383  [engine run];
384  OCMVerify(times(1), [mockEngine updateDisplays]);
385  engine.viewController = nil;
386  OCMVerify(times(2), [mockEngine updateDisplays]);
387 }
388 
389 - (void)testLifeCycleNotificationDidEnterBackground {
390  FlutterDartProject* project = [[FlutterDartProject alloc] init];
391  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
392  [engine run];
393  NSNotification* sceneNotification =
394  [NSNotification notificationWithName:UISceneDidEnterBackgroundNotification
395  object:nil
396  userInfo:nil];
397  NSNotification* applicationNotification =
398  [NSNotification notificationWithName:UIApplicationDidEnterBackgroundNotification
399  object:nil
400  userInfo:nil];
401  id mockEngine = OCMPartialMock(engine);
402  [[NSNotificationCenter defaultCenter] postNotification:sceneNotification];
403  [[NSNotificationCenter defaultCenter] postNotification:applicationNotification];
404 #if APPLICATION_EXTENSION_API_ONLY
405  OCMVerify(times(1), [mockEngine sceneDidEnterBackground:[OCMArg any]]);
406 #else
407  OCMVerify(times(1), [mockEngine applicationDidEnterBackground:[OCMArg any]]);
408 #endif
409  XCTAssertTrue(engine.isGpuDisabled);
410  bool switch_value = false;
411  [engine shell].GetIsGpuDisabledSyncSwitch()->Execute(
412  fml::SyncSwitch::Handlers().SetIfTrue([&] { switch_value = true; }).SetIfFalse([&] {
413  switch_value = false;
414  }));
415  XCTAssertTrue(switch_value);
416 }
417 
418 - (void)testLifeCycleNotificationWillEnterForeground {
419  FlutterDartProject* project = [[FlutterDartProject alloc] init];
420  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
421  [engine run];
422  NSNotification* sceneNotification =
423  [NSNotification notificationWithName:UISceneWillEnterForegroundNotification
424  object:nil
425  userInfo:nil];
426  NSNotification* applicationNotification =
427  [NSNotification notificationWithName:UIApplicationWillEnterForegroundNotification
428  object:nil
429  userInfo:nil];
430  id mockEngine = OCMPartialMock(engine);
431  [[NSNotificationCenter defaultCenter] postNotification:sceneNotification];
432  [[NSNotificationCenter defaultCenter] postNotification:applicationNotification];
433 #if APPLICATION_EXTENSION_API_ONLY
434  OCMVerify(times(1), [mockEngine sceneWillEnterForeground:[OCMArg any]]);
435 #else
436  OCMVerify(times(1), [mockEngine applicationWillEnterForeground:[OCMArg any]]);
437 #endif
438  XCTAssertFalse(engine.isGpuDisabled);
439  bool switch_value = true;
440  [engine shell].GetIsGpuDisabledSyncSwitch()->Execute(
441  fml::SyncSwitch::Handlers().SetIfTrue([&] { switch_value = true; }).SetIfFalse([&] {
442  switch_value = false;
443  }));
444  XCTAssertFalse(switch_value);
445 }
446 
447 - (void)testSpawnsShareGpuContext {
448  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar"];
449  [engine run];
450  FlutterEngine* spawn = [engine spawnWithEntrypoint:nil
451  libraryURI:nil
452  initialRoute:nil
453  entrypointArgs:nil];
454  XCTAssertNotNil(spawn);
455  XCTAssertTrue([engine iosPlatformView] != nullptr);
456  XCTAssertTrue([spawn iosPlatformView] != nullptr);
457  std::shared_ptr<flutter::IOSContext> engine_context = [engine iosPlatformView]->GetIosContext();
458  std::shared_ptr<flutter::IOSContext> spawn_context = [spawn iosPlatformView]->GetIosContext();
459  XCTAssertEqual(engine_context, spawn_context);
460  // If this assert fails it means we may be using the software. For software rendering, this is
461  // expected to be nullptr.
462  XCTAssertTrue(engine_context->GetMainContext() != nullptr);
463  XCTAssertEqual(engine_context->GetMainContext(), spawn_context->GetMainContext());
464 }
465 
466 - (void)testEnableSemanticsWhenFlutterViewAccessibilityDidCall {
467  FlutterEngineSpy* engine = [[FlutterEngineSpy alloc] initWithName:@"foobar"];
468  engine.ensureSemanticsEnabledCalled = NO;
469  [engine flutterViewAccessibilityDidCall];
470  XCTAssertTrue(engine.ensureSemanticsEnabledCalled);
471 }
472 
473 @end
FlutterEngine
Definition: FlutterEngine.h:61
FlutterPlugin-p
Definition: FlutterPlugin.h:189
FlutterTextInputDelegate-p
Definition: FlutterTextInputDelegate.h:37
-[FlutterEngine waitForFirstFrame:callback:]
void waitForFirstFrame:callback:(NSTimeInterval timeout,[callback] void(^ callback)(BOOL didTimeout))
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
-[FlutterEngine platformViewsRenderingAPI]
flutter::IOSRenderingAPI platformViewsRenderingAPI()
FlutterEngineSpy::ensureSemanticsEnabledCalled
BOOL ensureSemanticsEnabledCalled
Definition: FlutterEngineTest.mm:24
FlutterEngine_Test.h
-[FlutterEngine ensureSemanticsEnabled]
void ensureSemanticsEnabled()
Definition: FlutterEngine.mm:421
FlutterTextInputPlugin.h
FlutterEngine_Internal.h
-[FlutterEngine(Test) shell]
flutter::Shell & shell()
FlutterEngineSpy
Definition: FlutterEngineTest.mm:23
FlutterMacros.h
-[FlutterEngine setBinaryMessenger:]
void setBinaryMessenger:(FlutterBinaryMessengerRelay *binaryMessenger)
-[FlutterEngine(Test) updateDisplays]
void updateDisplays()
-[FlutterEngine shell]
flutter::Shell & shell()
FlutterBinaryMessengerRelay.h
FakeBinaryMessengerRelay::failOnDealloc
BOOL failOnDealloc
Definition: FlutterEngineTest.mm:44
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterEngineTest
Definition: FlutterEngineTest.mm:55
flutter::IOSRenderingAPI
IOSRenderingAPI
Definition: rendering_api_selection.h:14
-[FlutterPluginRegistry-p registrarForPlugin:]
nullable NSObject< FlutterPluginRegistrar > * registrarForPlugin:(NSString *pluginKey)
flutter::IOSRenderingAPI::kMetal
@ kMetal
FakeBinaryMessengerRelay
Definition: FlutterEngineTest.mm:43
engine
id engine
Definition: FlutterTextInputPluginTest.mm:89
FlutterDartProject_Internal.h
FlutterBinaryMessengerRelay
Definition: FlutterBinaryMessengerRelay.h:14
FlutterJSONMethodCodec
Definition: FlutterCodecs.h:455
platform_view_ios.h
FLTDefaultSettingsForBundle
flutter::Settings FLTDefaultSettingsForBundle(NSBundle *bundle, NSProcessInfo *processInfoOrNil)
Definition: FlutterDartProject.mm:46
FlutterDartProject
Definition: FlutterDartProject.mm:262
-[FlutterEngine runWithEntrypoint:initialRoute:]
BOOL runWithEntrypoint:initialRoute:(nullable NSString *entrypoint,[initialRoute] nullable NSString *initialRoute)
-[FlutterEngine spawnWithEntrypoint:libraryURI:initialRoute:entrypointArgs:]
FlutterEngine * spawnWithEntrypoint:libraryURI:initialRoute:entrypointArgs:(/*nullable */NSString *entrypoint,[libraryURI]/*nullable */NSString *libraryURI,[initialRoute]/*nullable */NSString *initialRoute,[entrypointArgs]/*nullable */NSArray< NSString * > *entrypointArgs)
-[FlutterEngine run]
BOOL run()
Definition: FlutterEngine.mm:937
flutter::IOSRenderingAPI::kSoftware
@ kSoftware
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)