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