| Flutter iOS Embedder |

platform_view_ios.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 "flutter/shell/platform/darwin/ios/platform_view_ios.h"
6 #include <memory>
7
8 #include <utility>
9
10 #include "flutter/common/task_runners.h"
11 #include "flutter/fml/synchronization/waitable_event.h"
12 #include "flutter/fml/trace_event.h"
13 #include "flutter/shell/common/shell_io_manager.h"
14 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
15 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
16
17 namespace flutter {
18
19 PlatformViewIOS::AccessibilityBridgeManager::AccessibilityBridgeManager(
20 const std::function<void(bool)>& set_semantics_enabled)
21 : AccessibilityBridgeManager(set_semantics_enabled, nullptr) {}
22
23 PlatformViewIOS::AccessibilityBridgeManager::AccessibilityBridgeManager(
24 const std::function<void(bool)>& set_semantics_enabled,
25 AccessibilityBridge* bridge)
26 : accessibility_bridge_(bridge), set_semantics_enabled_(set_semantics_enabled) {
27 if (bridge) {
28 set_semantics_enabled_(true);
29 }
30 }
31
32 void PlatformViewIOS::AccessibilityBridgeManager::Set(std::unique_ptr<AccessibilityBridge> bridge) {
33 accessibility_bridge_ = std::move(bridge);
34 set_semantics_enabled_(true);
35 }
36
37 void PlatformViewIOS::AccessibilityBridgeManager::Clear() {
38 set_semantics_enabled_(false);
39 accessibility_bridge_.reset();
40 }
41
42 PlatformViewIOS::PlatformViewIOS(
43 PlatformView::Delegate& delegate,
44 const std::shared_ptr<IOSContext>& context,
45 const std::shared_ptr<PlatformViewsController>& platform_views_controller,
46 const flutter::TaskRunners& task_runners)
47 : PlatformView(delegate, task_runners),
48 ios_context_(context),
49 platform_views_controller_(platform_views_controller),
50 accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),
51 platform_message_handler_(
52 new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {}
53
54 PlatformViewIOS::PlatformViewIOS(
55 PlatformView::Delegate& delegate,
56 IOSRenderingAPI rendering_api,
57 const std::shared_ptr<PlatformViewsController>& platform_views_controller,
58 const flutter::TaskRunners& task_runners,
59 const std::shared_ptr<fml::ConcurrentTaskRunner>& worker_task_runner,
60 const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch)
61 : PlatformViewIOS(delegate,
62 IOSContext::Create(rendering_api,
63 delegate.OnPlatformViewGetSettings().enable_impeller
64 ? IOSRenderingBackend::kImpeller
65 : IOSRenderingBackend::kSkia,
66 is_gpu_disabled_sync_switch),
67 platform_views_controller,
68 task_runners) {}
69
70 PlatformViewIOS::~PlatformViewIOS() = default;
71
72 // |PlatformView|
73 void PlatformViewIOS::HandlePlatformMessage(std::unique_ptr<flutter::PlatformMessage> message) {
74 platform_message_handler_->HandlePlatformMessage(std::move(message));
75 }
76
77 fml::WeakNSObject<FlutterViewController> PlatformViewIOS::GetOwnerViewController() const {
78 return owner_controller_;
79 }
80
81 void PlatformViewIOS::SetOwnerViewController(
82 const fml::WeakNSObject<FlutterViewController>& owner_controller) {
83 FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
84 std::lock_guard<std::mutex> guard(ios_surface_mutex_);
85 if (ios_surface_ || !owner_controller) {
86 NotifyDestroyed();
87 ios_surface_.reset();
88 accessibility_bridge_.Clear();
89 }
90 owner_controller_ = owner_controller;
91
92 // Add an observer that will clear out the owner_controller_ ivar and
93 // the accessibility_bridge_ in case the view controller is deleted.
94 dealloc_view_controller_observer_.reset(
95 [[[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
96 object:owner_controller_.get()
97 queue:[NSOperationQueue mainQueue]
98 usingBlock:^(NSNotification* note) {
99 // Implicit copy of 'this' is fine.
100 accessibility_bridge_.Clear();
101 owner_controller_.reset();
102 }] retain]);
103
104 if (owner_controller_ && [owner_controller_.get() isViewLoaded]) {
105 this->attachView();
106 }
107 // Do not call `NotifyCreated()` here - let FlutterViewController take care
108 // of that when its Viewport is sized. If `NotifyCreated()` is called here,
109 // it can occasionally get invoked before the viewport is sized resulting in
110 // a framebuffer that will not be able to completely attach.
111 }
112
113 void PlatformViewIOS::attachView() {
114 FML_DCHECK(owner_controller_);
115 FML_DCHECK(owner_controller_.get().isViewLoaded)
116 << "FlutterViewController's view should be loaded "
117 "before attaching to PlatformViewIOS.";
118 auto flutter_view = static_cast<FlutterView*>(owner_controller_.get().view);
119 auto ca_layer = fml::scoped_nsobject<CALayer>{[[flutter_view layer] retain]};
120 ios_surface_ = IOSSurface::Create(ios_context_, ca_layer);
121 FML_DCHECK(ios_surface_ != nullptr);
122
123 if (accessibility_bridge_) {
124 accessibility_bridge_.Set(std::make_unique<AccessibilityBridge>(
125 owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
126 }
127 }
128
129 PointerDataDispatcherMaker PlatformViewIOS::GetDispatcherMaker() {
130 return [](DefaultPointerDataDispatcher::Delegate& delegate) {
131 return std::make_unique<SmoothPointerDataDispatcher>(delegate);
132 };
133 }
134
135 void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id,
136 NSObject<FlutterTexture>* texture) {
137 RegisterTexture(ios_context_->CreateExternalTexture(
138 texture_id, fml::scoped_nsobject<NSObject<FlutterTexture>>{[texture retain]}));
139 }
140
141 // |PlatformView|
142 std::unique_ptr<Surface> PlatformViewIOS::CreateRenderingSurface() {
143 FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
144 std::lock_guard<std::mutex> guard(ios_surface_mutex_);
145 if (!ios_surface_) {
146 FML_DLOG(INFO) << "Could not CreateRenderingSurface, this PlatformViewIOS "
147 "has no ViewController.";
148 return nullptr;
149 }
150 return ios_surface_->CreateGPUSurface(ios_context_->GetMainContext().get());
151 }
152
153 // |PlatformView|
154 std::shared_ptr<ExternalViewEmbedder> PlatformViewIOS::CreateExternalViewEmbedder() {
155 return std::make_shared<IOSExternalViewEmbedder>(platform_views_controller_, ios_context_);
156 }
157
158 // |PlatformView|
159 sk_sp<GrDirectContext> PlatformViewIOS::CreateResourceContext() const {
160 return ios_context_->CreateResourceContext();
161 }
162
163 // |PlatformView|
164 std::shared_ptr<impeller::Context> PlatformViewIOS::GetImpellerContext() const {
165 return ios_context_->GetImpellerContext();
166 }
167
168 // |PlatformView|
169 void PlatformViewIOS::SetSemanticsEnabled(bool enabled) {
170 if (!owner_controller_) {
171 FML_LOG(WARNING) << "Could not set semantics to enabled, this "
172 "PlatformViewIOS has no ViewController.";
173 return;
174 }
175 if (enabled && !accessibility_bridge_) {
176 accessibility_bridge_.Set(std::make_unique<AccessibilityBridge>(
177 owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
178 } else if (!enabled && accessibility_bridge_) {
179 accessibility_bridge_.Clear();
180 } else {
181 PlatformView::SetSemanticsEnabled(enabled);
182 }
183 }
184
185 // |shell:PlatformView|
186 void PlatformViewIOS::SetAccessibilityFeatures(int32_t flags) {
187 PlatformView::SetAccessibilityFeatures(flags);
188 }
189
190 // |PlatformView|
191 void PlatformViewIOS::UpdateSemantics(flutter::SemanticsNodeUpdates update,
192 flutter::CustomAccessibilityActionUpdates actions) {
193 FML_DCHECK(owner_controller_);
194 if (accessibility_bridge_) {
195 accessibility_bridge_.get()->UpdateSemantics(std::move(update), actions);
196 [[NSNotificationCenter defaultCenter] postNotificationName:FlutterSemanticsUpdateNotification
197 object:owner_controller_.get()];
198 }
199 }
200
201 // |PlatformView|
202 std::unique_ptr<VsyncWaiter> PlatformViewIOS::CreateVSyncWaiter() {
203 return std::make_unique<VsyncWaiterIOS>(task_runners_);
204 }
205
206 void PlatformViewIOS::OnPreEngineRestart() const {
207 if (accessibility_bridge_) {
208 accessibility_bridge_.get()->clearState();
209 }
210 if (!owner_controller_) {
211 return;
212 }
213 [owner_controller_.get() platformViewsController]->Reset();
214 [[owner_controller_.get() restorationPlugin] reset];
215 }
216
217 std::unique_ptr<std::vector<std::string>> PlatformViewIOS::ComputePlatformResolvedLocales(
218 const std::vector<std::string>& supported_locale_data) {
219 size_t localeDataLength = 3;
220 NSMutableArray<NSString*>* supported_locale_identifiers =
221 [NSMutableArray arrayWithCapacity:supported_locale_data.size() / localeDataLength];
222 for (size_t i = 0; i < supported_locale_data.size(); i += localeDataLength) {
223 NSDictionary<NSString*, NSString*>* dict = @{
224 NSLocaleLanguageCode : [NSString stringWithUTF8String:supported_locale_data[i].c_str()]
225 ?: @"",
226 NSLocaleCountryCode : [NSString stringWithUTF8String:supported_locale_data[i + 1].c_str()]
227 ?: @"",
228 NSLocaleScriptCode : [NSString stringWithUTF8String:supported_locale_data[i + 2].c_str()]
229 ?: @""
230 };
231 [supported_locale_identifiers addObject:[NSLocale localeIdentifierFromComponents:dict]];
232 }
233 NSArray<NSString*>* result =
234 [NSBundle preferredLocalizationsFromArray:supported_locale_identifiers];
235
236 // Output format should be either empty or 3 strings for language, country, and script.
237 std::unique_ptr<std::vector<std::string>> out = std::make_unique<std::vector<std::string>>();
238
239 if (result != nullptr && [result count] > 0) {
240 NSLocale* locale = [NSLocale localeWithLocaleIdentifier:[result firstObject]];
241 NSString* languageCode = [locale languageCode];
242 out->emplace_back(languageCode == nullptr ? "" : languageCode.UTF8String);
243 NSString* countryCode = [locale countryCode];
244 out->emplace_back(countryCode == nullptr ? "" : countryCode.UTF8String);
245 NSString* scriptCode = [locale scriptCode];
246 out->emplace_back(scriptCode == nullptr ? "" : scriptCode.UTF8String);
247 }
248 return out;
249 }
250
251 PlatformViewIOS::ScopedObserver::ScopedObserver() {}
252
253 PlatformViewIOS::ScopedObserver::~ScopedObserver() {
254 if (observer_) {
255 [[NSNotificationCenter defaultCenter] removeObserver:observer_];
256 [observer_ release];
257 }
258 }
259
260 void PlatformViewIOS::ScopedObserver::reset(id<NSObject> observer) {
261 if (observer != observer_) {
262 if (observer_) {
263 [[NSNotificationCenter defaultCenter] removeObserver:observer_];
264 [observer_ release];
265 }
266 observer_ = observer;
267 }
268 }
269
270 } // namespace flutter
flutter::IOSRenderingBackend::kSkia
@ kSkia
flutter::PlatformMessageHandlerIos
Definition: platform_message_handler_ios.h:16
FlutterSemanticsUpdateNotification
FLUTTER_DARWIN_EXPORT const NSNotificationName FlutterSemanticsUpdateNotification
Definition: FlutterViewController.mm:42
flutter::PlatformViewIOS
Definition: platform_view_ios.h:41
flutter::PlatformViewIOS::SetOwnerViewController
void SetOwnerViewController(const fml::WeakNSObject< FlutterViewController > &owner_controller)
Definition: platform_view_ios.mm:81
flutter::IOSContext
Manages the lifetime of the on-screen and off-screen rendering contexts on iOS. On-screen contexts ar...
Definition: ios_context.h:40
flutter::IOSRenderingBackend
IOSRenderingBackend
Definition: rendering_api_selection.h:19
flutter::IOSRenderingBackend::kImpeller
@ kImpeller
flutter::PlatformViewIOS::~PlatformViewIOS
~PlatformViewIOS() override
FlutterViewControllerWillDealloc
const NSNotificationName FlutterViewControllerWillDealloc
Definition: FlutterViewController.mm:43
flutter
Definition: accessibility_bridge.h:28
flutter::PlatformViewIOS::attachView
void attachView()
Definition: platform_view_ios.mm:113
flutter::IOSRenderingAPI
IOSRenderingAPI
Definition: rendering_api_selection.h:14
flutter::PlatformViewIOS::GetOwnerViewController
fml::WeakNSObject< FlutterViewController > GetOwnerViewController() const
Definition: platform_view_ios.mm:77
FlutterViewController_Internal.h
flutter::IOSSurface::Create
static std::unique_ptr< IOSSurface > Create(std::shared_ptr< IOSContext > context, const fml::scoped_nsobject< CALayer > &layer)
Definition: ios_surface.mm:19
FlutterView
Definition: FlutterView.h:34
vsync_waiter_ios.h
flutter::PlatformViewIOS::SetSemanticsEnabled
void SetSemanticsEnabled(bool enabled) override
Definition: platform_view_ios.mm:169
platform_view_ios.h
texture_id
int64_t texture_id
Definition: texture_registrar_unittests.cc:24
flutter::PlatformViewIOS::RegisterExternalTexture
void RegisterExternalTexture(int64_t id, NSObject< FlutterTexture > *texture)
Definition: platform_view_ios.mm:135
flutter::PlatformViewIOS::GetDispatcherMaker
PointerDataDispatcherMaker GetDispatcherMaker() override
Definition: platform_view_ios.mm:129
flutter::PlatformViewIOS::PlatformViewIOS
PlatformViewIOS(PlatformView::Delegate &delegate, const std::shared_ptr< IOSContext > &context, const std::shared_ptr< PlatformViewsController > &platform_views_controller, const flutter::TaskRunners &task_runners)
Definition: platform_view_ios.mm:42