| Flutter iOS Embedder |

FlutterPlatformPluginTest.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 <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
7
8 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
9 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
10 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
11 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h"
13 #import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
14
15 FLUTTER_ASSERT_ARC
16
17 @interface FlutterPlatformPluginTest : XCTestCase
18 @end
19
20 @interface FlutterPlatformPlugin ()
21 - (BOOL)isLiveTextInputAvailable;
22 - (void)searchWeb:(NSString*)searchTerm;
23 - (void)showLookUpViewController:(NSString*)term;
24 - (void)showShareViewController:(NSString*)content;
25 - (void)playSystemSound:(NSString*)soundType;
26 - (void)vibrateHapticFeedback:(NSString*)feedbackType;
27 @end
28
29 @interface UIViewController ()
30 - (void)presentViewController:(UIViewController*)viewControllerToPresent
31 animated:(BOOL)flag
32 completion:(void (^)(void))completion;
33 @end
34
35 @implementation FlutterPlatformPluginTest
36
37 - (void)testSearchWebInvokedWithEscapedTerm {
38 id mockApplication = OCMClassMock([UIApplication class]);
39 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
40
41 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
42 [engine runWithEntrypoint:nil];
43
44 XCTestExpectation* invokeExpectation =
45 [self expectationWithDescription:@"Web search launched with escaped search term"];
46
47 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
48 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
49
50 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
51 arguments:@"Testing Word!"];
52
53 FlutterResult result = ^(id result) {
54 OCMVerify([mockPlugin searchWeb:@"Testing Word!"]);
55 OCMVerify([mockApplication openURL:[NSURL URLWithString:@"x-web-search://?Testing%20Word!"]
56 options:@{}
57 completionHandler:nil]);
58 [invokeExpectation fulfill];
59 };
60
61 [mockPlugin handleMethodCall:methodCall result:result];
62 [self waitForExpectationsWithTimeout:1 handler:nil];
63 [mockApplication stopMocking];
64 }
65
66 - (void)testSearchWebSkippedIfAppExtension {
67 id mockBundle = OCMPartialMock([NSBundle mainBundle]);
68 OCMStub([mockBundle objectForInfoDictionaryKey:@"NSExtension"]).andReturn(@{
69 @"NSExtensionPointIdentifier" : @"com.apple.share-services"
70 });
71 id mockApplication = OCMClassMock([UIApplication class]);
72 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
73 OCMReject([mockApplication openURL:OCMOCK_ANY options:OCMOCK_ANY completionHandler:OCMOCK_ANY]);
74 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
75 [engine runWithEntrypoint:nil];
76
77 XCTestExpectation* invokeExpectation =
78 [self expectationWithDescription:@"Web search launched with non escaped search term"];
79
80 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
81 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
82
83 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
84 arguments:@"Test"];
85
86 FlutterResult result = ^(id result) {
87 OCMVerify([mockPlugin searchWeb:@"Test"]);
88
89 [invokeExpectation fulfill];
90 };
91
92 [mockPlugin handleMethodCall:methodCall result:result];
93 [self waitForExpectationsWithTimeout:1 handler:nil];
94 [mockBundle stopMocking];
95 [mockApplication stopMocking];
96 }
97
98 - (void)testLookUpCallInitiated {
99 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
100 [engine runWithEntrypoint:nil];
101
102 XCTestExpectation* presentExpectation =
103 [self expectationWithDescription:@"Look Up view controller presented"];
104
105 FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
106 nibName:nil
107 bundle:nil];
108 FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
109
110 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
111 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
112
113 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"LookUp.invoke"
114 arguments:@"Test"];
115 FlutterResult result = ^(id result) {
116 OCMVerify([mockEngineViewController
117 presentViewController:[OCMArg isKindOfClass:[UIReferenceLibraryViewController class]]
118 animated:YES
119 completion:nil]);
120 [presentExpectation fulfill];
121 };
122 [mockPlugin handleMethodCall:methodCall result:result];
123 [self waitForExpectationsWithTimeout:2 handler:nil];
124 }
125
126 - (void)testShareScreenInvoked {
127 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
128 [engine runWithEntrypoint:nil];
129
130 XCTestExpectation* presentExpectation =
131 [self expectationWithDescription:@"Share view controller presented"];
132
133 FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
134 nibName:nil
135 bundle:nil];
136 FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
137 OCMStub([mockEngineViewController
138 presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
139 animated:YES
140 completion:nil]);
141
142 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
143 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
144
145 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke"
146 arguments:@"Test"];
147 FlutterResult result = ^(id result) {
148 OCMVerify([mockEngineViewController
149 presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
150 animated:YES
151 completion:nil]);
152 [presentExpectation fulfill];
153 };
154 [mockPlugin handleMethodCall:methodCall result:result];
155 [self waitForExpectationsWithTimeout:1 handler:nil];
156 }
157
158 - (void)testShareScreenInvokedOnIPad {
159 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
160 [engine runWithEntrypoint:nil];
161
162 XCTestExpectation* presentExpectation =
163 [self expectationWithDescription:@"Share view controller presented on iPad"];
164
165 FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
166 nibName:nil
167 bundle:nil];
168 FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
169 OCMStub([mockEngineViewController
170 presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
171 animated:YES
172 completion:nil]);
173
174 id mockTraitCollection = OCMClassMock([UITraitCollection class]);
175 OCMStub([mockTraitCollection userInterfaceIdiom]).andReturn(UIUserInterfaceIdiomPad);
176
177 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
178 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
179
180 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke"
181 arguments:@"Test"];
182 FlutterResult result = ^(id result) {
183 OCMVerify([mockEngineViewController
184 presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
185 animated:YES
186 completion:nil]);
187 [presentExpectation fulfill];
188 };
189 [mockPlugin handleMethodCall:methodCall result:result];
190 [self waitForExpectationsWithTimeout:1 handler:nil];
191 }
192
193 - (void)testClipboardHasCorrectStrings {
194 [UIPasteboard generalPasteboard].string = nil;
195 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
196 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
197
198 XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setString"];
199 FlutterResult resultSet = ^(id result) {
200 [setStringExpectation fulfill];
201 };
202 FlutterMethodCall* methodCallSet =
203 [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData"
204 arguments:@{@"text" : @"some string"}];
205 [plugin handleMethodCall:methodCallSet result:resultSet];
206 [self waitForExpectationsWithTimeout:1 handler:nil];
207
208 XCTestExpectation* hasStringsExpectation = [self expectationWithDescription:@"hasStrings"];
209 FlutterResult result = ^(id result) {
210 XCTAssertTrue([result[@"value"] boolValue]);
211 [hasStringsExpectation fulfill];
212 };
213 FlutterMethodCall* methodCall =
214 [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil];
215 [plugin handleMethodCall:methodCall result:result];
216 [self waitForExpectationsWithTimeout:1 handler:nil];
217
218 XCTestExpectation* getDataExpectation = [self expectationWithDescription:@"getData"];
219 FlutterResult getDataResult = ^(id result) {
220 XCTAssertEqualObjects(result[@"text"], @"some string");
221 [getDataExpectation fulfill];
222 };
223 FlutterMethodCall* methodCallGetData =
224 [FlutterMethodCall methodCallWithMethodName:@"Clipboard.getData" arguments:@"text/plain"];
225 [plugin handleMethodCall:methodCallGetData result:getDataResult];
226 [self waitForExpectationsWithTimeout:1 handler:nil];
227 }
228
229 - (void)testClipboardSetDataToNullDoNotCrash {
230 [UIPasteboard generalPasteboard].string = nil;
231 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
232 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
233
234 XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setData"];
235 FlutterResult resultSet = ^(id result) {
236 [setStringExpectation fulfill];
237 };
238 FlutterMethodCall* methodCallSet =
239 [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData"
240 arguments:@{@"text" : [NSNull null]}];
241 [plugin handleMethodCall:methodCallSet result:resultSet];
242
243 XCTestExpectation* getDataExpectation = [self expectationWithDescription:@"getData"];
244 FlutterResult result = ^(id result) {
245 XCTAssertEqualObjects(result[@"text"], @"null");
246 [getDataExpectation fulfill];
247 };
248 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.getData"
249 arguments:@"text/plain"];
250 [plugin handleMethodCall:methodCall result:result];
251 [self waitForExpectationsWithTimeout:1 handler:nil];
252 }
253
254 - (void)testPopSystemNavigator {
255 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
256 [engine runWithEntrypoint:nil];
257 FlutterViewController* flutterViewController =
258 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
259 UINavigationController* navigationController =
260 [[UINavigationController alloc] initWithRootViewController:flutterViewController];
261 UITabBarController* tabBarController = [[UITabBarController alloc] init];
262 tabBarController.viewControllers = @[ navigationController ];
263 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
264
265 id navigationControllerMock = OCMPartialMock(navigationController);
266 OCMStub([navigationControllerMock popViewControllerAnimated:YES]);
267 // Set some string to the pasteboard.
268 XCTestExpectation* navigationPopCalled = [self expectationWithDescription:@"SystemNavigator.pop"];
269 FlutterResult resultSet = ^(id result) {
270 [navigationPopCalled fulfill];
271 };
272 FlutterMethodCall* methodCallSet =
273 [FlutterMethodCall methodCallWithMethodName:@"SystemNavigator.pop" arguments:@(YES)];
274 [plugin handleMethodCall:methodCallSet result:resultSet];
275 [self waitForExpectationsWithTimeout:1 handler:nil];
276 OCMVerify([navigationControllerMock popViewControllerAnimated:YES]);
277
278 [flutterViewController deregisterNotifications];
279 }
280
281 - (void)testWhetherDeviceHasLiveTextInputInvokeCorrectly {
282 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
283 XCTestExpectation* invokeExpectation =
284 [self expectationWithDescription:@"isLiveTextInputAvailableInvoke"];
285 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
286 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
287 FlutterMethodCall* methodCall =
288 [FlutterMethodCall methodCallWithMethodName:@"LiveText.isLiveTextInputAvailable"
289 arguments:nil];
290 FlutterResult result = ^(id result) {
291 OCMVerify([mockPlugin isLiveTextInputAvailable]);
292 [invokeExpectation fulfill];
293 };
294 [mockPlugin handleMethodCall:methodCall result:result];
295 [self waitForExpectationsWithTimeout:1 handler:nil];
296 }
297
298 - (void)testSystemSoundPlay {
299 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
300 XCTestExpectation* invokeExpectation =
301 [self expectationWithDescription:@"SystemSound.play invoked"];
302 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
303 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
304
305 FlutterMethodCall* methodCall =
306 [FlutterMethodCall methodCallWithMethodName:@"SystemSound.play"
307 arguments:@"SystemSoundType.click"];
308 FlutterResult result = ^(id result) {
309 OCMVerify([mockPlugin playSystemSound:@"SystemSoundType.click"]);
310 [invokeExpectation fulfill];
311 };
312 [mockPlugin handleMethodCall:methodCall result:result];
313 [self waitForExpectationsWithTimeout:1 handler:nil];
314 }
315
316 - (void)testHapticFeedbackVibrate {
317 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
318 XCTestExpectation* invokeExpectation =
319 [self expectationWithDescription:@"HapticFeedback.vibrate invoked"];
320 FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
321 FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
322
323 FlutterMethodCall* methodCall =
324 [FlutterMethodCall methodCallWithMethodName:@"HapticFeedback.vibrate"
325 arguments:@"HapticFeedbackType.lightImpact"];
326 FlutterResult result = ^(id result) {
327 OCMVerify([mockPlugin vibrateHapticFeedback:@"HapticFeedbackType.lightImpact"]);
328 [invokeExpectation fulfill];
329 };
330 [mockPlugin handleMethodCall:methodCall result:result];
331 [self waitForExpectationsWithTimeout:1 handler:nil];
332 }
333
334 - (void)testViewControllerBasedStatusBarHiddenUpdate {
335 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
336 OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
337 .andReturn(@YES);
338 {
339 // Enabling system UI overlays to update status bar.
340 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
341 [engine runWithEntrypoint:nil];
342 FlutterViewController* flutterViewController =
343 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
344 XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
345
346 // Update to hidden.
347 FlutterPlatformPlugin* plugin = [engine platformPlugin];
348
349 XCTestExpectation* enableSystemUIOverlaysCalled =
350 [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
351 FlutterResult resultSet = ^(id result) {
352 [enableSystemUIOverlaysCalled fulfill];
353 };
354 FlutterMethodCall* methodCallSet =
355 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
356 arguments:@[ @"SystemUiOverlay.bottom" ]];
357 [plugin handleMethodCall:methodCallSet result:resultSet];
358 [self waitForExpectationsWithTimeout:1 handler:nil];
359 XCTAssertTrue(flutterViewController.prefersStatusBarHidden);
360
361 // Update to shown.
362 XCTestExpectation* enableSystemUIOverlaysCalled2 =
363 [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
364 FlutterResult resultSet2 = ^(id result) {
365 [enableSystemUIOverlaysCalled2 fulfill];
366 };
367 FlutterMethodCall* methodCallSet2 =
368 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
369 arguments:@[ @"SystemUiOverlay.top" ]];
370 [plugin handleMethodCall:methodCallSet2 result:resultSet2];
371 [self waitForExpectationsWithTimeout:1 handler:nil];
372 XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
373
374 [flutterViewController deregisterNotifications];
375 }
376 {
377 // Enable system UI mode to update status bar.
378 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
379 [engine runWithEntrypoint:nil];
380 FlutterViewController* flutterViewController =
381 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
382 XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
383
384 // Update to hidden.
385 FlutterPlatformPlugin* plugin = [engine platformPlugin];
386
387 XCTestExpectation* enableSystemUIModeCalled =
388 [self expectationWithDescription:@"setEnabledSystemUIMode"];
389 FlutterResult resultSet = ^(id result) {
390 [enableSystemUIModeCalled fulfill];
391 };
392 FlutterMethodCall* methodCallSet =
393 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIMode"
394 arguments:@"SystemUiMode.immersive"];
395 [plugin handleMethodCall:methodCallSet result:resultSet];
396 [self waitForExpectationsWithTimeout:1 handler:nil];
397 XCTAssertTrue(flutterViewController.prefersStatusBarHidden);
398
399 // Update to shown.
400 XCTestExpectation* enableSystemUIModeCalled2 =
401 [self expectationWithDescription:@"setEnabledSystemUIMode"];
402 FlutterResult resultSet2 = ^(id result) {
403 [enableSystemUIModeCalled2 fulfill];
404 };
405 FlutterMethodCall* methodCallSet2 =
406 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIMode"
407 arguments:@"SystemUiMode.edgeToEdge"];
408 [plugin handleMethodCall:methodCallSet2 result:resultSet2];
409 [self waitForExpectationsWithTimeout:1 handler:nil];
410 XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
411
412 [flutterViewController deregisterNotifications];
413 }
414 [bundleMock stopMocking];
415 }
416
417 - (void)testStatusBarHiddenUpdate {
418 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
419 OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
420 .andReturn(@NO);
421 id mockApplication = OCMClassMock([UIApplication class]);
422 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
423
424 // Enabling system UI overlays to update status bar.
425 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
426 [engine runWithEntrypoint:nil];
427 FlutterViewController* flutterViewController =
428 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
429
430 // Update the visibility of the status bar to hidden.
431 FlutterPlatformPlugin* plugin = [engine platformPlugin];
432
433 XCTestExpectation* systemOverlaysBottomExpectation =
434 [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
435 FlutterResult systemOverlaysBottomResult = ^(id result) {
436 [systemOverlaysBottomExpectation fulfill];
437 };
438 FlutterMethodCall* setSystemOverlaysBottomCall =
439 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
440 arguments:@[ @"SystemUiOverlay.bottom" ]];
441 [plugin handleMethodCall:setSystemOverlaysBottomCall result:systemOverlaysBottomResult];
442 [self waitForExpectationsWithTimeout:1 handler:nil];
443 OCMVerify([mockApplication setStatusBarHidden:YES]);
444
445 // Update the visibility of the status bar to shown.
446 XCTestExpectation* systemOverlaysTopExpectation =
447 [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
448 FlutterResult systemOverlaysTopResult = ^(id result) {
449 [systemOverlaysTopExpectation fulfill];
450 };
451 FlutterMethodCall* setSystemOverlaysTopCall =
452 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
453 arguments:@[ @"SystemUiOverlay.top" ]];
454 [plugin handleMethodCall:setSystemOverlaysTopCall result:systemOverlaysTopResult];
455 [self waitForExpectationsWithTimeout:1 handler:nil];
456 OCMVerify([mockApplication setStatusBarHidden:NO]);
457
458 [flutterViewController deregisterNotifications];
459 [mockApplication stopMocking];
460 [bundleMock stopMocking];
461 }
462
463 - (void)testStatusBarHiddenNotUpdatedInAppExtension {
464 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
465 OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
466 .andReturn(@NO);
467 OCMStub([bundleMock objectForInfoDictionaryKey:@"NSExtension"]).andReturn(@{
468 @"NSExtensionPointIdentifier" : @"com.apple.share-services"
469 });
470 id mockApplication = OCMClassMock([UIApplication class]);
471 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
472 OCMReject([mockApplication setStatusBarHidden:OCMOCK_ANY]);
473
474 // Enabling system UI overlays to update status bar.
475 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
476 [engine runWithEntrypoint:nil];
477 FlutterViewController* flutterViewController =
478 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
479
480 // Update the visibility of the status bar to hidden does not occur with extensions.
481 FlutterPlatformPlugin* plugin = [engine platformPlugin];
482
483 XCTestExpectation* systemOverlaysBottomExpectation =
484 [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
485 FlutterResult systemOverlaysBottomResult = ^(id result) {
486 [systemOverlaysBottomExpectation fulfill];
487 };
488 FlutterMethodCall* setSystemOverlaysBottomCall =
489 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
490 arguments:@[ @"SystemUiOverlay.bottom" ]];
491 [plugin handleMethodCall:setSystemOverlaysBottomCall result:systemOverlaysBottomResult];
492 [self waitForExpectationsWithTimeout:1 handler:nil];
493 OCMReject([mockApplication setStatusBarHidden:YES]);
494
495 // Update the visibility of the status bar to shown does not occur with extensions.
496 XCTestExpectation* systemOverlaysTopExpectation =
497 [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
498 FlutterResult systemOverlaysTopResult = ^(id result) {
499 [systemOverlaysTopExpectation fulfill];
500 };
501 FlutterMethodCall* setSystemOverlaysTopCall =
502 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
503 arguments:@[ @"SystemUiOverlay.top" ]];
504 [plugin handleMethodCall:setSystemOverlaysTopCall result:systemOverlaysTopResult];
505 [self waitForExpectationsWithTimeout:1 handler:nil];
506 OCMReject([mockApplication setStatusBarHidden:NO]);
507
508 [flutterViewController deregisterNotifications];
509 [mockApplication stopMocking];
510 [bundleMock stopMocking];
511 }
512
513 - (void)testStatusBarStyle {
514 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
515 OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
516 .andReturn(@NO);
517 id mockApplication = OCMClassMock([UIApplication class]);
518 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
519
520 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
521 [engine runWithEntrypoint:nil];
522 FlutterViewController* flutterViewController =
523 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
524 XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
525
526 FlutterPlatformPlugin* plugin = [engine platformPlugin];
527
528 XCTestExpectation* enableSystemUIModeCalled =
529 [self expectationWithDescription:@"setSystemUIOverlayStyle"];
530 FlutterResult resultSet = ^(id result) {
531 [enableSystemUIModeCalled fulfill];
532 };
533 FlutterMethodCall* methodCallSet =
534 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setSystemUIOverlayStyle"
535 arguments:@{@"statusBarBrightness" : @"Brightness.dark"}];
536 [plugin handleMethodCall:methodCallSet result:resultSet];
537 [self waitForExpectationsWithTimeout:1 handler:nil];
538
539 OCMVerify([mockApplication setStatusBarStyle:UIStatusBarStyleLightContent]);
540
541 [flutterViewController deregisterNotifications];
542 [mockApplication stopMocking];
543 [bundleMock stopMocking];
544 }
545
546 - (void)testStatusBarStyleNotUpdatedInAppExtension {
547 id bundleMock = OCMPartialMock([NSBundle mainBundle]);
548 OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
549 .andReturn(@NO);
550 OCMStub([bundleMock objectForInfoDictionaryKey:@"NSExtension"]).andReturn(@{
551 @"NSExtensionPointIdentifier" : @"com.apple.share-services"
552 });
553 id mockApplication = OCMClassMock([UIApplication class]);
554 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
555 OCMReject([mockApplication setStatusBarHidden:OCMOCK_ANY]);
556
557 FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
558 [engine runWithEntrypoint:nil];
559 FlutterViewController* flutterViewController =
560 [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
561 XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
562
563 FlutterPlatformPlugin* plugin = [engine platformPlugin];
564
565 XCTestExpectation* enableSystemUIModeCalled =
566 [self expectationWithDescription:@"setSystemUIOverlayStyle"];
567 FlutterResult resultSet = ^(id result) {
568 [enableSystemUIModeCalled fulfill];
569 };
570 FlutterMethodCall* methodCallSet =
571 [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setSystemUIOverlayStyle"
572 arguments:@{@"statusBarBrightness" : @"Brightness.dark"}];
573 [plugin handleMethodCall:methodCallSet result:resultSet];
574 [self waitForExpectationsWithTimeout:1 handler:nil];
575
576 [flutterViewController deregisterNotifications];
577 [mockApplication stopMocking];
578 [bundleMock stopMocking];
579 }
580
581 @end
FlutterBinaryMessenger.h
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
FlutterEngine_Internal.h
FlutterMacros.h
FlutterPlatformPlugin.h
engine
id engine
Definition: FlutterTextInputPluginTest.mm:137
FlutterViewController.h
FlutterEngine
Definition: FlutterEngine.h:61
-[FlutterEngine runWithEntrypoint:]
BOOL runWithEntrypoint:(nullable NSString *entrypoint)
FlutterMethodCall
Definition: FlutterCodecs.h:221
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterPlatformPlugin
Definition: FlutterPlatformPlugin.h:12
-[FlutterPlatformPlugin handleMethodCall:result:]
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
Definition: FlutterPlatformPlugin.mm:113
FlutterPlatformPluginTest
Definition: FlutterPlatformPluginTest.mm:18
FlutterViewController
Definition: FlutterViewController.h:57
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
platform_view_ios.h