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