Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
AppDelegate.m
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 "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@interface FlutterEngine ()
20@property(nonatomic, strong) FlutterMethodChannel* statusBarChannel;
21@end
22
23@implementation NoStatusBarViewController
24- (BOOL)prefersStatusBarHidden {
25 return YES;
26}
27@end
28
29// The FlutterViewController version of NoStatusBarViewController
31
32@end
33
35- (BOOL)prefersStatusBarHidden {
36 return YES;
37}
38@end
39
40@implementation AppDelegate
41
42- (BOOL)application:(UIApplication*)application
43 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
44 NSArray<NSString*>* processArguments = NSProcessInfo.processInfo.arguments;
45 if ([processArguments containsObject:@"--enable-software-rendering"]) {
46 @throw @"--enable-software-rendering is unsupported in iOS scenario tests";
47 }
48
49 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
50 if ([processArguments containsObject:@"--maskview-blocking"]) {
51 self.window.tintColor = UIColor.systemPinkColor;
52 }
53 NSDictionary<NSString*, NSString*>* launchArgsMap = @{
54 // The golden test args should match `GoldenTestManager`.
55 @"--locale-initialization" : @"locale_initialization",
56 @"--platform-view" : @"platform_view",
57 @"--platform-view-no-overlay-intersection" : @"platform_view_no_overlay_intersection",
58 @"--platform-view-two-intersecting-overlays" : @"platform_view_two_intersecting_overlays",
59 @"--platform-view-partial-intersection" : @"platform_view_partial_intersection",
60 @"--platform-view-one-overlay-two-intersecting-overlays" :
61 @"platform_view_one_overlay_two_intersecting_overlays",
62 @"--platform-view-multiple-without-overlays" : @"platform_view_multiple_without_overlays",
63 @"--platform-view-max-overlays" : @"platform_view_max_overlays",
64 @"--platform-view-surrounding-layers-fractional-coordinate" :
65 @"platform_view_surrounding_layers_fractional_coordinate",
66 @"--platform-view-partial-intersection-fractional-coordinate" :
67 @"platform_view_partial_intersection_fractional_coordinate",
68 @"--platform-view-multiple" : @"platform_view_multiple",
69 @"--platform-view-multiple-background-foreground" :
70 @"platform_view_multiple_background_foreground",
71 @"--platform-view-cliprect" : @"platform_view_cliprect",
72 @"--platform-view-cliprect-multiple-clips" : @"platform_view_cliprect_multiple_clips",
73 @"--platform-view-cliprrect" : @"platform_view_cliprrect",
74 @"--platform-view-cliprrect-multiple-clips" : @"platform_view_cliprrect_multiple_clips",
75 @"--platform-view-large-cliprrect" : @"platform_view_large_cliprrect",
76 @"--platform-view-large-cliprrect-multiple-clips" :
77 @"platform_view_large_cliprrect_multiple_clips",
78 @"--platform-view-clippath" : @"platform_view_clippath",
79 @"--platform-view-clippath-multiple-clips" : @"platform_view_clippath_multiple_clips",
80 @"--platform-view-cliprrect-with-transform" : @"platform_view_cliprrect_with_transform",
81 @"--platform-view-cliprrect-with-transform-multiple-clips" :
82 @"platform_view_cliprrect_with_transform_multiple_clips",
83 @"--platform-view-large-cliprrect-with-transform" :
84 @"platform_view_large_cliprrect_with_transform",
85 @"--platform-view-large-cliprrect-with-transform-multiple-clips" :
86 @"platform_view_large_cliprrect_with_transform_multiple_clips",
87 @"--platform-view-cliprect-with-transform" : @"platform_view_cliprect_with_transform",
88 @"--platform-view-cliprect-with-transform-multiple-clips" :
89 @"platform_view_cliprect_with_transform_multiple_clips",
90 @"--platform-view-clippath-with-transform" : @"platform_view_clippath_with_transform",
91 @"--platform-view-clippath-with-transform-multiple-clips" :
92 @"platform_view_clippath_with_transform_multiple_clips",
93 @"--platform-view-transform" : @"platform_view_transform",
94 @"--platform-view-opacity" : @"platform_view_opacity",
95 @"--platform-view-with-other-backdrop-filter" : @"platform_view_with_other_backdrop_filter",
96 @"--two-platform-views-with-other-backdrop-filter" :
97 @"two_platform_views_with_other_backdrop_filter",
98 @"--platform-view-with-negative-backdrop-filter" :
99 @"platform_view_with_negative_backdrop_filter",
100 @"--platform-view-rotate" : @"platform_view_rotate",
101 @"--non-full-screen-flutter-view-platform-view" : @"non_full_screen_flutter_view_platform_view",
102 @"--gesture-reject-after-touches-ended" : @"platform_view_gesture_reject_after_touches_ended",
103 @"--gesture-reject-eager" : @"platform_view_gesture_reject_eager",
104 @"--gesture-accept" : @"platform_view_gesture_accept",
105 @"--gesture-accept-with-overlapping-platform-views" :
106 @"platform_view_gesture_accept_with_overlapping_platform_views",
107 @"--tap-status-bar" : @"tap_status_bar",
108 @"--animated-color-square" : @"animated_color_square",
109 @"--solid-blue" : @"solid_blue",
110 @"--platform-view-with-continuous-texture" : @"platform_view_with_continuous_texture",
111 @"--bogus-font-text" : @"bogus_font_text",
112 @"--spawn-engine-works" : @"spawn_engine_works",
113 @"--pointer-events" : @"pointer_events",
114 @"--platform-view-scrolling-under-widget" : @"platform_view_scrolling_under_widget",
115 @"--platform-views-with-clips-scrolling" : @"platform_views_with_clips_scrolling",
116 @"--platform-views-with-clips-scrolling-multiple-clips" :
117 @"platform_views_with_clips_scrolling_multiple_clips",
118 @"--platform-view-cliprect-after-moved" : @"platform_view_cliprect_after_moved",
119 @"--platform-view-cliprect-after-moved-multiple-clips" :
120 @"platform_view_cliprect_after_moved_multiple_clips",
121 @"--two-platform-view-clip-rect" : @"two_platform_view_clip_rect",
122 @"--two-platform-view-clip-rect-multiple-clips" : @"two_platform_view_clip_rect_multiple_clips",
123 @"--two-platform-view-clip-rrect" : @"two_platform_view_clip_rrect",
124 @"--two-platform-view-clip-rrect-multiple-clips" :
125 @"two_platform_view_clip_rrect_multiple_clips",
126 @"--two-platform-view-clip-path" : @"two_platform_view_clip_path",
127 @"--two-platform-view-clip-path-multiple-clips" : @"two_platform_view_clip_path_multiple_clips",
128 @"--darwin-system-font" : @"darwin_system_font",
129 };
130 __block NSString* flutterViewControllerTestName = nil;
131 [launchArgsMap
132 enumerateKeysAndObjectsUsingBlock:^(NSString* argument, NSString* testName, BOOL* stop) {
133 if ([processArguments containsObject:argument]) {
134 flutterViewControllerTestName = testName;
135 *stop = YES;
136 }
137 }];
138 if (flutterViewControllerTestName) {
139 [self setupFlutterViewControllerTest:flutterViewControllerTestName];
140 } else if ([processArguments containsObject:@"--screen-before-flutter"]) {
141 self.window.rootViewController = [[ScreenBeforeFlutter alloc] initWithEngineRunCompletion:nil];
142 } else {
143 self.window.rootViewController = [[UIViewController alloc] init];
144 }
145
146 [self.window makeKeyAndVisible];
147 if ([processArguments containsObject:@"--with-continuous-texture"]) {
149 registerWithRegistrar:[self registrarForPlugin:@"com.constant.firing.texture"]];
150 }
151 return [super application:application didFinishLaunchingWithOptions:launchOptions];
152}
153
154- (FlutterEngine*)engineForTest:(NSString*)scenarioIdentifier {
155 if ([scenarioIdentifier isEqualToString:@"spawn_engine_works"]) {
156 FlutterEngine* spawner = [[FlutterEngine alloc] initWithName:@"FlutterControllerTest"
157 project:nil];
158 [spawner run];
159 return [spawner spawnWithEntrypoint:nil libraryURI:nil initialRoute:nil entrypointArgs:nil];
160 } else {
161 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"FlutterControllerTest"
162 project:nil];
163 [engine run];
164 return engine;
165 }
166}
167
168- (FlutterViewController*)flutterViewControllerForTest:(NSString*)scenarioIdentifier
169 withEngine:(FlutterEngine*)engine {
170 if ([scenarioIdentifier isEqualToString:@"tap_status_bar"]) {
171 return [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
172 } else {
173 return [[NoStatusBarFlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
174 }
175}
176
177- (void)setupFlutterViewControllerTest:(NSString*)scenarioIdentifier {
178 FlutterEngine* engine = [self engineForTest:scenarioIdentifier];
179 FlutterViewController* flutterViewController =
180 [self flutterViewControllerForTest:scenarioIdentifier withEngine:engine];
181 flutterViewController.view.accessibilityIdentifier = @"flutter_view";
182
183 [engine.binaryMessenger
184 setMessageHandlerOnChannel:@"waiting_for_status"
185 binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
187 methodChannelWithName:@"driver"
188 binaryMessenger:engine.binaryMessenger
189 codec:[FlutterJSONMethodCodec sharedInstance]];
190 [channel invokeMethod:@"set_scenario" arguments:@{@"name" : scenarioIdentifier}];
191 }];
192 // Can be used to synchronize timing in the test for a signal from Dart.
193 [engine.binaryMessenger
194 setMessageHandlerOnChannel:@"display_data"
195 binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
196 NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:message
197 options:0
198 error:nil];
199 UITextField* text = [[UITextField alloc] initWithFrame:CGRectMake(0, 400, 300, 100)];
200 text.text = dict[@"data"];
201 [flutterViewController.view addSubview:text];
202 }];
203
204 TextPlatformViewFactory* textPlatformViewFactory =
205 [[TextPlatformViewFactory alloc] initWithMessenger:engine.binaryMessenger];
206 NSObject<FlutterPluginRegistrar>* registrar =
207 [engine registrarForPlugin:@"scenarios/TextPlatformViewPlugin"];
208 [registrar registerViewFactory:textPlatformViewFactory
209 withId:@"scenarios/textPlatformView"
210 gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
211 [registrar registerViewFactory:textPlatformViewFactory
212 withId:@"scenarios/textPlatformView_blockPolicyUntilTouchesEnded"
213 gestureRecognizersBlockingPolicy:
214 FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded];
215
216 UIViewController* rootViewController = flutterViewController;
217 if ([scenarioIdentifier isEqualToString:@"non_full_screen_flutter_view_platform_view"]) {
218 // Make Flutter View's origin x/y not 0.
219 rootViewController = [[NoStatusBarViewController alloc] init];
220 [rootViewController.view addSubview:flutterViewController.view];
221 flutterViewController.view.frame = CGRectMake(150, 150, 500, 500);
222 } else if ([scenarioIdentifier isEqualToString:@"tap_status_bar"]) {
223 [engine.binaryMessenger
224 setMessageHandlerOnChannel:@"flutter/status_bar"
225 binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
226 NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:message
227 options:0
228 error:nil];
229 FlutterBasicMessageChannel* channel = [[FlutterBasicMessageChannel alloc]
230 initWithName:@"display_data"
231 binaryMessenger:engine.binaryMessenger
233 [channel sendMessage:@{@"data" : dict}];
234 UITextField* text =
235 [[UITextField alloc] initWithFrame:CGRectMake(0, 400, 300, 100)];
236 text.text = dict[@"method"];
237 [flutterViewController.view addSubview:text];
238 }];
239 }
240
241 self.window.rootViewController = rootViewController;
242}
243
244@end
NS_ASSUME_NONNULL_BEGIN NSDictionary * launchArgsMap
FlutterEngine engine
Definition main.cc:84
FlutterEngine * spawnWithEntrypoint:libraryURI:initialRoute:entrypointArgs:(nullable NSString *entrypoint,[libraryURI] nullable NSString *libraryURI,[initialRoute] nullable NSString *initialRoute,[entrypointArgs] nullable NSArray< NSString * > *entrypointArgs)
instancetype methodChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
instancetype sharedInstance()
void registerWithRegistrar:(NSObject< FlutterPluginRegistrar > *registrar)
nullable NSObject< FlutterPluginRegistrar > * registrarForPlugin:(NSString *pluginKey)
int BOOL