Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2c7c8f4

Browse files
author
Chris Yang
committed
draft
draft format draf format draf fix non extension build add extension safe builders generate extension safe output fix build config fix clang tidy complains add to tests fix tests remove test logs fox tests fix test fix memory leak in platform plugin test format review
1 parent 32f929f commit 2c7c8f4

11 files changed

Lines changed: 572 additions & 70 deletions

File tree

ci/builders/mac_unopt.json

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,77 @@
223223
"script": "flutter/testing/scenario_app/run_ios_tests.sh"
224224
}
225225

226+
]
227+
},
228+
{
229+
"archives": [
230+
{
231+
"base_path": "out/ios_debug_sim_arm64_extension_safe/zip_archives/",
232+
"type": "gcs",
233+
"include_paths": [
234+
],
235+
"name": "ios_debug_sim_arm64_extension_safe"
236+
}
237+
],
238+
"properties": {
239+
"$flutter/osx_sdk": {
240+
"runtime_versions": [
241+
"ios-16-4_14e300c",
242+
"ios-16-2_14c18"
243+
],
244+
"sdk_version": "14e300c"
245+
}
246+
},
247+
"drone_dimensions": [
248+
"device_type=none",
249+
"os=Mac-12",
250+
"cpu=arm64"
251+
],
252+
"gclient_variables": {
253+
"download_android_deps": false
254+
},
255+
"gn": [
256+
"--ios",
257+
"--runtime-mode",
258+
"debug",
259+
"--simulator",
260+
"--no-lto",
261+
"--force-mac-arm64",
262+
"--simulator-cpu",
263+
"arm64",
264+
"--darwin-extension-safe"
265+
],
266+
"name": "ios_debug_sim_arm64_extension_safe",
267+
"ninja": {
268+
"config": "ios_debug_sim_arm64_extension_safe",
269+
"targets": [
270+
"flutter/testing/scenario_app",
271+
"flutter/shell/platform/darwin/ios:ios_test_flutter"
272+
]
273+
},
274+
"tests": [
275+
{
276+
"language": "python3",
277+
"name": "Tests for ios_debug_sim_arm64_extension_safe",
278+
"parameters": [
279+
"--variant",
280+
"ios_debug_sim_arm64_extension_safe",
281+
"--type",
282+
"objc",
283+
"--engine-capture-core-dump",
284+
"--ios-variant",
285+
"ios_debug_sim_arm64_extension_safe"
286+
],
287+
"script": "flutter/testing/run_tests.py"
288+
},
289+
{
290+
"name": "Scenario App Integration Tests",
291+
"parameters": [
292+
"ios_debug_sim_arm64_extension_safe"
293+
],
294+
"script": "flutter/testing/scenario_app/run_ios_tests.sh"
295+
}
296+
226297
]
227298
}
228299
]

common/config.gni

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ declare_args() {
2222

2323
# Whether to include backtrace support.
2424
enable_backtrace = true
25+
26+
# Whether to include --fapplication-extension when build iOS framework.
27+
# This is currently a test flag and does not work properly.
28+
#TODO(cyanglaz): Remove above comment about test flag when the entire iOS embedder supports app extension
29+
#https://github.com/flutter/flutter/issues/124289
30+
darwin_extension_safe = false
2531
}
2632

2733
# feature_defines_list ---------------------------------------------------------

