| 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
11 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h"
14 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h"
15 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneLifeCycle_Internal.h"
16 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneLifeCycle_Test.h"
17 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h"
18
19 FLUTTER_ASSERT_ARC
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
24 @property(nonatomic, strong) FlutterPluginSceneLifeCycleDelegate* sceneLifeCycleDelegate;
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 {
52 FlutterPluginSceneLifeCycleDelegate* delegate =
53 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
64 FlutterPluginSceneLifeCycleDelegate* delegate =
65 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
78 FlutterPluginSceneLifeCycleDelegate* delegate =
79 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
95 FlutterPluginSceneLifeCycleDelegate* delegate =
96 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
107 FlutterPluginSceneLifeCycleDelegate* delegate =
108 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
118 FlutterPluginSceneLifeCycleDelegate* delegate =
119 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
134 FlutterPluginSceneLifeCycleDelegate* delegate =
135 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
163 FlutterPluginSceneLifeCycleDelegate* delegate =
164 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
175 FlutterPluginSceneLifeCycleDelegate* delegate =
176 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
188 FlutterPluginSceneLifeCycleDelegate* delegate =
189 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
202 FlutterPluginSceneLifeCycleDelegate* delegate =
203 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
226 FlutterPluginSceneLifeCycleDelegate* delegate =
227 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
240 FlutterPluginSceneLifeCycleDelegate* delegate =
241 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
255 FlutterPluginSceneLifeCycleDelegate* delegate =
256 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
275 FlutterPluginSceneLifeCycleDelegate* delegate =
276 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
321 FlutterPluginSceneLifeCycleDelegate* delegate =
322 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
373 FlutterPluginSceneLifeCycleDelegate* delegate =
374 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
404 FlutterPluginSceneLifeCycleDelegate* delegate =
405 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
435 FlutterPluginSceneLifeCycleDelegate* delegate =
436 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
479 FlutterPluginSceneLifeCycleDelegate* delegate =
480 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
510 FlutterPluginSceneLifeCycleDelegate* delegate =
511 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
541 FlutterPluginSceneLifeCycleDelegate* delegate =
542 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
572 FlutterPluginSceneLifeCycleDelegate* delegate =
573 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
600 FlutterPluginSceneLifeCycleDelegate* delegate =
601 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
630 FlutterPluginSceneLifeCycleDelegate* delegate =
631 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
646 FlutterPluginSceneLifeCycleDelegate* delegate =
647 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
664 FlutterPluginSceneLifeCycleDelegate* delegate =
665 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
682 FlutterPluginSceneLifeCycleDelegate* delegate =
683 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
700 FlutterPluginSceneLifeCycleDelegate* delegate =
701 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
718 FlutterPluginSceneLifeCycleDelegate* delegate =
719 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
742 FlutterPluginSceneLifeCycleDelegate* delegate =
743 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
766 FlutterPluginSceneLifeCycleDelegate* delegate =
767 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
795 FlutterPluginSceneLifeCycleDelegate* delegate =
796 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
821 FlutterPluginSceneLifeCycleDelegate* delegate =
822 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
861 FlutterPluginSceneLifeCycleDelegate* delegate =
862 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
902 FlutterPluginSceneLifeCycleDelegate* delegate =
903 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
943 FlutterPluginSceneLifeCycleDelegate* delegate =
944 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
967 FlutterPluginSceneLifeCycleDelegate* delegate =
968 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
991 FlutterPluginSceneLifeCycleDelegate* delegate =
992 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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 {
1020 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1052 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1096 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1140 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1169 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1205 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1241 FlutterPluginSceneLifeCycleDelegate* delegate =
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 {
1303 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1304 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1330 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1331 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1341 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1342 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1352 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1353 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1363 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1364 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1374 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1375 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1385 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1386 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1408 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1409 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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 {
1430 FlutterEnginePluginSceneLifeCycleDelegate* delegate =
1431 [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
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
FlutterEngine_Internal.h
FlutterEngine_Test.h
FlutterPluginAppLifeCycleDelegate_internal.h
FlutterRestorationPlugin.h
FlutterSceneLifeCycle_Internal.h
FlutterSceneLifeCycle_Test.h
FlutterSharedApplication.h
viewController
FlutterViewController * viewController
Definition: FlutterTextInputPluginTest.mm:139
engine
id engine
Definition: FlutterTextInputPluginTest.mm:136
FlutterEnginePluginSceneLifeCycleDelegate
Definition: FlutterSceneLifeCycle.mm:511
-[FlutterEnginePluginSceneLifeCycleDelegate sceneDidBecomeActive:]
void sceneDidBecomeActive:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:572
-[FlutterEnginePluginSceneLifeCycleDelegate sceneWillEnterForeground:]
void sceneWillEnterForeground:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:564
-[FlutterEnginePluginSceneLifeCycleDelegate sceneWillResignActive:]
void sceneWillResignActive:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:582
-[FlutterEnginePluginSceneLifeCycleDelegate addDelegate:]
void addDelegate:(NSObject< FlutterSceneLifeCycleDelegate > *delegate)
Definition: FlutterSceneLifeCycle.mm:523
-[FlutterEnginePluginSceneLifeCycleDelegate sceneDidEnterBackground:]
void sceneDidEnterBackground:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:590
-[FlutterEnginePluginSceneLifeCycleDelegate sceneDidDisconnect:]
void sceneDidDisconnect:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:554
FlutterAppDelegate
Definition: FlutterAppDelegate.h:28
FlutterEngine
Definition: FlutterEngine.h:61
FlutterPluginAppLifeCycleDelegate
Definition: FlutterPluginAppLifeCycleDelegate.h:16
FlutterPluginSceneLifeCycleDelegate
Definition: FlutterSceneLifeCycle.h:149
-[FlutterPluginSceneLifeCycleDelegate scene:openURLContexts:]
void scene:openURLContexts:(UIScene *scene,[openURLContexts] NSSet< UIOpenURLContext * > *URLContexts)
Definition: FlutterSceneLifeCycle.mm:289
-[FlutterPluginSceneLifeCycleDelegate updateFlutterManagedEnginesInScene:]
void updateFlutterManagedEnginesInScene:(UIScene *scene)
-[FlutterPluginSceneLifeCycleDelegate scene:willConnectToSession:options:]
void scene:willConnectToSession:options:(UIScene *scene,[willConnectToSession] UISceneSession *session,[options] UISceneConnectionOptions *connectionOptions)
Definition: FlutterSceneLifeCycle.mm:191
FlutterPluginSceneLifeCycleDelegate::developerManagedEngines
NSPointerArray * developerManagedEngines
Definition: FlutterSceneLifeCycle_Test.h:15
FlutterPluginSceneLifeCycleDelegate::flutterManagedEngines
NSPointerArray * flutterManagedEngines
Definition: FlutterSceneLifeCycle_Test.h:14
-[FlutterPluginSceneLifeCycleDelegate allEngines]
NSArray * allEngines()
-[FlutterPluginSceneLifeCycleDelegate sceneWillEnterForeground:]
void sceneWillEnterForeground:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:253
-[FlutterPluginSceneLifeCycleDelegate sceneWillResignActive:]
void sceneWillResignActive:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:271
-[FlutterPluginSceneLifeCycleDelegate sceneDidBecomeActive:]
void sceneDidBecomeActive:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:261
-[FlutterPluginSceneLifeCycleDelegate sceneDidEnterBackground:]
void sceneDidEnterBackground:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:279
-[FlutterPluginSceneLifeCycleDelegate sceneDidDisconnect:]
void sceneDidDisconnect:(UIScene *scene)
Definition: FlutterSceneLifeCycle.mm:243
-[FlutterPluginSceneLifeCycleDelegate windowScene:performActionForShortcutItem:completionHandler:]
void windowScene:performActionForShortcutItem:completionHandler:(UIWindowScene *windowScene,[performActionForShortcutItem] UIApplicationShortcutItem *shortcutItem,[completionHandler] void(^ completionHandler)(BOOL succeeded))
Definition: FlutterSceneLifeCycle.mm:409
-[FlutterPluginSceneLifeCycleDelegate scene:continueUserActivity:]
void scene:continueUserActivity:(UIScene *scene,[continueUserActivity] NSUserActivity *userActivity)
Definition: FlutterSceneLifeCycle.mm:323
FlutterRestorationPlugin
Definition: FlutterRestorationPlugin.h:13
FlutterSceneLifecycleTest
Definition: FlutterSceneLifeCycleTest.mm:40
FlutterSharedApplication
Definition: FlutterSharedApplication.h:13
FlutterSwiftUIAppSceneDelegate
Definition: FlutterSceneLifeCycleTest.mm:24
FlutterSwiftUIAppSceneDelegate::sceneLifeCycleDelegate
FlutterPluginSceneLifeCycleDelegate * sceneLifeCycleDelegate
Definition: FlutterSceneLifeCycleTest.mm:24
FlutterViewController
Definition: FlutterViewController.h:57
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FlutterSceneLifeCycleDelegate-p
Definition: FlutterSceneLifeCycle.h:31
-[FlutterSceneLifeCycleEngineRegistration-p unregisterSceneLifeCycleWithFlutterEngine:]
BOOL unregisterSceneLifeCycleWithFlutterEngine:(FlutterEngine *engine)
-[FlutterSceneLifeCycleEngineRegistration-p registerSceneLifeCycleWithFlutterEngine:]
BOOL registerSceneLifeCycleWithFlutterEngine:(FlutterEngine *engine)
FlutterSceneLifeCycleProvider-p
Definition: FlutterSceneLifeCycle.h:213