Flutter iOS Embedder
FlutterSceneLifeCycleTest.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 <UIKit/UIKit.h>
8 #import <XCTest/XCTest.h>
9 #include <objc/NSObject.h>
10 
18 
20 
21 // This class is meant to mimic the SceneDelegate class generated by SwiftUI that does not conform
22 // FlutterSceneLifeCycleProvider but actually does.
23 @interface FlutterSwiftUIAppSceneDelegate : NSObject
25 @end
26 
27 @implementation FlutterSwiftUIAppSceneDelegate
28 
29 @synthesize sceneLifeCycleDelegate = _sceneLifeCycleDelegate;
30 
31 - (instancetype)init {
32  if (self = [super init]) {
33  _sceneLifeCycleDelegate = [[FlutterPluginSceneLifeCycleDelegate alloc] init];
34  }
35  return self;
36 }
37 @end
38 
39 @interface FlutterSceneLifecycleTest : XCTestCase
40 @end
41 
42 @implementation FlutterSceneLifecycleTest
43 - (void)setUp {
44 }
45 
46 - (void)tearDown {
47 }
48 
49 #pragma mark - FlutterPluginSceneLifeCycleDelegate
50 
51 - (void)testAddFlutterManagedEngine {
54 
55  id mockEngine = OCMClassMock([FlutterEngine class]);
56  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
57  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
58 
59  [delegate addFlutterManagedEngine:mockEngine];
60  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
61 }
62 
63 - (void)testAddDuplicateFlutterEngine {
66 
67  id mockEngine = OCMClassMock([FlutterEngine class]);
68  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
69  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
70 
71  [delegate addFlutterManagedEngine:mockEngine];
72  [delegate addFlutterManagedEngine:mockEngine];
73  [delegate addFlutterManagedEngine:mockEngine];
74  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
75 }
76 
77 - (void)testAddMultipleFlutterEngine {
80 
81  id mockEngine = OCMClassMock([FlutterEngine class]);
82  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
83  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
84  [delegate addFlutterManagedEngine:mockEngine];
85 
86  id mockEngine2 = OCMClassMock([FlutterEngine class]);
87  id mockLifecycleDelegate2 = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
88  OCMStub([mockEngine2 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate2);
89  [delegate addFlutterManagedEngine:mockEngine2];
90 
91  XCTAssertEqual(delegate.flutterManagedEngines.count, 2.0);
92 }
93 
94 - (void)testRemoveFlutterManagedEngine {
97 
98  id mockEngine = OCMClassMock([FlutterEngine class]);
99  [delegate addFlutterManagedEngine:mockEngine];
100  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
101 
102  [delegate removeFlutterManagedEngine:mockEngine];
103  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
104 }
105 
106 - (void)testRemoveNotFoundFlutterEngine {
109 
110  id mockEngine = OCMClassMock([FlutterEngine class]);
111  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
112 
113  [delegate removeFlutterManagedEngine:mockEngine];
114  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
115 }
116 
117 - (void)testupdateFlutterManagedEnginesInSceneRemovesDeallocatedEngine {
120 
121  id mockWindowScene = OCMClassMock([UIWindowScene class]);
122 
123  @autoreleasepool {
124  id mockEngine = OCMClassMock([FlutterEngine class]);
125  [delegate addFlutterManagedEngine:mockEngine];
126  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
127  }
128 
129  [delegate updateFlutterManagedEnginesInScene:mockWindowScene];
130  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
131 }
132 
133 - (void)testupdateFlutterManagedEnginesInSceneRemovesEngineNotInScene {
136 
137  id mockEngine = OCMClassMock([FlutterEngine class]);
138  id mockViewController = OCMClassMock([UIViewController class]);
139  id mockView = OCMClassMock([UIView class]);
140  id mockWindow = OCMClassMock([UIWindow class]);
141  id mockWindowScene = OCMClassMock([UIWindowScene class]);
142  id mockLifecycleProvider = OCMProtocolMock(@protocol(FlutterSceneLifeCycleProvider));
143  id mockLifecycleDelegate = OCMClassMock([FlutterPluginSceneLifeCycleDelegate class]);
144  OCMStub([mockEngine viewController]).andReturn(mockViewController);
145  OCMStub([mockViewController view]).andReturn(mockView);
146  OCMStub([mockView window]).andReturn(mockWindow);
147  OCMStub([mockWindow windowScene]).andReturn(mockWindowScene);
148  OCMStub([mockWindow windowScene]).andReturn(mockWindowScene);
149  OCMStub([mockWindowScene delegate]).andReturn(mockLifecycleProvider);
150  OCMStub([mockLifecycleProvider sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
151 
152  [delegate addFlutterManagedEngine:mockEngine];
153  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
154 
155  id mockWindowScene2 = OCMClassMock([UIWindowScene class]);
156 
157  [delegate updateFlutterManagedEnginesInScene:mockWindowScene2];
158  OCMVerify(times(1), [mockLifecycleDelegate addFlutterManagedEngine:mockEngine]);
159  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
160 }
161 
162 - (void)testupdateFlutterManagedEnginesInSceneDoesNotRemoveEngineWithNilScene {
165  id mockEngine = OCMClassMock([FlutterEngine class]);
166  id mockWindowScene = OCMClassMock([UIWindowScene class]);
167  [delegate addFlutterManagedEngine:mockEngine];
168  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
169 
170  [delegate updateFlutterManagedEnginesInScene:mockWindowScene];
171  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
172 }
173 
174 - (void)testManuallyRegisterSceneLifeCycleWithFlutterEngine {
177 
178  id mockEngine = OCMClassMock([FlutterEngine class]);
179  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
180  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
181 
182  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine];
183  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
184  XCTAssertEqual(delegate.developerManagedEngines.count, 1.0);
185 }
186 
187 - (void)testManuallyUnregisterSceneLifeCycleWithFlutterEngine {
190 
191  id mockEngine = OCMClassMock([FlutterEngine class]);
192  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
193  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
194 
195  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine];
196  [delegate unregisterSceneLifeCycleWithFlutterEngine:mockEngine];
197  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
198  XCTAssertEqual(delegate.developerManagedEngines.count, 0.0);
199 }
200 
201 - (void)testManuallyRegisterSceneLifeCycleWithFlutterEngineCannotBeAutoAdded {
204 
205  FlutterEngine* engine = [[FlutterEngine alloc] init];
206  id mockEngine = OCMPartialMock(engine);
207  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
208  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
209 
210  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine];
211  [delegate addFlutterManagedEngine:mockEngine];
212  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
213  XCTAssertEqual(delegate.developerManagedEngines.count, 1.0);
214 
215  [delegate unregisterSceneLifeCycleWithFlutterEngine:mockEngine];
216  [delegate addFlutterManagedEngine:mockEngine];
217  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
218  XCTAssertEqual(delegate.developerManagedEngines.count, 0.0);
219 
220  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine];
221  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
222  XCTAssertEqual(delegate.developerManagedEngines.count, 1.0);
223 }
224 
225 - (void)testManuallyRegisterSceneLifeCycleWithFlutterEngineCannotBeAutoRemoved {
228 
229  id mockEngine = OCMClassMock([FlutterEngine class]);
230  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
231  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
232 
233  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine];
234  [delegate removeFlutterManagedEngine:mockEngine];
235  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
236  XCTAssertEqual(delegate.developerManagedEngines.count, 1.0);
237 }
238 
239 - (void)testManuallyRegisterSceneLifeCycleWithFlutterEngineRemovesAutomatic {
242 
243  id mockEngine = OCMClassMock([FlutterEngine class]);
244  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
245  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
246 
247  [delegate addFlutterManagedEngine:mockEngine];
248  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
249  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine];
250  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
251  XCTAssertEqual(delegate.developerManagedEngines.count, 1.0);
252 }
253 
254 - (void)testAllEnginesContainsManualAndAutomatic {
257 
258  id mockEngine = OCMClassMock([FlutterEngine class]);
259  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
260  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
261 
262  id mockEngine2 = OCMClassMock([FlutterEngine class]);
263 
264  [delegate addFlutterManagedEngine:mockEngine];
265  [delegate registerSceneLifeCycleWithFlutterEngine:mockEngine2];
266 
267  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
268  XCTAssertEqual(delegate.developerManagedEngines.count, 1.0);
269  XCTAssertEqual(delegate.allEngines.count, 2.0);
270  XCTAssertEqual([delegate.allEngines objectAtIndex:0], mockEngine);
271  XCTAssertEqual([delegate.allEngines objectAtIndex:1], mockEngine2);
272 }
273 
274 - (void)testEngineReceivedConnectNotificationForSceneBeforeActualEvent {
277  FlutterPluginSceneLifeCycleDelegate* mockDelegate = OCMPartialMock(delegate);
278  id mocks = [self mocksForEvents];
279  id mockEngine = mocks[@"mockEngine"];
280  id mockScene = mocks[@"mockScene"];
281  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
282  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
283  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
284  willConnectToSession:[OCMArg any]
285  options:[OCMArg any]])
286  .andReturn(YES);
287 
288  id mocks2 = [self mocksForEvents];
289  id mockEngine2 = mocks2[@"mockEngine"];
290  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate2 =
291  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks2[@"mockLifecycleDelegate"];
292  OCMStub([mockLifecycleDelegate2 scene:[OCMArg any]
293  willConnectToSession:[OCMArg any]
294  options:[OCMArg any]])
295  .andReturn(YES);
296 
297  // received notification
298  [mockDelegate engine:mockEngine receivedConnectNotificationFor:mockScene];
299  [mockDelegate engine:mockEngine2 receivedConnectNotificationFor:mockScene];
300  OCMVerify(times(1), [mockDelegate addFlutterManagedEngine:mockEngine]);
301  OCMVerify(times(1), [mockDelegate addFlutterManagedEngine:mockEngine2]);
302  XCTAssertEqual(delegate.flutterManagedEngines.count, 2.0);
303  OCMVerify(times(0), [mockDelegate scene:[OCMArg any]
304  willConnectToSession:[OCMArg any]
305  options:[OCMArg any]]);
306 
307  // actual event
308  id session = OCMClassMock([UISceneSession class]);
309  id options = OCMClassMock([UISceneConnectionOptions class]);
310  [mockDelegate scene:mockScene willConnectToSession:session options:options];
311  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene
312  willConnectToSession:session
313  options:options]);
314  OCMVerify(times(1), [mockLifecycleDelegate2 scene:mockScene
315  willConnectToSession:session
316  options:nil]);
317  XCTAssertEqual(delegate.flutterManagedEngines.count, 2.0);
318 }
319 
320 - (void)testEngineReceivedConnectNotificationForSceneAfterActualEvent {
323  FlutterPluginSceneLifeCycleDelegate* mockDelegate = OCMPartialMock(delegate);
324  id mocks = [self mocksForEvents];
325  id mockEngine = mocks[@"mockEngine"];
326  id mockScene = mocks[@"mockScene"];
327  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
328  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
329  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
330  willConnectToSession:[OCMArg any]
331  options:[OCMArg any]])
332  .andReturn(YES);
333  id mocks2 = [self mocksForEvents];
334  id mockEngine2 = mocks2[@"mockEngine"];
335  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate2 =
336  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks2[@"mockLifecycleDelegate"];
337  OCMStub([mockLifecycleDelegate2 scene:[OCMArg any]
338  willConnectToSession:[OCMArg any]
339  options:[OCMArg any]])
340  .andReturn(YES);
341 
342  // actual event
343  id session = OCMClassMock([UISceneSession class]);
344  id options = OCMClassMock([UISceneConnectionOptions class]);
345  OCMStub([mockScene session]).andReturn(session);
346  [mockDelegate scene:mockScene willConnectToSession:session options:options];
347  XCTAssertEqual(delegate.flutterManagedEngines.count, 0.0);
348  OCMVerify(times(0), [mockLifecycleDelegate scene:mockScene
349  willConnectToSession:session
350  options:options]);
351  OCMVerify(times(0), [mockLifecycleDelegate2 scene:mockScene
352  willConnectToSession:session
353  options:options]);
354  OCMStub([mockDelegate connectionOptions]).andReturn(options);
355 
356  // received notification
357  [mockDelegate engine:mockEngine receivedConnectNotificationFor:mockScene];
358  [mockDelegate engine:mockEngine2 receivedConnectNotificationFor:mockScene];
359 
360  OCMVerify(times(1), [mockDelegate addFlutterManagedEngine:mockEngine]);
361  OCMVerify(times(1), [mockDelegate addFlutterManagedEngine:mockEngine2]);
362  XCTAssertEqual(delegate.flutterManagedEngines.count, 2.0);
363  OCMVerify(times(1), [mockDelegate scene:mockScene willConnectToSession:session options:options]);
364  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene
365  willConnectToSession:session
366  options:options]);
367  OCMVerify(times(1), [mockLifecycleDelegate2 scene:mockScene
368  willConnectToSession:session
369  options:nil]);
370 }
371 
372 - (void)testSceneWillConnectToSessionOptionsHandledByScenePlugin {
375 
376  id mocks = [self mocksForEvents];
377  id mockEngine = mocks[@"mockEngine"];
378  id mockScene = mocks[@"mockScene"];
379  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
380  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
381  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
382  willConnectToSession:[OCMArg any]
383  options:[OCMArg any]])
384  .andReturn(YES);
385  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
386  OCMStub([mockAppLifecycleDelegate sceneWillConnectFallback:[OCMArg any]]).andReturn(YES);
387 
388  id session = OCMClassMock([UISceneSession class]);
389  id options = OCMClassMock([UISceneConnectionOptions class]);
390 
391  [delegate addFlutterManagedEngine:mockEngine];
392  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
393 
394  [delegate scene:mockScene willConnectToSession:session options:options];
395  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene
396  willConnectToSession:session
397  options:options]);
398  OCMVerify(times(0), [mockAppLifecycleDelegate sceneWillConnectFallback:options]);
399  OCMVerify(times(0), [mockEngine sendDeepLinkToFramework:[OCMArg any]
400  completionHandler:[OCMArg any]]);
401 }
402 
403 - (void)testSceneWillConnectToSessionOptionsHandledByApplicationPlugin {
406 
407  id mocks = [self mocksForEvents];
408  id mockEngine = mocks[@"mockEngine"];
409  id mockScene = mocks[@"mockScene"];
410  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
411  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
412  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
413  willConnectToSession:[OCMArg any]
414  options:[OCMArg any]])
415  .andReturn(NO);
416  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
417  OCMStub([mockAppLifecycleDelegate sceneWillConnectFallback:[OCMArg any]]).andReturn(YES);
418 
419  id session = OCMClassMock([UISceneSession class]);
420  id options = OCMClassMock([UISceneConnectionOptions class]);
421 
422  [delegate addFlutterManagedEngine:mockEngine];
423  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
424 
425  [delegate scene:mockScene willConnectToSession:session options:options];
426  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene
427  willConnectToSession:session
428  options:options]);
429  OCMVerify(times(1), [mockAppLifecycleDelegate sceneWillConnectFallback:options]);
430  OCMVerify(times(0), [mockEngine sendDeepLinkToFramework:[OCMArg any]
431  completionHandler:[OCMArg any]]);
432 }
433 
434 - (void)testSceneWillConnectToSessionOptionsHandledByApplicationPluginMultipleEngines {
437 
438  id mocks = [self mocksForEvents];
439  id mockEngine = mocks[@"mockEngine"];
440  id mockScene = mocks[@"mockScene"];
441  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
442  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
443  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
444  willConnectToSession:[OCMArg any]
445  options:[OCMArg any]])
446  .andReturn(NO);
447 
448  id mocks2 = [self mocksForEvents];
449  id mockEngine2 = mocks2[@"mockEngine"];
450  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate2 =
451  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks2[@"mockLifecycleDelegate"];
452  OCMStub([mockLifecycleDelegate2 scene:[OCMArg any]
453  willConnectToSession:[OCMArg any]
454  options:[OCMArg any]])
455  .andReturn(NO);
456 
457  id mockAppLifecycleDelegate = mocks2[@"mockAppLifecycleDelegate"];
458  OCMStub([mockAppLifecycleDelegate sceneWillConnectFallback:[OCMArg any]]).andReturn(YES);
459  id session = OCMClassMock([UISceneSession class]);
460  id options = OCMClassMock([UISceneConnectionOptions class]);
461 
462  [delegate addFlutterManagedEngine:mockEngine];
463  [delegate addFlutterManagedEngine:mockEngine2];
464  XCTAssertEqual(delegate.flutterManagedEngines.count, 2.0);
465 
466  [delegate scene:mockScene willConnectToSession:session options:options];
467  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene
468  willConnectToSession:session
469  options:options]);
470  OCMVerify(times(1), [mockLifecycleDelegate2 scene:mockScene
471  willConnectToSession:session
472  options:nil]);
473  OCMVerify(times(1), [mockAppLifecycleDelegate sceneWillConnectFallback:options]);
474  OCMVerify(times(0), [mockEngine sendDeepLinkToFramework:[OCMArg any]
475  completionHandler:[OCMArg any]]);
476 }
477 
478 - (void)testSceneWillConnectToSessionOptionsHandledByUniversalLinks {
481 
482  id mocks = [self mocksForEvents];
483  id mockEngine = mocks[@"mockEngine"];
484  id mockScene = mocks[@"mockScene"];
485  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
486  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
487  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
488  willConnectToSession:[OCMArg any]
489  options:[OCMArg any]])
490  .andReturn(NO);
491 
492  id session = OCMClassMock([UISceneSession class]);
493  id options = OCMClassMock([UISceneConnectionOptions class]);
494  id userActivity = OCMClassMock([NSUserActivity class]);
495  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
496  NSURL* url = [NSURL URLWithString:@"example.com"];
497  OCMStub([userActivity webpageURL]).andReturn(url);
498  NSSet<NSUserActivity*>* userActivities = [NSSet setWithObjects:userActivity, nil];
499  OCMStub([options userActivities]).andReturn(userActivities);
500  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
501 
502  [delegate addFlutterManagedEngine:mockEngine];
503  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
504 
505  [delegate scene:mockScene willConnectToSession:session options:options];
506  OCMVerify(times(1), [mockEngine sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
507 }
508 
509 - (void)testSceneWillConnectToSessionOptionsHandledByDeepLinks {
512 
513  id mocks = [self mocksForEvents];
514  id mockEngine = mocks[@"mockEngine"];
515  id mockScene = mocks[@"mockScene"];
516  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
517  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
518  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
519  willConnectToSession:[OCMArg any]
520  options:[OCMArg any]])
521  .andReturn(NO);
522 
523  id session = OCMClassMock([UISceneSession class]);
524  id options = OCMClassMock([UISceneConnectionOptions class]);
525  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
526  NSURL* url = [NSURL URLWithString:@"example.com"];
527  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
528  id urlContext = OCMClassMock([UIOpenURLContext class]);
529  OCMStub([urlContext URL]).andReturn(url);
530  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
531  OCMStub([options URLContexts]).andReturn(urlContexts);
532 
533  [delegate addFlutterManagedEngine:mockEngine];
534  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
535 
536  [delegate scene:mockScene willConnectToSession:session options:options];
537  OCMVerify(times(1), [mockEngine sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
538 }
539 
540 - (void)testSceneWillConnectToSessionOptionsHandledByNoPlugin {
543 
544  id mocks = [self mocksForEvents];
545  id mockEngine = mocks[@"mockEngine"];
546  id mockScene = mocks[@"mockScene"];
547  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
548  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
549  OCMStub([mockLifecycleDelegate scene:[OCMArg any]
550  willConnectToSession:[OCMArg any]
551  options:[OCMArg any]])
552  .andReturn(NO);
553 
554  id session = OCMClassMock([UISceneSession class]);
555  id options = OCMClassMock([UISceneConnectionOptions class]);
556  id userActivity = OCMClassMock([NSUserActivity class]);
557  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
558  NSURL* url = [NSURL URLWithString:@"example.com"];
559  OCMStub([userActivity webpageURL]).andReturn(url);
560  NSSet<NSUserActivity*>* userActivities = [NSSet setWithObjects:userActivity, nil];
561  OCMStub([options userActivities]).andReturn(userActivities);
562  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(NO);
563 
564  [delegate addFlutterManagedEngine:mockEngine];
565  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
566 
567  [delegate scene:mockScene willConnectToSession:session options:options];
568  OCMVerify(times(0), [mockEngine sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
569 }
570 
571 - (void)testSceneWillConnectToSessionAddsEngineFromRootViewController {
574  FlutterPluginSceneLifeCycleDelegate* mockDelegate = OCMPartialMock(delegate);
575 
576  id mockScene = OCMClassMock([UIWindowScene class]);
577  id mockWindow = OCMClassMock([UIWindow class]);
578  id mockViewController = OCMClassMock([FlutterViewController class]);
579  id mockEngine = OCMClassMock([FlutterEngine class]);
580  id mockSceneDelegate = OCMProtocolMock(@protocol(UIWindowSceneDelegate));
581 
582  OCMStub([mockScene delegate]).andReturn(mockSceneDelegate);
583  OCMStub([mockSceneDelegate window]).andReturn(mockWindow);
584  OCMStub([mockWindow rootViewController]).andReturn(mockViewController);
585  OCMStub([mockViewController engine]).andReturn(mockEngine);
586 
587  id session = OCMClassMock([UISceneSession class]);
588  id options = OCMClassMock([UISceneConnectionOptions class]);
589 
590  [mockDelegate scene:mockScene willConnectToSession:session options:options];
591 
592  OCMVerify(times(1), [mockDelegate addFlutterManagedEngine:mockEngine]);
593  OCMVerify(times(1), [mockDelegate scene:mockScene
594  willConnectToSession:session
595  flutterEngine:mockEngine
596  options:options]);
597 }
598 
599 - (void)testSceneWillConnectToSessionAddsEngineFromRootViewControllerAndNotNotification {
602  FlutterPluginSceneLifeCycleDelegate* mockDelegate = OCMPartialMock(delegate);
603 
604  id mockScene = OCMClassMock([UIWindowScene class]);
605  id mockWindow = OCMClassMock([UIWindow class]);
606  id mockViewController = OCMClassMock([FlutterViewController class]);
607  id mockEngine = OCMClassMock([FlutterEngine class]);
608  id mockSceneDelegate = OCMProtocolMock(@protocol(UIWindowSceneDelegate));
609 
610  OCMStub([mockScene delegate]).andReturn(mockSceneDelegate);
611  OCMStub([mockSceneDelegate window]).andReturn(mockWindow);
612  OCMStub([mockWindow rootViewController]).andReturn(mockViewController);
613  OCMStub([mockViewController engine]).andReturn(mockEngine);
614 
615  id session = OCMClassMock([UISceneSession class]);
616  id options = OCMClassMock([UISceneConnectionOptions class]);
617 
618  [mockDelegate scene:mockScene willConnectToSession:session options:options];
619  [mockDelegate engine:mockEngine receivedConnectNotificationFor:mockScene];
620 
621  OCMVerify(times(2), [mockDelegate addFlutterManagedEngine:mockEngine]);
622  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
623  OCMVerify(times(1), [mockDelegate scene:mockScene
624  willConnectToSession:session
625  flutterEngine:mockEngine
626  options:options]);
627 }
628 
629 - (void)testSceneDidDisconnect {
632 
633  id mocks = [self mocksForEvents];
634  id mockEngine = mocks[@"mockEngine"];
635  id mockScene = mocks[@"mockScene"];
636  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
637 
638  [delegate addFlutterManagedEngine:mockEngine];
639  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
640 
641  [delegate sceneDidDisconnect:mockScene];
642  OCMVerify(times(1), [mockLifecycleDelegate sceneDidDisconnect:mockScene]);
643 }
644 
645 - (void)testSceneWillEnterForeground {
648 
649  id mocks = [self mocksForEvents];
650  id mockEngine = mocks[@"mockEngine"];
651  id mockScene = mocks[@"mockScene"];
652  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
653  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
654 
655  [delegate addFlutterManagedEngine:mockEngine];
656  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
657 
658  [delegate sceneWillEnterForeground:mockScene];
659  OCMVerify(times(1), [mockLifecycleDelegate sceneWillEnterForeground:mockScene]);
660  OCMVerify(times(1), [mockAppLifecycleDelegate sceneWillEnterForegroundFallback]);
661 }
662 
663 - (void)testSceneDidBecomeActive {
666 
667  id mocks = [self mocksForEvents];
668  id mockEngine = mocks[@"mockEngine"];
669  id mockScene = mocks[@"mockScene"];
670  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
671  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
672 
673  [delegate addFlutterManagedEngine:mockEngine];
674  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
675 
676  [delegate sceneDidBecomeActive:mockScene];
677  OCMVerify(times(1), [mockLifecycleDelegate sceneDidBecomeActive:mockScene]);
678  OCMVerify(times(1), [mockAppLifecycleDelegate sceneDidBecomeActiveFallback]);
679 }
680 
681 - (void)testSceneWillResignActive {
684 
685  id mocks = [self mocksForEvents];
686  id mockEngine = mocks[@"mockEngine"];
687  id mockScene = mocks[@"mockScene"];
688  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
689  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
690 
691  [delegate addFlutterManagedEngine:mockEngine];
692  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
693 
694  [delegate sceneWillResignActive:mockScene];
695  OCMVerify(times(1), [mockLifecycleDelegate sceneWillResignActive:mockScene]);
696  OCMVerify(times(1), [mockAppLifecycleDelegate sceneWillResignActiveFallback]);
697 }
698 
699 - (void)testSceneDidEnterBackground {
702 
703  id mocks = [self mocksForEvents];
704  id mockEngine = mocks[@"mockEngine"];
705  id mockScene = mocks[@"mockScene"];
706  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
707  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
708 
709  [delegate addFlutterManagedEngine:mockEngine];
710  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
711 
712  [delegate sceneDidEnterBackground:mockScene];
713  OCMVerify(times(1), [mockLifecycleDelegate sceneDidEnterBackground:mockScene]);
714  OCMVerify(times(1), [mockAppLifecycleDelegate sceneDidEnterBackgroundFallback]);
715 }
716 
717 - (void)testSceneOpenURLContextsHandledByScenePlugin {
720 
721  id mocks = [self mocksForEvents];
722  id mockEngine = mocks[@"mockEngine"];
723  id mockScene = mocks[@"mockScene"];
724  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
725  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
726  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
727  OCMStub([mockLifecycleDelegate scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(YES);
728  OCMStub([mockAppLifecycleDelegate sceneFallbackOpenURLContexts:[OCMArg any]]).andReturn(YES);
729 
730  id urlContext = OCMClassMock([UIOpenURLContext class]);
731  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
732 
733  [delegate addFlutterManagedEngine:mockEngine];
734  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
735 
736  [delegate scene:mockScene openURLContexts:urlContexts];
737  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene openURLContexts:urlContexts]);
738  OCMVerify(times(0), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
739 }
740 
741 - (void)testSceneOpenURLContextsHandledByApplicationPlugin {
744 
745  id mocks = [self mocksForEvents];
746  id mockEngine = mocks[@"mockEngine"];
747  id mockScene = mocks[@"mockScene"];
748  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
749  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
750  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
751  OCMStub([mockLifecycleDelegate scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
752  OCMStub([mockAppLifecycleDelegate sceneFallbackOpenURLContexts:[OCMArg any]]).andReturn(YES);
753 
754  id urlContext = OCMClassMock([UIOpenURLContext class]);
755  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
756 
757  [delegate addFlutterManagedEngine:mockEngine];
758  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
759 
760  [delegate scene:mockScene openURLContexts:urlContexts];
761  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene openURLContexts:urlContexts]);
762  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
763 }
764 
765 - (void)testSceneOpenURLContextsHandledByDeeplink {
768 
769  id mocks = [self mocksForEvents];
770  id mockEngine = mocks[@"mockEngine"];
771  id mockScene = mocks[@"mockScene"];
772  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
773  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
774  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
775  OCMStub([mockLifecycleDelegate scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
776  OCMStub([mockAppLifecycleDelegate sceneFallbackOpenURLContexts:[OCMArg any]]).andReturn(NO);
777  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
778  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
779 
780  NSURL* url = [NSURL URLWithString:@"example.com"];
781  id urlContext = OCMClassMock([UIOpenURLContext class]);
782  OCMStub([urlContext URL]).andReturn(url);
783  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
784 
785  [delegate addFlutterManagedEngine:mockEngine];
786  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
787 
788  [delegate scene:mockScene openURLContexts:urlContexts];
789  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene openURLContexts:urlContexts]);
790  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
791  OCMVerify(times(1), [mockEngine sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
792 }
793 
794 - (void)testSceneOpenURLContextsHandledByNoPlugin {
797 
798  id mocks = [self mocksForEvents];
799  id mockEngine = mocks[@"mockEngine"];
800  id mockScene = mocks[@"mockScene"];
801  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
802  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
803  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
804  OCMStub([mockLifecycleDelegate scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
805  OCMStub([mockAppLifecycleDelegate sceneFallbackOpenURLContexts:[OCMArg any]]).andReturn(NO);
806  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
807  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(NO);
808 
809  id urlContext = OCMClassMock([UIOpenURLContext class]);
810  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
811 
812  [delegate addFlutterManagedEngine:mockEngine];
813  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
814 
815  [delegate scene:mockScene openURLContexts:urlContexts];
816  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene openURLContexts:urlContexts]);
817  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
818 }
819 
820 - (void)testSceneOpenURLContextsWithMultipleEnginesSomeHandledByPlugin {
823 
824  id mocks = [self mocksForEvents];
825  id mockScene = mocks[@"mockScene"];
826  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
827 
828  id mockEngine1 = OCMClassMock([FlutterEngine class]);
829  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate1 =
830  OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
831  OCMStub([mockEngine1 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate1);
832  OCMStub([mockLifecycleDelegate1 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(YES);
833 
834  id mockEngine2 = OCMClassMock([FlutterEngine class]);
835  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate2 =
836  OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
837  OCMStub([mockEngine2 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate2);
838  OCMStub([mockLifecycleDelegate2 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
839 
840  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
841  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
842 
843  NSURL* url = [NSURL URLWithString:@"example.com"];
844  id urlContext = OCMClassMock([UIOpenURLContext class]);
845  OCMStub([urlContext URL]).andReturn(url);
846  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
847 
848  [delegate addFlutterManagedEngine:mockEngine1];
849  [delegate addFlutterManagedEngine:mockEngine2];
850 
851  [delegate scene:mockScene openURLContexts:urlContexts];
852 
853  OCMVerify(times(1), [mockLifecycleDelegate1 scene:mockScene openURLContexts:urlContexts]);
854  OCMVerify(times(1), [mockLifecycleDelegate2 scene:mockScene openURLContexts:urlContexts]);
855  OCMVerify(times(0), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
856  OCMVerify(times(0), [mockEngine1 sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
857  OCMVerify(times(1), [mockEngine2 sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
858 }
859 
860 - (void)testSceneOpenURLContextsWithMultipleEnginesHandledByApplication {
863 
864  id mocks = [self mocksForEvents];
865  id mockScene = mocks[@"mockScene"];
866  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
867  OCMStub([mockAppLifecycleDelegate sceneFallbackOpenURLContexts:[OCMArg any]]).andReturn(YES);
868 
869  id mockEngine1 = OCMClassMock([FlutterEngine class]);
870  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate1 =
871  OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
872  OCMStub([mockEngine1 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate1);
873  OCMStub([mockLifecycleDelegate1 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
874 
875  id mockEngine2 = OCMClassMock([FlutterEngine class]);
876  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate2 =
877  OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
878  OCMStub([mockEngine2 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate2);
879  OCMStub([mockLifecycleDelegate2 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
880 
881  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
882  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
883 
884  NSURL* url = [NSURL URLWithString:@"example.com"];
885  id urlContext = OCMClassMock([UIOpenURLContext class]);
886  OCMStub([urlContext URL]).andReturn(url);
887  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
888 
889  [delegate addFlutterManagedEngine:mockEngine1];
890  [delegate addFlutterManagedEngine:mockEngine2];
891 
892  [delegate scene:mockScene openURLContexts:urlContexts];
893 
894  OCMVerify(times(1), [mockLifecycleDelegate1 scene:mockScene openURLContexts:urlContexts]);
895  OCMVerify(times(1), [mockLifecycleDelegate2 scene:mockScene openURLContexts:urlContexts]);
896  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
897  OCMVerify(times(0), [mockEngine1 sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
898  OCMVerify(times(0), [mockEngine2 sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
899 }
900 
901 - (void)testSceneOpenURLContextsWithMultipleEnginesHandledByDeeplink {
904 
905  id mocks = [self mocksForEvents];
906  id mockScene = mocks[@"mockScene"];
907  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
908  OCMStub([mockAppLifecycleDelegate sceneFallbackOpenURLContexts:[OCMArg any]]).andReturn(NO);
909 
910  id mockEngine1 = OCMClassMock([FlutterEngine class]);
911  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate1 =
912  OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
913  OCMStub([mockEngine1 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate1);
914  OCMStub([mockLifecycleDelegate1 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
915 
916  id mockEngine2 = OCMClassMock([FlutterEngine class]);
917  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate2 =
918  OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
919  OCMStub([mockEngine2 sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate2);
920  OCMStub([mockLifecycleDelegate2 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(NO);
921 
922  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
923  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
924 
925  NSURL* url = [NSURL URLWithString:@"example.com"];
926  id urlContext = OCMClassMock([UIOpenURLContext class]);
927  OCMStub([urlContext URL]).andReturn(url);
928  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
929 
930  [delegate addFlutterManagedEngine:mockEngine1];
931  [delegate addFlutterManagedEngine:mockEngine2];
932 
933  [delegate scene:mockScene openURLContexts:urlContexts];
934 
935  OCMVerify(times(1), [mockLifecycleDelegate1 scene:mockScene openURLContexts:urlContexts]);
936  OCMVerify(times(1), [mockLifecycleDelegate2 scene:mockScene openURLContexts:urlContexts]);
937  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackOpenURLContexts:urlContexts]);
938  OCMVerify(times(1), [mockEngine1 sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
939  OCMVerify(times(1), [mockEngine2 sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
940 }
941 
942 - (void)testSceneContinueUserActivityHandledByScenePlugin {
945 
946  id mocks = [self mocksForEvents];
947  id mockEngine = mocks[@"mockEngine"];
948  id mockScene = mocks[@"mockScene"];
949  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
950  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
951  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
952  OCMStub([mockLifecycleDelegate scene:[OCMArg any] continueUserActivity:[OCMArg any]])
953  .andReturn(YES);
954  OCMStub([mockAppLifecycleDelegate sceneFallbackContinueUserActivity:[OCMArg any]]).andReturn(YES);
955 
956  id userActivity = OCMClassMock([NSUserActivity class]);
957 
958  [delegate addFlutterManagedEngine:mockEngine];
959  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
960 
961  [delegate scene:mockScene continueUserActivity:userActivity];
962  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene continueUserActivity:userActivity]);
963  OCMVerify(times(0), [mockAppLifecycleDelegate sceneFallbackContinueUserActivity:userActivity]);
964 }
965 
966 - (void)testSceneContinueUserActivityHandledByApplicationPlugin {
969 
970  id mocks = [self mocksForEvents];
971  id mockEngine = mocks[@"mockEngine"];
972  id mockScene = mocks[@"mockScene"];
973  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
974  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
975  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
976  OCMStub([mockLifecycleDelegate scene:[OCMArg any] continueUserActivity:[OCMArg any]])
977  .andReturn(NO);
978  OCMStub([mockAppLifecycleDelegate sceneFallbackContinueUserActivity:[OCMArg any]]).andReturn(YES);
979 
980  id userActivity = OCMClassMock([NSUserActivity class]);
981 
982  [delegate addFlutterManagedEngine:mockEngine];
983  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
984 
985  [delegate scene:mockScene continueUserActivity:userActivity];
986  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene continueUserActivity:userActivity]);
987  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackContinueUserActivity:userActivity]);
988 }
989 
990 - (void)testSceneContinueUserActivityHandledByUniversalLinks {
993 
994  id mocks = [self mocksForEvents];
995  id mockEngine = mocks[@"mockEngine"];
996  id mockScene = mocks[@"mockScene"];
997  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
998  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
999  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
1000  OCMStub([mockLifecycleDelegate scene:[OCMArg any] continueUserActivity:[OCMArg any]])
1001  .andReturn(NO);
1002  OCMStub([mockAppLifecycleDelegate sceneFallbackContinueUserActivity:[OCMArg any]]).andReturn(NO);
1003  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
1004  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(YES);
1005 
1006  NSURL* url = [NSURL URLWithString:@"example.com"];
1007  id userActivity = OCMClassMock([NSUserActivity class]);
1008  OCMStub([userActivity webpageURL]).andReturn(url);
1009 
1010  [delegate addFlutterManagedEngine:mockEngine];
1011  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1012 
1013  [delegate scene:mockScene continueUserActivity:userActivity];
1014  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene continueUserActivity:userActivity]);
1015  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackContinueUserActivity:userActivity]);
1016  OCMVerify(times(1), [mockEngine sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
1017 }
1018 
1019 - (void)testStateRestorationActivityForScene {
1021  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1022 
1023  id mocks = [self mocksForEvents];
1024  id mockEngine = mocks[@"mockEngine"];
1025  id mockViewController = OCMClassMock([FlutterViewController class]);
1026  id mockRestorationPlugin = OCMClassMock([FlutterRestorationPlugin class]);
1027  OCMStub([mockEngine viewController]).andReturn(mockViewController);
1028  OCMStub([mockEngine restorationPlugin]).andReturn(mockRestorationPlugin);
1029 
1030  NSString* restorationId = @"restorationId";
1031  NSString* mockDataString = @"mockData";
1032  NSString* configName = @"ConfigurationName";
1033  NSData* mockData = [mockDataString dataUsingEncoding:NSUTF8StringEncoding];
1034  OCMStub([mockViewController restorationIdentifier]).andReturn(restorationId);
1035  OCMStub([mockRestorationPlugin restorationData]).andReturn(mockData);
1036 
1037  id mockScene = mocks[@"mockScene"];
1038  id mockSession = OCMClassMock([UISceneSession class]);
1039  id mockConfiguration = OCMClassMock([UISceneConfiguration class]);
1040  OCMStub([mockScene session]).andReturn(mockSession);
1041  OCMStub([mockSession configuration]).andReturn(mockConfiguration);
1042  OCMStub([mockConfiguration name]).andReturn(configName);
1043 
1044  [delegate addFlutterManagedEngine:mockEngine];
1045  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1046  NSUserActivity* state = [delegate stateRestorationActivityForScene:mockScene];
1047  XCTAssertEqual(state.userInfo[restorationId], mockData);
1048  XCTAssertEqual(state.activityType, configName);
1049 }
1050 
1051 - (void)testSceneRestoreInteractionStateWithUserActivity {
1053  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1054  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
1055  id mockURL = OCMClassMock([NSURL class]);
1056  id mockFileDate = OCMClassMock([NSDate class]);
1057  int64_t mockBundleDateNum = 1;
1058 
1059  OCMStub([mockBundle executableURL]).andReturn(mockURL);
1060  OCMStub([mockURL getResourceValue:[OCMArg setTo:mockFileDate]
1061  forKey:NSURLContentModificationDateKey
1062  error:[OCMArg setTo:nil]]);
1063  OCMStub([mockFileDate timeIntervalSince1970]).andReturn(mockBundleDateNum);
1064 
1065  id mocks = [self mocksForEvents];
1066  id mockEngine = mocks[@"mockEngine"];
1067  id mockViewController = OCMClassMock([FlutterViewController class]);
1068  id mockRestorationPlugin = OCMClassMock([FlutterRestorationPlugin class]);
1069  OCMStub([mockEngine viewController]).andReturn(mockViewController);
1070  OCMStub([mockEngine restorationPlugin]).andReturn(mockRestorationPlugin);
1071 
1072  NSString* restorationId = @"restorationId";
1073  NSString* mockDataString = @"teststring";
1074  NSNumber* mockBundleStateDateNum = @1.0;
1075  NSData* mockData = [mockDataString dataUsingEncoding:NSUTF8StringEncoding];
1076  OCMStub([mockViewController restorationIdentifier]).andReturn(restorationId);
1077  OCMStub([mockRestorationPlugin restorationData]).andReturn(mockData);
1078 
1079  id mockScene = mocks[@"mockScene"];
1080 
1081  id userActivity = OCMClassMock([NSUserActivity class]);
1082  NSDictionary* mockUserInfo = @{
1083  @"mod-date" : mockBundleStateDateNum,
1084  restorationId : mockData,
1085  };
1086  OCMStub([userActivity userInfo]).andReturn(mockUserInfo);
1087 
1088  [delegate addFlutterManagedEngine:mockEngine];
1089  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1090  [delegate scene:mockScene restoreInteractionStateWithUserActivity:userActivity];
1091  OCMVerify(times(1), [mockRestorationPlugin setRestorationData:mockData]);
1092  [mockBundle stopMocking];
1093 }
1094 
1095 - (void)testSceneDoesNotRestoreInteractionStateWithUserActivity {
1097  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1098  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
1099  id mockURL = OCMClassMock([NSURL class]);
1100  id mockFileDate = OCMClassMock([NSDate class]);
1101  int64_t mockBundleDateNum = 1;
1102 
1103  OCMStub([mockBundle executableURL]).andReturn(mockURL);
1104  OCMStub([mockURL getResourceValue:[OCMArg setTo:mockFileDate]
1105  forKey:NSURLContentModificationDateKey
1106  error:[OCMArg setTo:nil]]);
1107  OCMStub([mockFileDate timeIntervalSince1970]).andReturn(mockBundleDateNum);
1108 
1109  id mocks = [self mocksForEvents];
1110  id mockEngine = mocks[@"mockEngine"];
1111  id mockViewController = OCMClassMock([FlutterViewController class]);
1112  id mockRestorationPlugin = OCMClassMock([FlutterRestorationPlugin class]);
1113  OCMStub([mockEngine viewController]).andReturn(mockViewController);
1114  OCMStub([mockEngine restorationPlugin]).andReturn(mockRestorationPlugin);
1115 
1116  NSString* restorationId = @"restorationId";
1117  NSString* mockDataString = @"teststring";
1118  NSNumber* mockBundleStateDateNum = @2.0;
1119  NSData* mockData = [mockDataString dataUsingEncoding:NSUTF8StringEncoding];
1120  OCMStub([mockViewController restorationIdentifier]).andReturn(restorationId);
1121  OCMStub([mockRestorationPlugin restorationData]).andReturn(mockData);
1122 
1123  id mockScene = mocks[@"mockScene"];
1124 
1125  id userActivity = OCMClassMock([NSUserActivity class]);
1126  NSDictionary* mockUserInfo = @{
1127  @"mod-date" : mockBundleStateDateNum,
1128  restorationId : mockData,
1129  };
1130  OCMStub([userActivity userInfo]).andReturn(mockUserInfo);
1131 
1132  [delegate addFlutterManagedEngine:mockEngine];
1133  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1134  [delegate scene:mockScene restoreInteractionStateWithUserActivity:userActivity];
1135  OCMVerify(times(0), [mockRestorationPlugin setRestorationData:mockData]);
1136  [mockBundle stopMocking];
1137 }
1138 
1139 - (void)testSceneContinueUserActivityHandledByNoPlugin {
1141  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1142 
1143  id mocks = [self mocksForEvents];
1144  id mockEngine = mocks[@"mockEngine"];
1145  id mockScene = mocks[@"mockScene"];
1146  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
1147  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
1148  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
1149  OCMStub([mockLifecycleDelegate scene:[OCMArg any] continueUserActivity:[OCMArg any]])
1150  .andReturn(NO);
1151  OCMStub([mockAppLifecycleDelegate sceneFallbackContinueUserActivity:[OCMArg any]]).andReturn(NO);
1152  id flutterApp = OCMClassMock([FlutterSharedApplication class]);
1153  OCMStub([flutterApp isFlutterDeepLinkingEnabled]).andReturn(NO);
1154 
1155  NSURL* url = [NSURL URLWithString:@"example.com"];
1156  id userActivity = OCMClassMock([NSUserActivity class]);
1157  OCMStub([userActivity webpageURL]).andReturn(url);
1158 
1159  [delegate addFlutterManagedEngine:mockEngine];
1160  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1161 
1162  [delegate scene:mockScene continueUserActivity:userActivity];
1163  OCMVerify(times(1), [mockLifecycleDelegate scene:mockScene continueUserActivity:userActivity]);
1164  OCMVerify(times(1), [mockAppLifecycleDelegate sceneFallbackContinueUserActivity:userActivity]);
1165  OCMVerify(times(0), [mockEngine sendDeepLinkToFramework:url completionHandler:[OCMArg any]]);
1166 }
1167 
1168 - (void)testWindowScenePerformActionForShortcutItemHandledByScenePlugin {
1170  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1171 
1172  id mocks = [self mocksForEvents];
1173  id mockEngine = mocks[@"mockEngine"];
1174  id mockScene = mocks[@"mockScene"];
1175  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
1176  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
1177  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
1178  OCMStub([mockLifecycleDelegate windowScene:[OCMArg any]
1179  performActionForShortcutItem:[OCMArg any]
1180  completionHandler:[OCMArg any]])
1181  .andReturn(YES);
1182  OCMStub([mockAppLifecycleDelegate sceneFallbackPerformActionForShortcutItem:[OCMArg any]
1183  completionHandler:[OCMArg any]])
1184  .andReturn(YES);
1185 
1186  id shortcutItem = OCMClassMock([UIApplicationShortcutItem class]);
1187  id handler = ^(BOOL succeeded) {
1188  };
1189 
1190  [delegate addFlutterManagedEngine:mockEngine];
1191  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1192 
1193  [delegate windowScene:mockScene
1194  performActionForShortcutItem:shortcutItem
1195  completionHandler:handler];
1196  OCMVerify(times(1), [mockLifecycleDelegate windowScene:mockScene
1197  performActionForShortcutItem:shortcutItem
1198  completionHandler:handler]);
1199  OCMVerify(times(0),
1200  [mockAppLifecycleDelegate sceneFallbackPerformActionForShortcutItem:shortcutItem
1201  completionHandler:handler]);
1202 }
1203 
1204 - (void)testWindowScenePerformActionForShortcutItemHandledByApplicationPlugin {
1206  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1207 
1208  id mocks = [self mocksForEvents];
1209  id mockEngine = mocks[@"mockEngine"];
1210  id mockScene = mocks[@"mockScene"];
1211  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
1212  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
1213  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
1214  OCMStub([mockLifecycleDelegate windowScene:[OCMArg any]
1215  performActionForShortcutItem:[OCMArg any]
1216  completionHandler:[OCMArg any]])
1217  .andReturn(NO);
1218  OCMStub([mockAppLifecycleDelegate sceneFallbackPerformActionForShortcutItem:[OCMArg any]
1219  completionHandler:[OCMArg any]])
1220  .andReturn(YES);
1221 
1222  id shortcutItem = OCMClassMock([UIApplicationShortcutItem class]);
1223  id handler = ^(BOOL succeeded) {
1224  };
1225 
1226  [delegate addFlutterManagedEngine:mockEngine];
1227  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1228 
1229  [delegate windowScene:mockScene
1230  performActionForShortcutItem:shortcutItem
1231  completionHandler:handler];
1232  OCMVerify(times(1), [mockLifecycleDelegate windowScene:mockScene
1233  performActionForShortcutItem:shortcutItem
1234  completionHandler:handler]);
1235  OCMVerify(times(1),
1236  [mockAppLifecycleDelegate sceneFallbackPerformActionForShortcutItem:shortcutItem
1237  completionHandler:handler]);
1238 }
1239 
1240 - (void)testWindowScenePerformActionForShortcutItemHandledByNoPlugin {
1242  [[FlutterPluginSceneLifeCycleDelegate alloc] init];
1243 
1244  id mocks = [self mocksForEvents];
1245  id mockEngine = mocks[@"mockEngine"];
1246  id mockScene = mocks[@"mockScene"];
1247  FlutterEnginePluginSceneLifeCycleDelegate* mockLifecycleDelegate =
1248  (FlutterEnginePluginSceneLifeCycleDelegate*)mocks[@"mockLifecycleDelegate"];
1249  id mockAppLifecycleDelegate = mocks[@"mockAppLifecycleDelegate"];
1250  OCMStub([mockLifecycleDelegate windowScene:[OCMArg any]
1251  performActionForShortcutItem:[OCMArg any]
1252  completionHandler:[OCMArg any]])
1253  .andReturn(NO);
1254  OCMStub([mockAppLifecycleDelegate sceneFallbackPerformActionForShortcutItem:[OCMArg any]
1255  completionHandler:[OCMArg any]])
1256  .andReturn(NO);
1257 
1258  id shortcutItem = OCMClassMock([UIApplicationShortcutItem class]);
1259  id handler = ^(BOOL succeeded) {
1260  };
1261 
1262  [delegate addFlutterManagedEngine:mockEngine];
1263  XCTAssertEqual(delegate.flutterManagedEngines.count, 1.0);
1264 
1265  [delegate windowScene:mockScene
1266  performActionForShortcutItem:shortcutItem
1267  completionHandler:handler];
1268  OCMVerify(times(1), [mockLifecycleDelegate windowScene:mockScene
1269  performActionForShortcutItem:shortcutItem
1270  completionHandler:handler]);
1271  OCMVerify(times(1),
1272  [mockAppLifecycleDelegate sceneFallbackPerformActionForShortcutItem:shortcutItem
1273  completionHandler:handler]);
1274 }
1275 
1276 - (NSDictionary*)mocksForEvents {
1277  id mockEngine = OCMClassMock([FlutterEngine class]);
1278  id mockLifecycleDelegate = OCMClassMock([FlutterEnginePluginSceneLifeCycleDelegate class]);
1279  OCMStub([mockEngine sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
1280 
1281  id mockApplication = OCMClassMock([UIApplication class]);
1282  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
1283 
1284  id mockAppDelegate = OCMClassMock([FlutterAppDelegate class]);
1285  OCMStub([mockApplication delegate]).andReturn(mockAppDelegate);
1286 
1287  id mockAppLifecycleDelegate = OCMClassMock([FlutterPluginAppLifeCycleDelegate class]);
1288  OCMStub([mockAppDelegate lifeCycleDelegate]).andReturn(mockAppLifecycleDelegate);
1289 
1290  id mockScene = OCMClassMock([UIWindowScene class]);
1291 
1292  return @{
1293  @"mockEngine" : mockEngine,
1294  @"mockScene" : mockScene,
1295  @"mockLifecycleDelegate" : mockLifecycleDelegate,
1296  @"mockAppLifecycleDelegate" : mockAppLifecycleDelegate,
1297  };
1298 }
1299 
1300 #pragma mark - FlutterEnginePluginSceneLifeCycleDelegate
1301 
1302 - (void)testEngineSceneWillConnectToSession {
1305 
1306  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin =
1307  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1308  OCMStub([mockPlugin scene:[OCMArg any] willConnectToSession:[OCMArg any] options:[OCMArg any]])
1309  .andReturn(YES);
1310  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin2 =
1311  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1312  OCMStub([mockPlugin2 scene:[OCMArg any] willConnectToSession:[OCMArg any] options:[OCMArg any]])
1313  .andReturn(YES);
1314 
1315  [delegate addDelegate:mockPlugin];
1316  [delegate addDelegate:mockPlugin2];
1317 
1318  id mockScene = OCMClassMock([UIWindowScene class]);
1319  id mockSession = OCMClassMock([UISceneSession class]);
1320  id mockOptions = OCMClassMock([UISceneConnectionOptions class]);
1321 
1322  XCTAssertTrue([delegate scene:mockScene willConnectToSession:mockSession options:mockOptions]);
1323  OCMVerify(times(1), [mockPlugin scene:mockScene
1324  willConnectToSession:mockSession
1325  options:mockOptions]);
1326  OCMVerify(times(1), [mockPlugin2 scene:mockScene willConnectToSession:mockSession options:nil]);
1327 }
1328 
1329 - (void)testEngineSceneDidDisconnect {
1332 
1333  id mockPlugin = OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1334  [delegate addDelegate:mockPlugin];
1335  id mockScene = OCMClassMock([UIWindowScene class]);
1336  [delegate sceneDidDisconnect:mockScene];
1337  OCMVerify([mockPlugin sceneDidDisconnect:mockScene]);
1338 }
1339 
1340 - (void)testEngineSceneWillEnterForeground {
1343 
1344  id mockPlugin = OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1345  [delegate addDelegate:mockPlugin];
1346  id mockScene = OCMClassMock([UIWindowScene class]);
1347  [delegate sceneWillEnterForeground:mockScene];
1348  OCMVerify([mockPlugin sceneWillEnterForeground:mockScene]);
1349 }
1350 
1351 - (void)testEngineSceneDidBecomeActive {
1354 
1355  id mockPlugin = OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1356  [delegate addDelegate:mockPlugin];
1357  id mockScene = OCMClassMock([UIWindowScene class]);
1358  [delegate sceneDidBecomeActive:mockScene];
1359  OCMVerify([mockPlugin sceneDidBecomeActive:mockScene]);
1360 }
1361 
1362 - (void)testEngineSceneWillResignActive {
1365 
1366  id mockPlugin = OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1367  [delegate addDelegate:mockPlugin];
1368  id mockScene = OCMClassMock([UIWindowScene class]);
1369  [delegate sceneWillResignActive:mockScene];
1370  OCMVerify([mockPlugin sceneWillResignActive:mockScene]);
1371 }
1372 
1373 - (void)testEngineSceneDidEnterBackground {
1376 
1377  id mockPlugin = OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1378  [delegate addDelegate:mockPlugin];
1379  id mockScene = OCMClassMock([UIWindowScene class]);
1380  [delegate sceneDidEnterBackground:mockScene];
1381  OCMVerify([mockPlugin sceneDidEnterBackground:mockScene]);
1382 }
1383 
1384 - (void)testEngineSceneOpenURLContexts {
1387 
1388  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin =
1389  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1390  OCMStub([mockPlugin scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(YES);
1391  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin2 =
1392  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1393  OCMStub([mockPlugin2 scene:[OCMArg any] openURLContexts:[OCMArg any]]).andReturn(YES);
1394 
1395  [delegate addDelegate:mockPlugin];
1396  [delegate addDelegate:mockPlugin2];
1397 
1398  id mockScene = OCMClassMock([UIWindowScene class]);
1399  id urlContext = OCMClassMock([UIOpenURLContext class]);
1400  NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
1401 
1402  XCTAssertTrue([delegate scene:mockScene openURLContexts:urlContexts]);
1403  OCMVerify(times(1), [mockPlugin scene:mockScene openURLContexts:urlContexts]);
1404  OCMVerify(times(0), [mockPlugin2 scene:mockScene openURLContexts:urlContexts]);
1405 }
1406 
1407 - (void)testEngineSceneContinueUserActivity {
1410 
1411  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin =
1412  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1413  OCMStub([mockPlugin scene:[OCMArg any] continueUserActivity:[OCMArg any]]).andReturn(YES);
1414  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin2 =
1415  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1416  OCMStub([mockPlugin2 scene:[OCMArg any] continueUserActivity:[OCMArg any]]).andReturn(YES);
1417 
1418  [delegate addDelegate:mockPlugin];
1419  [delegate addDelegate:mockPlugin2];
1420 
1421  id mockScene = OCMClassMock([UIWindowScene class]);
1422  id userActivity = OCMClassMock([NSUserActivity class]);
1423 
1424  XCTAssertTrue([delegate scene:mockScene continueUserActivity:userActivity]);
1425  OCMVerify(times(1), [mockPlugin scene:mockScene continueUserActivity:userActivity]);
1426  OCMVerify(times(0), [mockPlugin2 scene:mockScene continueUserActivity:userActivity]);
1427 }
1428 
1429 - (void)testEngineWindowScenePerformActionForShortcutItem {
1432 
1433  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin =
1434  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1435  OCMStub([mockPlugin windowScene:[OCMArg any]
1436  performActionForShortcutItem:[OCMArg any]
1437  completionHandler:[OCMArg any]])
1438  .andReturn(YES);
1439  NSObject<FlutterSceneLifeCycleDelegate>* mockPlugin2 =
1440  OCMProtocolMock(@protocol(FlutterSceneLifeCycleDelegate));
1441  OCMStub([mockPlugin2 windowScene:[OCMArg any]
1442  performActionForShortcutItem:[OCMArg any]
1443  completionHandler:[OCMArg any]])
1444  .andReturn(YES);
1445 
1446  [delegate addDelegate:mockPlugin];
1447  [delegate addDelegate:mockPlugin2];
1448 
1449  id mockScene = OCMClassMock([UIWindowScene class]);
1450  id shortcutItem = OCMClassMock([UIApplicationShortcutItem class]);
1451  id handler = ^(BOOL succeeded) {
1452  };
1453 
1454  XCTAssertTrue([delegate windowScene:mockScene
1455  performActionForShortcutItem:shortcutItem
1456  completionHandler:handler]);
1457  OCMVerify(times(1), [mockPlugin windowScene:mockScene
1458  performActionForShortcutItem:shortcutItem
1459  completionHandler:handler]);
1460  OCMVerify(times(0), [mockPlugin2 windowScene:mockScene
1461  performActionForShortcutItem:shortcutItem
1462  completionHandler:handler]);
1463 }
1464 
1465 - (void)testFlutterPluginSceneLifeCycleDelegateFromScene {
1466  id mockScene = OCMClassMock([UIWindowScene class]);
1467  id mockSceneDelegate = OCMClassMock([FlutterSwiftUIAppSceneDelegate class]);
1468  id mockSceneLifeCycleDelegate = OCMClassMock([FlutterPluginSceneLifeCycleDelegate class]);
1469 
1470  OCMStub([mockScene delegate]).andReturn(mockSceneDelegate);
1471  OCMStub([mockSceneDelegate sceneLifeCycleDelegate]).andReturn(mockSceneLifeCycleDelegate);
1472 
1473  XCTAssertEqual([FlutterPluginSceneLifeCycleDelegate fromScene:mockScene],
1474  mockSceneLifeCycleDelegate);
1475 }
1476 @end
FlutterViewController * viewController
void addDelegate:(NSObject< FlutterSceneLifeCycleDelegate > *delegate)
void scene:openURLContexts:(UIScene *scene,[openURLContexts] NSSet< UIOpenURLContext * > *URLContexts)
void updateFlutterManagedEnginesInScene:(UIScene *scene)
void scene:willConnectToSession:options:(UIScene *scene,[willConnectToSession] UISceneSession *session,[options] UISceneConnectionOptions *connectionOptions)
void windowScene:performActionForShortcutItem:completionHandler:(UIWindowScene *windowScene,[performActionForShortcutItem] UIApplicationShortcutItem *shortcutItem,[completionHandler] void(^ completionHandler)(BOOL succeeded))
void scene:continueUserActivity:(UIScene *scene,[continueUserActivity] NSUserActivity *userActivity)
FlutterPluginSceneLifeCycleDelegate * sceneLifeCycleDelegate
BOOL unregisterSceneLifeCycleWithFlutterEngine:(FlutterEngine *engine)
BOOL registerSceneLifeCycleWithFlutterEngine:(FlutterEngine *engine)