shell/platform/darwin/ios/BUILD.gn

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ source_set("flutter_framework_source_arc") {
4444
cflags_objcc = flutter_cflags_objcc_arc
4545

4646
defines = [ "FLUTTER_FRAMEWORK=1" ]
47+
if (darwin_extension_safe) {
48+
defines += [ "APPLICATION_EXTENSION_API_ONLY=1" ]
49+
}
4750
allow_circular_includes_from = [ ":flutter_framework_source" ]
4851
deps = [
4952
":flutter_framework_source",
@@ -153,6 +156,9 @@ source_set("flutter_framework_source") {
153156
sources += _flutter_framework_headers
154157

155158
defines = [ "FLUTTER_FRAMEWORK=1" ]
159+
if (darwin_extension_safe) {
160+
defines += [ "APPLICATION_EXTENSION_API_ONLY=1" ]
161+
}
156162

157163
if (shell_enable_metal) {
158164
sources += [
@@ -249,6 +255,10 @@ source_set("ios_test_flutter_mrc") {
249255
if (shell_enable_vulkan) {
250256
deps += [ "//flutter/vulkan" ]
251257
}
258+
259+
if (darwin_extension_safe) {
260+
defines = [ "APPLICATION_EXTENSION_API_ONLY=1" ]
261+
}
252262
}
253263

254264
shared_library("ios_test_flutter") {
@@ -312,6 +322,10 @@ shared_library("ios_test_flutter") {
312322
":ios_gpu_configuration_config",
313323
"//flutter:config",
314324
]
325+
326+
if (darwin_extension_safe) {
327+
defines = [ "APPLICATION_EXTENSION_API_ONLY=1" ]
328+
}
315329
}
316330

317331
shared_library("create_flutter_framework_dylib") {

shell/platform/darwin/ios/framework/Source/FlutterEngine.mm

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -225,22 +225,44 @@ - (instancetype)initWithName:(NSString*)labelPrefix
225225
name:UIApplicationDidReceiveMemoryWarningNotification
226226
object:nil];
227227

228+
#if APPLICATION_EXTENSION_API_ONLY
229+
if (@available(iOS 13.0, *)) {
230+
[self setUpSceneLifecycleNotifications:center];
231+
} else {
232+
[self setUpApplicationLifecycleNotifications:center];
233+
}
234+
#else
235+
[self setUpApplicationLifecycleNotifications:center];
236+
#endif
237+
228238
[center addObserver:self
229-
selector:@selector(applicationWillEnterForeground:)
230-
name:UIApplicationWillEnterForegroundNotification
239+
selector:@selector(onLocaleUpdated:)
240+
name:NSCurrentLocaleDidChangeNotification
231241
object:nil];
232242

243+
return self;
244+
}
245+
246+
- (void)setUpSceneLifecycleNotifications:(NSNotificationCenter*)center API_AVAILABLE(ios(13.0)) {
233247
[center addObserver:self
234-
selector:@selector(applicationDidEnterBackground:)
235-
name:UIApplicationDidEnterBackgroundNotification
248+
selector:@selector(sceneWillEnterForeground:)
249+
name:UISceneWillEnterForegroundNotification
236250
object:nil];
237-
238251
[center addObserver:self
239-
selector:@selector(onLocaleUpdated:)
240-
name:NSCurrentLocaleDidChangeNotification
252+
selector:@selector(sceneDidEnterBackground:)
253+
name:UISceneDidEnterBackgroundNotification
241254
object:nil];
255+
}
242256

243-
return self;
257+
- (void)setUpApplicationLifecycleNotifications:(NSNotificationCenter*)center {
258+
[center addObserver:self
259+
selector:@selector(applicationWillEnterForeground:)
260+
name:UIApplicationWillEnterForegroundNotification
261+
object:nil];
262+
[center addObserver:self
263+
selector:@selector(applicationDidEnterBackground:)
264+
name:UIApplicationDidEnterBackgroundNotification
265+
object:nil];
244266
}
245267

246268
- (void)recreatePlatformViewController {
@@ -856,8 +878,20 @@ - (BOOL)createShell:(NSString*)entrypoint
856878
_threadHost->io_thread->GetTaskRunner() // io
857879
);
858880

881+
#if APPLICATION_EXTENSION_API_ONLY
882+
if (@available(iOS 13.0, *)) {
883+
_isGpuDisabled = self.viewController.windowSceneIfViewLoaded.activationState ==
884+
UISceneActivationStateBackground;
885+
} else {
886+
// [UIApplication sharedApplication API is not available for app extension.
887+
// We intialize the shell assuming the GPU is required.
888+
_isGpuDisabled = NO;
889+
}
890+
#else
859891
_isGpuDisabled =
860892
[UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
893+
#endif
894+
861895
// Create the shell. This is a blocking operation.
862896
std::unique_ptr<flutter::Shell> shell = flutter::Shell::Create(
863897
/*platform_data=*/platformData,
@@ -1302,11 +1336,29 @@ - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
13021336

13031337
#pragma mark - Notifications
13041338

1339+
#if APPLICATION_EXTENSION_API_ONLY
1340+
- (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1341+
[self flutterWillEnterForeground:notification];
1342+
}
1343+
1344+
- (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1345+
[self flutterDidEnterBackground:notification];
1346+
}
1347+
#else
13051348
- (void)applicationWillEnterForeground:(NSNotification*)notification {
1306-
[self setIsGpuDisabled:NO];
1349+
[self flutterWillEnterForeground:notification];
13071350
}
13081351

13091352
- (void)applicationDidEnterBackground:(NSNotification*)notification {
1353+
[self flutterDidEnterBackground:notification];
1354+
}
1355+
#endif
1356+
1357+
- (void)flutterWillEnterForeground:(NSNotification*)notification {
1358+
[self setIsGpuDisabled:NO];
1359+
}
1360+
1361+
- (void)flutterDidEnterBackground:(NSNotification*)notification {
13101362
[self setIsGpuDisabled:YES];
13111363
[self notifyLowMemory];
13121364
}

shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#import <objc/runtime.h>
1010

1111
#import "flutter/common/settings.h"
12+
#include "flutter/fml/synchronization/sync_switch.h"
1213
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
1314
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterBinaryMessengerRelay.h"
1415
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
@@ -341,4 +342,62 @@ - (void)testFlutterEngineUpdatesDisplays {
341342
OCMVerify(times(2), [mockEngine updateDisplays]);
342343
}
343344

345+
- (void)testLifeCycleNotificationDidEnterBackground {
346+
FlutterDartProject* project = [[FlutterDartProject alloc] init];
347+
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
348+
[engine run];
349+
NSNotification* sceneNotification =
350+
[NSNotification notificationWithName:UISceneDidEnterBackgroundNotification
351+
object:nil
352+
userInfo:nil];
353+
NSNotification* applicationNotification =
354+
[NSNotification notificationWithName:UIApplicationDidEnterBackgroundNotification
355+
object:nil
356+
userInfo:nil];
357+
id mockEngine = OCMPartialMock(engine);
358+
[[NSNotificationCenter defaultCenter] postNotification:sceneNotification];
359+
[[NSNotificationCenter defaultCenter] postNotification:applicationNotification];
360+
#if APPLICATION_EXTENSION_API_ONLY
361+
OCMVerify(times(1), [mockEngine sceneDidEnterBackground:[OCMArg any]]);
362+
#else
363+
OCMVerify(times(1), [mockEngine applicationDidEnterBackground:[OCMArg any]]);
364+
#endif
365+
XCTAssertTrue(engine.isGpuDisabled);
366+
bool switch_value = false;
367+
[engine shell].GetIsGpuDisabledSyncSwitch()->Execute(
368+
fml::SyncSwitch::Handlers().SetIfTrue([&] { switch_value = true; }).SetIfFalse([&] {
369+
switch_value = false;
370+
}));
371+
XCTAssertTrue(switch_value);
372+
}
373+
374+
- (void)testLifeCycleNotificationWillEnterForeground {
375+
FlutterDartProject* project = [[FlutterDartProject alloc] init];
376+
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
377+
[engine run];
378+
NSNotification* sceneNotification =
379+
[NSNotification notificationWithName:UISceneWillEnterForegroundNotification
380+
object:nil
381+
userInfo:nil];
382+
NSNotification* applicationNotification =
383+
[NSNotification notificationWithName:UIApplicationWillEnterForegroundNotification
384+
object:nil
385+
userInfo:nil];
386+
id mockEngine = OCMPartialMock(engine);
387+
[[NSNotificationCenter defaultCenter] postNotification:sceneNotification];
388+
[[NSNotificationCenter defaultCenter] postNotification:applicationNotification];
389+
#if APPLICATION_EXTENSION_API_ONLY
390+
OCMVerify(times(1), [mockEngine sceneWillEnterForeground:[OCMArg any]]);
391+
#else
392+
OCMVerify(times(1), [mockEngine applicationWillEnterForeground:[OCMArg any]]);
393+
#endif
394+
XCTAssertFalse(engine.isGpuDisabled);
395+
bool switch_value = true;
396+
[engine shell].GetIsGpuDisabledSyncSwitch()->Execute(
397+
fml::SyncSwitch::Handlers().SetIfTrue([&] { switch_value = true; }).SetIfFalse([&] {
398+
switch_value = false;
399+
}));
400+
XCTAssertFalse(switch_value);
401+
}
402+
344403
@end

shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ class ThreadHost;
3535
- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
3636
performAction:(FlutterTextInputAction)action
3737
withClient:(int)client;
38+
- (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0));
39+
- (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0));
40+
- (void)applicationWillEnterForeground:(NSNotification*)notification;
41+
- (void)applicationDidEnterBackground:(NSNotification*)notification;
42+
3843
@end

shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,23 @@ - (void)popSystemNavigator:(BOOL)isAnimated {
269269
// It's also possible in an Add2App scenario that the FlutterViewController was presented
270270
// outside the context of a UINavigationController, and still wants to be popped.
271271

272-
UIViewController* engineViewController = [_engine.get() viewController];
272+
FlutterViewController* engineViewController = [_engine.get() viewController];
273273
UINavigationController* navigationController = [engineViewController navigationController];
274274
if (navigationController) {
275275
[navigationController popViewControllerAnimated:isAnimated];
276276
} else {
277-
UIViewController* rootViewController =
278-
[UIApplication sharedApplication].keyWindow.rootViewController;
277+
UIViewController* rootViewController = nil;
278+
#if APPLICATION_EXTENSION_API_ONLY
279+
if (@available(iOS 15.0, *)) {
280+
rootViewController =
281+
[engineViewController windowSceneIfViewLoaded].keyWindow.rootViewController;
282+
} else {
283+
FML_LOG(WARNING)
284+
<< "rootViewController is not available in application extension prior to iOS 15.0.";
285+
}
286+
#else
287+
rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
288+
#endif
279289
if (engineViewController != rootViewController) {
280290
[engineViewController dismissViewControllerAnimated:isAnimated completion:nil];
281291
}

shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ - (void)testLookUpCallInitiated {
3737
XCTestExpectation* presentExpectation =
3838
[self expectationWithDescription:@"Look Up view controller presented"];
3939

40-
FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
41-
nibName:nil
42-
bundle:nil];
40+
FlutterViewController* engineViewController =
41+
[[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil] autorelease];
4342
FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
4443

4544
FlutterPlatformPlugin* plugin =

0 commit comments

Comments
 (0)