Skip to content

Commit 48532ca

Browse files
authored
[iOS] Create FlutterFMLTaskRunner(s) (flutter#185617)
fml::TaskRunner is a core C++ dependency for asynchronous task execution across the iOS embedder. It appears frequently in Objective-C API which is problematic for adding or migrating embedder code to Swift. This class also makes heavy use of fml::TimePoint and fml::TimeDelta, and thus adds further C++ to any code making use of the task runner. flutter::TaskRunners, is a container that groups together task runners for the platform thread, UI thread, and raster thread. This adds FlutterFMLTaskRunner and FlutterFMLTaskRunners. Ideally, these would be named FlutterTaskRunner but that identifier is already a key part of the Embedder API. To differentiate our FML-based run loops from the Embedder API types, we add FML to the name. The two new classes have API that is entirely free from C++ types, but for each, we introduce a category on it in the FlutterTaskRunner[s]+FML.h header that includes an initialiser that takes the associated C++ type and a getter that returns it. This allows for a stepwise migration. This patch adds, but does not yet migrate to, the new wrapper types. I'll send follow-up patches with the migrations. Issue: flutter#157140 <!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I added new tests to check the change I am making, or this PR is [test-exempt]. - [X] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [X] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent f152beb commit 48532ca

12 files changed

Lines changed: 361 additions & 3 deletions

engine/src/flutter/shell/platform/darwin/ios/BUILD.gn

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ source_set("InternalFlutterSwift") {
4545
# Targets should only ever depend on the framework target.
4646
# This allows code in this target to use types declared in the bridging
4747
# header, but defined in the framework, while avoiding linking errors.
48-
visibility = [ ":flutter_framework_source" ]
48+
visibility = [
49+
":flutter_framework_source",
50+
":ios_test_flutter",
51+
]
4952
configs += [ "//flutter/shell/platform/darwin/common:config" ]
53+
deps = [ ":flutter_engine_bindings" ]
5054
include_dirs = [
5155
"//flutter/shell/platform/darwin/common/framework/Headers",
5256
"//flutter/shell/platform/darwin/ios/framework/Headers",
@@ -212,23 +216,52 @@ source_set("flutter_framework_source") {
212216
"//flutter/third_party/icu",
213217
"//flutter/third_party/spring_animation",
214218
]
215-
public_deps = [ ":InternalFlutterSwift" ]
219+
public_deps = [
220+
":InternalFlutterSwift",
221+
":flutter_engine_bindings",
222+
]
216223
}
217224

218225
if (enable_ios_unittests) {
226+
source_set("flutter_engine_bindings_test_helpers") {
227+
testonly = true
228+
visibility = [ ":*" ]
229+
configs += [ "//flutter/shell/platform/darwin/common:test_config" ]
230+
sources = [
231+
"framework/Source/FlutterFMLTaskRunnerTestHelper.h",
232+
"framework/Source/FlutterFMLTaskRunnerTestHelper.mm",
233+
]
234+
deps = [
235+
":flutter_engine_bindings",
236+
"//flutter/fml",
237+
]
238+
}
239+
219240
source_set("ios_test_flutter_swift") {
220241
testonly = true
221242
visibility = [ ":*" ]
222243
configs += [ "//flutter/shell/platform/darwin/common:test_config" ]
244+
include_dirs = [
245+
"//flutter/shell/platform/darwin/common/framework/Headers",
246+
"//flutter/shell/platform/darwin/ios/framework/Headers",
247+
"//flutter/shell/platform/darwin/ios/framework",
248+
]
249+
bridge_header = "FlutterTests-Bridging-Header.h"
223250
sources = [
224251
"framework/Source/AccessibilityFeaturesTests.swift",
225252
"framework/Source/ConnectionCollectionTest.swift",
226253
"framework/Source/FakeUIPressProxy.swift",
227254
"framework/Source/LaunchEngineTest.swift",
228255
"framework/Source/SplashScreenManagerTests.swift",
256+
"framework/Source/TaskRunnerTests.swift",
229257
]
230258
frameworks = [ "XCTest.framework" ]
231-
deps = [ ":flutter_framework_source" ]
259+
deps = [
260+
":flutter_engine_bindings",
261+
":flutter_engine_bindings_test_helpers",
262+
":flutter_framework_source",
263+
"//flutter/fml",
264+
]
232265
}
233266

234267
shared_library("ios_test_flutter") {
@@ -291,6 +324,8 @@ if (enable_ios_unittests) {
291324
"platform_view_ios_test.mm",
292325
]
293326
deps = [
327+
":InternalFlutterSwift",
328+
":flutter_engine_bindings_test_helpers",
294329
":flutter_framework",
295330
":flutter_framework_source",
296331
":ios_gpu_configuration",
@@ -314,6 +349,34 @@ if (enable_ios_unittests) {
314349
}
315350
} # if (enable_ios_unittests)
316351

352+
source_set("flutter_engine_bindings") {
353+
visibility = [ ":*" ]
354+
cflags_objc = flutter_cflags_objc
355+
cflags_objcc = flutter_cflags_objcc
356+
357+
defines = [ "FLUTTER_FRAMEWORK=1" ]
358+
configs += [ "//flutter/shell/platform/darwin/common:config" ]
359+
include_dirs = [
360+
"//flutter/shell/platform/darwin/common/framework/Headers",
361+
"//flutter/shell/platform/darwin/ios/framework/Headers",
362+
"//flutter/shell/platform/darwin/ios/framework", # For module.modulemap
363+
]
364+
sources = [
365+
"framework/Source/FlutterFMLTaskRunner+FML.h",
366+
"framework/Source/FlutterFMLTaskRunner.h",
367+
"framework/Source/FlutterFMLTaskRunner.mm",
368+
"framework/Source/FlutterFMLTaskRunners.h",
369+
"framework/Source/FlutterFMLTaskRunners.mm",
370+
]
371+
deps = [
372+
"//flutter/common",
373+
"//flutter/fml",
374+
"//flutter/shell/common",
375+
"//flutter/shell/platform/darwin/common:framework_common",
376+
]
377+
public_deps = [ "//flutter/third_party/spring_animation" ]
378+
}
379+
317380
shared_library("create_flutter_framework_dylib") {
318381
visibility = [ ":*" ]
319382

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FLUTTERTESTS_BRIDGING_HEADER_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FLUTTERTESTS_BRIDGING_HEADER_H_
7+
8+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner.h"
9+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunnerTestHelper.h"
10+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunners.h"
11+
12+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FLUTTERTESTS_BRIDGING_HEADER_H_

engine/src/flutter/shell/platform/darwin/ios/InternalFlutterSwift-Bridging-Header.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_INTERNALFLUTTERSWIFT_BRIDGING_HEADER_H_
77

88
#import "flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h"
9+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner.h"
10+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunners.h"
911

1012
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_INTERNALFLUTTERSWIFT_BRIDGING_HEADER_H_
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNER_FML_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNER_FML_H_
7+
8+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner.h"
9+
10+
#include "flutter/fml/memory/ref_ptr.h"
11+
#include "flutter/fml/task_runner.h"
12+
13+
@interface FlutterFMLTaskRunner ()
14+
15+
- (instancetype)initWithTaskRunner:(fml::RefPtr<fml::TaskRunner>)task_runner;
16+
17+
- (fml::RefPtr<fml::TaskRunner>)taskRunner;
18+
19+
@end
20+
21+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNER_FML_H_
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNER_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNER_H_
7+
8+
#import <Foundation/Foundation.h>
9+
10+
NS_SWIFT_NAME(TaskRunner)
11+
@interface FlutterFMLTaskRunner : NSObject
12+
13+
- (void)postTask:(void (^)(void))task;
14+
- (void)runNowOrPostTask:(void (^)(void))task;
15+
- (void)postTaskWithDelay:(NSTimeInterval)delay
16+
task:(void (^)(void))task NS_SWIFT_NAME(postTask(delay:task:));
17+
18+
- (BOOL)runsTasksOnCurrentThread;
19+
20+
@end
21+
22+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNER_H_
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner+FML.h"
6+
7+
#include <utility>
8+
9+
#include "flutter/fml/logging.h"
10+
11+
@implementation FlutterFMLTaskRunner {
12+
fml::RefPtr<fml::TaskRunner> _taskRunner;
13+
}
14+
15+
- (instancetype)initWithTaskRunner:(fml::RefPtr<fml::TaskRunner>)task_runner {
16+
FML_DCHECK(task_runner);
17+
if (self = [super init]) {
18+
_taskRunner = std::move(task_runner);
19+
}
20+
return self;
21+
}
22+
23+
- (void)postTask:(void (^)(void))task {
24+
FML_DCHECK(task);
25+
_taskRunner->PostTask([task]() { task(); });
26+
}
27+
28+
- (void)runNowOrPostTask:(void (^)(void))task {
29+
FML_DCHECK(task);
30+
fml::TaskRunner::RunNowOrPostTask(_taskRunner, [task]() { task(); });
31+
}
32+
33+
- (void)postTaskWithDelay:(NSTimeInterval)delay task:(void (^)(void))task {
34+
FML_DCHECK(task);
35+
_taskRunner->PostDelayedTask([task]() { task(); }, fml::TimeDelta::FromSecondsF(delay));
36+
}
37+
38+
- (BOOL)runsTasksOnCurrentThread {
39+
return _taskRunner->RunsTasksOnCurrentThread();
40+
}
41+
42+
- (fml::RefPtr<fml::TaskRunner>)taskRunner {
43+
return _taskRunner;
44+
}
45+
46+
@end
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERTESTHELPER_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERTESTHELPER_H_
7+
8+
#import <Foundation/Foundation.h>
9+
10+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner.h"
11+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunners.h"
12+
13+
NS_ASSUME_NONNULL_BEGIN
14+
15+
@interface FlutterFMLTaskRunnerTestHelper : NSObject
16+
17+
/**
18+
* Returns a FlutterFMLTaskRunner for the current thread.
19+
*/
20+
+ (FlutterFMLTaskRunner*)makeCurrentThreadTaskRunner;
21+
22+
/**
23+
* Returns a FlutterFMLTaskRunners object where all runners point to the same task runner.
24+
*/
25+
+ (FlutterFMLTaskRunners*)makeTaskRunnersWithLabel:(NSString*)label
26+
taskRunner:(FlutterFMLTaskRunner*)taskRunner;
27+
28+
@end
29+
30+
NS_ASSUME_NONNULL_END
31+
32+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERTESTHELPER_H_
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunnerTestHelper.h"
6+
7+
#include "flutter/fml/message_loop.h"
8+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner+FML.h"
9+
10+
@implementation FlutterFMLTaskRunnerTestHelper
11+
12+
+ (FlutterFMLTaskRunner*)makeCurrentThreadTaskRunner {
13+
fml::MessageLoop::EnsureInitializedForCurrentThread();
14+
return [[FlutterFMLTaskRunner alloc]
15+
initWithTaskRunner:fml::MessageLoop::GetCurrent().GetTaskRunner()];
16+
}
17+
18+
+ (FlutterFMLTaskRunners*)makeTaskRunnersWithLabel:(NSString*)label
19+
taskRunner:(FlutterFMLTaskRunner*)taskRunner {
20+
return [[FlutterFMLTaskRunners alloc] initWithLabel:label
21+
platformTaskRunner:taskRunner
22+
rasterTaskRunner:taskRunner
23+
uiTaskRunner:taskRunner
24+
ioTaskRunner:taskRunner];
25+
}
26+
27+
@end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERS_FML_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERS_FML_H_
7+
8+
#include "flutter/common/task_runners.h"
9+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunners.h"
10+
11+
@interface FlutterFMLTaskRunners (FML)
12+
13+
@property(nonatomic, readonly) const flutter::TaskRunners& taskRunners;
14+
15+
@end
16+
17+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERS_FML_H_
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERS_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERS_H_
7+
8+
#import <Foundation/Foundation.h>
9+
10+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFMLTaskRunner.h"
11+
12+
NS_ASSUME_NONNULL_BEGIN
13+
14+
NS_SWIFT_NAME(TaskRunners)
15+
@interface FlutterFMLTaskRunners : NSObject
16+
17+
@property(nonatomic, readonly) NSString* label;
18+
@property(nonatomic, readonly) FlutterFMLTaskRunner* platformTaskRunner;
19+
@property(nonatomic, readonly) FlutterFMLTaskRunner* rasterTaskRunner;
20+
@property(nonatomic, readonly) FlutterFMLTaskRunner* uiTaskRunner;
21+
@property(nonatomic, readonly) FlutterFMLTaskRunner* ioTaskRunner;
22+
23+
- (instancetype)initWithLabel:(NSString*)label
24+
platformTaskRunner:(FlutterFMLTaskRunner*)platformTaskRunner
25+
rasterTaskRunner:(FlutterFMLTaskRunner*)rasterTaskRunner
26+
uiTaskRunner:(FlutterFMLTaskRunner*)uiTaskRunner
27+
ioTaskRunner:(FlutterFMLTaskRunner*)ioTaskRunner;
28+
29+
@end
30+
31+
NS_ASSUME_NONNULL_END
32+
33+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERFMLTASKRUNNERS_H_

0 commit comments

Comments
 (0)