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