Flutter Engine
The Flutter Engine
AppDelegate.m
Go to the documentation of this file.
1// Copyright 2019 The Chromium 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 "AppDelegate.h"
6
10#import "TextPlatformView.h"
11
12// A UIViewController that sets YES for its preferedStatusBarHidden property.
13// StatusBar includes current time, which is non-deterministic. This ViewController
14// removes the StatusBar to make the screenshot deterministic.
15@interface NoStatusBarViewController : UIViewController
16
17@end
18
19@implementation NoStatusBarViewController
21 return YES;
22}
23@end
24
25// The FlutterViewController version of NoStatusBarViewController
27
28@end
29
32 return YES;
33}
34@end
35
36@implementation AppDelegate
37
38- (BOOL)application:(UIApplication*)application
39 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
40 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
41 if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--maskview-blocking"]) {
42 self.window.tintColor = UIColor.systemPinkColor;
43 }
44 NSDictionary<NSString*, NSString*>* launchArgsMap = @{
45 // The golden test args should match `GoldenTestManager`.
46 @"--locale-initialization" : @"locale_initialization",
47 @"--platform-view" : @"platform_view",
48 @"--platform-view-no-overlay-intersection" : @"platform_view_no_overlay_intersection",
49 @"--platform-view-two-intersecting-overlays" : @"platform_view_two_intersecting_overlays",
50 @"--platform-view-partial-intersection" : @"platform_view_partial_intersection",
51 @"--platform-view-one-overlay-two-intersecting-overlays" :
52 @"platform_view_one_overlay_two_intersecting_overlays",
53 @"--platform-view-multiple-without-overlays" : @"platform_view_multiple_without_overlays",
54 @"--platform-view-max-overlays" : @"platform_view_max_overlays",
55 @"--platform-view-surrounding-layers-fractional-coordinate" :
56 @"platform_view_surrounding_layers_fractional_coordinate",
57 @"--platform-view-partial-intersection-fractional-coordinate" :
58 @"platform_view_partial_intersection_fractional_coordinate",
59 @"--platform-view-multiple" : @"platform_view_multiple",
60 @"--platform-view-multiple-background-foreground" :
61 @"platform_view_multiple_background_foreground",
62 @"--platform-view-cliprect" : @"platform_view_cliprect",
63 @"--platform-view-cliprrect" : @"platform_view_cliprrect",
64 @"--platform-view-large-cliprrect" : @"platform_view_large_cliprrect",
65 @"--platform-view-clippath" : @"platform_view_clippath",
66 @"--platform-view-cliprrect-with-transform" : @"platform_view_cliprrect_with_transform",
67 @"--platform-view-large-cliprrect-with-transform" :
68 @"platform_view_large_cliprrect_with_transform",
69 @"--platform-view-cliprect-with-transform" : @"platform_view_cliprect_with_transform",
70 @"--platform-view-clippath-with-transform" : @"platform_view_clippath_with_transform",
71 @"--platform-view-transform" : @"platform_view_transform",
72 @"--platform-view-opacity" : @"platform_view_opacity",
73 @"--platform-view-with-other-backdrop-filter" : @"platform_view_with_other_backdrop_filter",
74 @"--two-platform-views-with-other-backdrop-filter" :
75 @"two_platform_views_with_other_backdrop_filter",
76 @"--platform-view-with-negative-backdrop-filter" :
77 @"platform_view_with_negative_backdrop_filter",
78 @"--platform-view-rotate" : @"platform_view_rotate",
79 @"--non-full-screen-flutter-view-platform-view" : @"non_full_screen_flutter_view_platform_view",
80 @"--gesture-reject-after-touches-ended" : @"platform_view_gesture_reject_after_touches_ended",
81 @"--gesture-reject-eager" : @"platform_view_gesture_reject_eager",
82 @"--gesture-accept" : @"platform_view_gesture_accept",
83 @"--gesture-accept-with-overlapping-platform-views" :
84 @"platform_view_gesture_accept_with_overlapping_platform_views",
85 @"--tap-status-bar" : @"tap_status_bar",
86 @"--animated-color-square" : @"animated_color_square",
87 @"--solid-blue" : @"solid_blue",
88 @"--platform-view-with-continuous-texture" : @"platform_view_with_continuous_texture",
89 @"--bogus-font-text" : @"bogus_font_text",
90 @"--spawn-engine-works" : @"spawn_engine_works",
91 @"--pointer-events" : @"pointer_events",
92 @"--platform-view-scrolling-under-widget" : @"platform_view_scrolling_under_widget",
93 @"--platform-views-with-clips-scrolling" : @"platform_views_with_clips_scrolling",
94 @"--platform-view-cliprect-after-moved" : @"platform_view_cliprect_after_moved",
95 @"--two-platform-view-clip-rect" : @"two_platform_view_clip_rect",
96 @"--two-platform-view-clip-rrect" : @"two_platform_view_clip_rrect",
97 @"--two-platform-view-clip-path" : @"two_platform_view_clip_path",
98 @"--darwin-system-font" : @"darwin_system_font",
99 };
100 __block NSString* flutterViewControllerTestName = nil;
101 [launchArgsMap
102 enumerateKeysAndObjectsUsingBlock:^(NSString* argument, NSString* testName, BOOL* stop) {
103 if ([[[NSProcessInfo processInfo] arguments] containsObject:argument]) {
104 flutterViewControllerTestName = testName;
105 *stop = YES;
106 }
107 }];
108 if (flutterViewControllerTestName) {
109 [self setupFlutterViewControllerTest:flutterViewControllerTestName];
110 } else if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--screen-before-flutter"]) {
111 self.window.rootViewController = [[ScreenBeforeFlutter alloc] initWithEngineRunCompletion:nil];
112 } else {
113 self.window.rootViewController = [[UIViewController alloc] init];
114 }
115
116 [self.window makeKeyAndVisible];
117 if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--with-continuous-texture"]) {
119 registerWithRegistrar:[self registrarForPlugin:@"com.constant.firing.texture"]];
120 }
121 return [super application:application didFinishLaunchingWithOptions:launchOptions];
122}
123
124- (FlutterEngine*)engineForTest:(NSString*)scenarioIdentifier {
125 if ([scenarioIdentifier isEqualToString:@"spawn_engine_works"]) {
126 FlutterEngine* spawner = [[FlutterEngine alloc] initWithName:@"FlutterControllerTest"
127 project:nil];
128 [spawner run];
129 return [spawner spawnWithEntrypoint:nil libraryURI:nil initialRoute:nil entrypointArgs:nil];
130 } else {
131 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"FlutterControllerTest"
132 project:nil];
133 [engine run];
134 return engine;
135 }
136}
137
138- (FlutterViewController*)flutterViewControllerForTest:(NSString*)scenarioIdentifier
139 withEngine:(FlutterEngine*)engine {
140 if ([scenarioIdentifier isEqualToString:@"tap_status_bar"]) {
141 return [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
142 } else {
143 return [[NoStatusBarFlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
144 }
145}
146
147- (void)setupFlutterViewControllerTest:(NSString*)scenarioIdentifier {
148 FlutterEngine* engine = [self engineForTest:scenarioIdentifier];
149 FlutterViewController* flutterViewController =
150 [self flutterViewControllerForTest:scenarioIdentifier withEngine:engine];
151 flutterViewController.view.accessibilityIdentifier = @"flutter_view";
152
153 [engine.binaryMessenger
154 setMessageHandlerOnChannel:@"waiting_for_status"
155 binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
157 methodChannelWithName:@"driver"
158 binaryMessenger:engine.binaryMessenger
160 [channel invokeMethod:@"set_scenario" arguments:@{@"name" : scenarioIdentifier}];
161 }];
162 // Can be used to synchronize timing in the test for a signal from Dart.
163 [engine.binaryMessenger
164 setMessageHandlerOnChannel:@"display_data"
165 binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
166 NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:message
167 options:0
168 error:nil];
169 UITextField* text = [[UITextField alloc] initWithFrame:CGRectMake(0, 400, 300, 100)];
170 text.text = dict[@"data"];
171 [flutterViewController.view addSubview:text];
172 }];
173
174 TextPlatformViewFactory* textPlatformViewFactory =
175 [[TextPlatformViewFactory alloc] initWithMessenger:engine.binaryMessenger];
176 NSObject<FlutterPluginRegistrar>* registrar =
177 [engine registrarForPlugin:@"scenarios/TextPlatformViewPlugin"];
178 [registrar registerViewFactory:textPlatformViewFactory
179 withId:@"scenarios/textPlatformView"
180 gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
181 [registrar registerViewFactory:textPlatformViewFactory
182 withId:@"scenarios/textPlatformView_blockPolicyUntilTouchesEnded"
183 gestureRecognizersBlockingPolicy:
184 FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded];
185
186 UIViewController* rootViewController = flutterViewController;
187 // Make Flutter View's origin x/y not 0.
188 if ([scenarioIdentifier isEqualToString:@"non_full_screen_flutter_view_platform_view"]) {
189 rootViewController = [[NoStatusBarViewController alloc] init];
190 [rootViewController.view addSubview:flutterViewController.view];
191 flutterViewController.view.frame = CGRectMake(150, 150, 500, 500);
192 }
193
194 self.window.rootViewController = rootViewController;
195
196 if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--assert-ca-layer-type"]) {
197 if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--enable-software-rendering"]) {
198 NSAssert([flutterViewController.view.layer isKindOfClass:[CALayer class]],
199 @"Expected CALayer for software rendering.");
200 } else {
201 NSAssert([flutterViewController.view.layer isKindOfClass:[CAMetalLayer class]],
202 @"Expected CAMetalLayer for non-software rendering.");
203 }
204 }
205}
206
207@end
NS_ASSUME_NONNULL_BEGIN NSDictionary * launchArgsMap
FlutterEngine engine
Definition: main.cc:68
UIWindow * window
Definition: AppDelegate.h:12
void registerWithRegistrar:(nonnull NSObject< FlutterPluginRegistrar > *registrar)
FlutterBinaryMessengerConnection setMessageHandlerOnChannel:binaryMessageHandler:(NSString *channel, [binaryMessageHandler] FlutterBinaryMessageHandler handler)
NSObject< FlutterPluginRegistrar > * registrarForPlugin:(NSString *pluginKey)
FlutterEngine * spawnWithEntrypoint:libraryURI:initialRoute:entrypointArgs:(/*nullable */NSString *entrypoint, [libraryURI]/*nullable */NSString *libraryURI, [initialRoute]/*nullable */NSString *initialRoute, [entrypointArgs]/*nullable */NSArray< NSString * > *entrypointArgs)
instancetype sharedInstance()
instancetype methodChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
NSObject< FlutterPluginRegistrar > * registrarForPlugin:(NSString *pluginKey)
int BOOL
Definition: windows_types.h:37