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