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 
14 
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
void(^ FlutterResult)(id _Nullable result)
BOOL runWithEntrypoint:(nullable NSString *entrypoint)
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)