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 
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 
43  PlatformView::Delegate& delegate,
44  const std::shared_ptr<IOSContext>& context,
45  const std::shared_ptr<FlutterPlatformViewsController>& 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 
55  PlatformView::Delegate& delegate,
56  IOSRenderingAPI rendering_api,
57  const std::shared_ptr<FlutterPlatformViewsController>& 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)
62  delegate,
63  IOSContext::Create(
64  rendering_api,
65  delegate.OnPlatformViewGetSettings().enable_impeller ? IOSRenderingBackend::kImpeller
67  static_cast<MsaaSampleCount>(delegate.OnPlatformViewGetSettings().msaa_samples),
68  is_gpu_disabled_sync_switch),
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 
79 fml::WeakNSObject<FlutterViewController> PlatformViewIOS::GetOwnerViewController() const {
80  return owner_controller_;
81 }
82 
84  const fml::WeakNSObject<FlutterViewController>& owner_controller) {
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(
97  [[[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
98  object:owner_controller_.get()
99  queue:[NSOperationQueue mainQueue]
100  usingBlock:^(NSNotification* note) {
101  // Implicit copy of 'this' is fine.
102  accessibility_bridge_.Clear();
103  owner_controller_.reset();
104  }] retain]);
105 
106  if (owner_controller_ && [owner_controller_.get() 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_.get().isViewLoaded)
118  << "FlutterViewController's view should be loaded "
119  "before attaching to PlatformViewIOS.";
120  auto flutter_view = static_cast<FlutterView*>(owner_controller_.get().view);
121  auto ca_layer = fml::scoped_nsobject<CALayer>{[[flutter_view layer] retain]};
122  ios_surface_ = IOSSurface::Create(ios_context_, ca_layer);
123  FML_DCHECK(ios_surface_ != nullptr);
124 
125  if (accessibility_bridge_) {
126  accessibility_bridge_.Set(std::make_unique<AccessibilityBridge>(
127  owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
128  }
129 }
130 
131 PointerDataDispatcherMaker PlatformViewIOS::GetDispatcherMaker() {
132  return [](DefaultPointerDataDispatcher::Delegate& delegate) {
133  return std::make_unique<SmoothPointerDataDispatcher>(delegate);
134  };
135 }
136 
138  NSObject<FlutterTexture>* texture) {
139  RegisterTexture(ios_context_->CreateExternalTexture(
140  texture_id, fml::scoped_nsobject<NSObject<FlutterTexture>>{[texture retain]}));
141 }
142 
143 // |PlatformView|
144 std::unique_ptr<Surface> PlatformViewIOS::CreateRenderingSurface() {
145  FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
146  std::lock_guard<std::mutex> guard(ios_surface_mutex_);
147  if (!ios_surface_) {
148  FML_DLOG(INFO) << "Could not CreateRenderingSurface, this PlatformViewIOS "
149  "has no ViewController.";
150  return nullptr;
151  }
152  return ios_surface_->CreateGPUSurface(ios_context_->GetMainContext().get());
153 }
154 
155 // |PlatformView|
156 std::shared_ptr<ExternalViewEmbedder> PlatformViewIOS::CreateExternalViewEmbedder() {
157  return std::make_shared<IOSExternalViewEmbedder>(platform_views_controller_, ios_context_);
158 }
159 
160 // |PlatformView|
161 sk_sp<GrDirectContext> PlatformViewIOS::CreateResourceContext() const {
162  return ios_context_->CreateResourceContext();
163 }
164 
165 // |PlatformView|
166 std::shared_ptr<impeller::Context> PlatformViewIOS::GetImpellerContext() const {
167  return ios_context_->GetImpellerContext();
168 }
169 
170 // |PlatformView|
172  if (!owner_controller_) {
173  FML_LOG(WARNING) << "Could not set semantics to enabled, this "
174  "PlatformViewIOS has no ViewController.";
175  return;
176  }
177  if (enabled && !accessibility_bridge_) {
178  accessibility_bridge_.Set(std::make_unique<AccessibilityBridge>(
179  owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
180  } else if (!enabled && accessibility_bridge_) {
181  accessibility_bridge_.Clear();
182  } else {
183  PlatformView::SetSemanticsEnabled(enabled);
184  }
185 }
186 
187 // |shell:PlatformView|
188 void PlatformViewIOS::SetAccessibilityFeatures(int32_t flags) {
189  PlatformView::SetAccessibilityFeatures(flags);
190 }
191 
192 // |PlatformView|
193 void PlatformViewIOS::UpdateSemantics(flutter::SemanticsNodeUpdates update,
194  flutter::CustomAccessibilityActionUpdates actions) {
195  FML_DCHECK(owner_controller_);
196  if (accessibility_bridge_) {
197  accessibility_bridge_.get()->UpdateSemantics(std::move(update), actions);
198  [[NSNotificationCenter defaultCenter] postNotificationName:FlutterSemanticsUpdateNotification
199  object:owner_controller_.get()];
200  }
201 }
202 
203 // |PlatformView|
204 std::unique_ptr<VsyncWaiter> PlatformViewIOS::CreateVSyncWaiter() {
205  return std::make_unique<VsyncWaiterIOS>(task_runners_);
206 }
207 
208 void PlatformViewIOS::OnPreEngineRestart() const {
209  if (accessibility_bridge_) {
210  accessibility_bridge_.get()->clearState();
211  }
212  if (!owner_controller_) {
213  return;
214  }
215  [owner_controller_.get() platformViewsController]->Reset();
216  [[owner_controller_.get() restorationPlugin] reset];
217 }
218 
219 std::unique_ptr<std::vector<std::string>> PlatformViewIOS::ComputePlatformResolvedLocales(
220  const std::vector<std::string>& supported_locale_data) {
221  size_t localeDataLength = 3;
222  NSMutableArray<NSString*>* supported_locale_identifiers =
223  [NSMutableArray arrayWithCapacity:supported_locale_data.size() / localeDataLength];
224  for (size_t i = 0; i < supported_locale_data.size(); i += localeDataLength) {
225  NSDictionary<NSString*, NSString*>* dict = @{
226  NSLocaleLanguageCode : [NSString stringWithUTF8String:supported_locale_data[i].c_str()]
227  ?: @"",
228  NSLocaleCountryCode : [NSString stringWithUTF8String:supported_locale_data[i + 1].c_str()]
229  ?: @"",
230  NSLocaleScriptCode : [NSString stringWithUTF8String:supported_locale_data[i + 2].c_str()]
231  ?: @""
232  };
233  [supported_locale_identifiers addObject:[NSLocale localeIdentifierFromComponents:dict]];
234  }
235  NSArray<NSString*>* result =
236  [NSBundle preferredLocalizationsFromArray:supported_locale_identifiers];
237 
238  // Output format should be either empty or 3 strings for language, country, and script.
239  std::unique_ptr<std::vector<std::string>> out = std::make_unique<std::vector<std::string>>();
240 
241  if (result != nullptr && [result count] > 0) {
242  NSLocale* locale = [NSLocale localeWithLocaleIdentifier:[result firstObject]];
243  NSString* languageCode = [locale languageCode];
244  out->emplace_back(languageCode == nullptr ? "" : languageCode.UTF8String);
245  NSString* countryCode = [locale countryCode];
246  out->emplace_back(countryCode == nullptr ? "" : countryCode.UTF8String);
247  NSString* scriptCode = [locale scriptCode];
248  out->emplace_back(scriptCode == nullptr ? "" : scriptCode.UTF8String);
249  }
250  return out;
251 }
252 
253 PlatformViewIOS::ScopedObserver::ScopedObserver() {}
254 
255 PlatformViewIOS::ScopedObserver::~ScopedObserver() {
256  if (observer_) {
257  [[NSNotificationCenter defaultCenter] removeObserver:observer_];
258  [observer_ release];
259  }
260 }
261 
262 void PlatformViewIOS::ScopedObserver::reset(id<NSObject> observer) {
263  if (observer != observer_) {
264  if (observer_) {
265  [[NSNotificationCenter defaultCenter] removeObserver:observer_];
266  [observer_ release];
267  }
268  observer_ = observer;
269  }
270 }
271 
272 } // namespace flutter
flutter::IOSRenderingBackend::kSkia
@ kSkia
flutter::PlatformMessageHandlerIos
Definition: platform_message_handler_ios.h:19
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:83
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
flutter
Definition: accessibility_bridge.h:28
flutter::PlatformViewIOS::attachView
void attachView()
Definition: platform_view_ios.mm:115
flutter::IOSRenderingAPI
IOSRenderingAPI
Definition: rendering_api_selection.h:14
flutter::PlatformViewIOS::GetOwnerViewController
fml::WeakNSObject< FlutterViewController > GetOwnerViewController() const
Definition: platform_view_ios.mm:79
FlutterViewControllerWillDealloc
const NSNotificationName FlutterViewControllerWillDealloc
Definition: FlutterViewController.mm:43
flutter::PlatformViewIOS::PlatformViewIOS
PlatformViewIOS(PlatformView::Delegate &delegate, const std::shared_ptr< IOSContext > &context, const std::shared_ptr< FlutterPlatformViewsController > &platform_views_controller, const flutter::TaskRunners &task_runners)
Definition: platform_view_ios.mm:42
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:18
FlutterView
Definition: FlutterView.h:39
vsync_waiter_ios.h
flutter::PlatformViewIOS::SetSemanticsEnabled
void SetSemanticsEnabled(bool enabled) override
Definition: platform_view_ios.mm:171
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:137
flutter::PlatformViewIOS::GetDispatcherMaker
PointerDataDispatcherMaker GetDispatcherMaker() override
Definition: platform_view_ios.mm:131