Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 335e125

Browse files
committed
Add an iOS PlatformViewsController for creating/disposing UIViews.
* Adds a FlutterPlatformViewFactory protocol - a simple factory protocol to be implemented by plugins that exposes a UIView for embeeding in Flutter apps. * Adds a FlutterPlatformView protocol, which is used to associate a dispose callback with a `UIView` created by a FlutterPlatformViewFactory. * Exposes a registerViewFactory method in FlutterPluginRegistrar. * Implements the `flutter/platform_views` system channel on iOS, allowing Dart code to ask for creation/destruction of UIViews.
1 parent c645657 commit 335e125

7 files changed

Lines changed: 208 additions & 0 deletions

File tree

shell/platform/darwin/ios/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ _flutter_framework_headers = [
2929
"framework/Headers/FlutterHeadlessDartRunner.h",
3030
"framework/Headers/FlutterMacros.h",
3131
"framework/Headers/FlutterNavigationController.h",
32+
"framework/Headers/FlutterPlatformViews.h",
3233
"framework/Headers/FlutterPlugin.h",
3334
"framework/Headers/FlutterPluginAppLifeCycleDelegate.h",
3435
"framework/Headers/FlutterTexture.h",
@@ -55,6 +56,8 @@ shared_library("create_flutter_framework_dylib") {
5556
"framework/Source/FlutterNavigationController.mm",
5657
"framework/Source/FlutterPlatformPlugin.h",
5758
"framework/Source/FlutterPlatformPlugin.mm",
59+
"framework/Source/FlutterPlatformViews_Internal.h",
60+
"framework/Source/FlutterPlatformViews.mm",
5861
"framework/Source/FlutterPluginAppLifeCycleDelegate.mm",
5962
"framework/Source/FlutterStandardCodec.mm",
6063
"framework/Source/FlutterStandardCodec_Internal.h",

shell/platform/darwin/ios/framework/Headers/Flutter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "FlutterHeadlessDartRunner.h"
5151
#include "FlutterMacros.h"
5252
#include "FlutterNavigationController.h"
53+
#include "FlutterPlatformViews.h"
5354
#include "FlutterPlugin.h"
5455
#include "FlutterPluginAppLifeCycleDelegate.h"
5556
#include "FlutterTexture.h"
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2019 The Chromium 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+
#ifndef FLUTTER_FLUTTERPLATFORMVIEWS_H_
6+
#define FLUTTER_FLUTTERPLATFORMVIEWS_H_
7+
8+
#import <CoreMedia/CoreMedia.h>
9+
#import <Foundation/Foundation.h>
10+
#import <UIKit/UIKit.h>
11+
12+
#include "FlutterCodecs.h"
13+
#include "FlutterMacros.h"
14+
15+
NS_ASSUME_NONNULL_BEGIN
16+
17+
/**
18+
An instance of a `UIView` created by a `FlutterPlatformViewFactory`.
19+
20+
This protocol is used to associate a view with a dispose callback.
21+
*/
22+
FLUTTER_EXPORT
23+
@protocol FlutterPlatformView <NSObject>
24+
- (UIView*)view;
25+
/**
26+
Called when the Flutter engine no longer needs this `view`.
27+
28+
The implementation of this method should release any kept for this view.
29+
*/
30+
- (void)dispose;
31+
@end
32+
33+
FLUTTER_EXPORT
34+
@protocol FlutterPlatformViewFactory <NSObject>
35+
/**
36+
Create a `FlutterPlatformView`.
37+
38+
Implemented by iOS code that expose a `UIView` for embedding in a Flutter app.
39+
40+
The implementation of this method should create a new `UIView` and return a `FlutterPlatformView`
41+
that wraps it.
42+
43+
- Parameters:
44+
- frame: The rectangle for the newly created `UIView` measued in points.
45+
- args: Parameters for creating the `UIView` sent from the Dart side of the Flutter app.
46+
If `createArgsCodec` is not implemented, or if no creation arguments were sent from the Dart
47+
code, this will be null. Otherwise this will be the value sent from the Dart code as decoded by
48+
`createArgsCodec`.
49+
*/
50+
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame andArgs:(id _Nullable)args;
51+
52+
/**
53+
Returns the `FlutterMessageCodec` for decoding the args parameter of `createWithFrame`.
54+
55+
Only needs to be implemented if `createWithFrame` needs an arguments parameter.
56+
*/
57+
@optional
58+
- (NSObject<FlutterMessageCodec>*)createArgsCodec;
59+
@end
60+
61+
NS_ASSUME_NONNULL_END
62+
63+
#endif // FLUTTER_FLUTTERPLATFORMVIEWS_H_

shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "FlutterBinaryMessenger.h"
1111
#include "FlutterChannels.h"
1212
#include "FlutterCodecs.h"
13+
#include "FlutterPlatformViews.h"
1314
#include "FlutterTexture.h"
1415

1516
NS_ASSUME_NONNULL_BEGIN
@@ -203,6 +204,19 @@ NS_ASSUME_NONNULL_BEGIN
203204
*/
204205
- (NSObject<FlutterTextureRegistry>*)textures;
205206

207+
/**
208+
Registers a `FlutterPlatformViewFactory` for creation of platfrom views.
209+
210+
Plugins expose `UIView` for embedding in Flutter apps by registering a view factory.
211+
212+
- Parameters:
213+
- factory: The view factory that will be registered.
214+
- factoryId:: A unique identifier for the factory, the Dart code of the Flutter app can use
215+
this identifier to request creation of a `UIView` by the registered factory.
216+
*/
217+
- (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
218+
withId:(NSString*)factoryId;
219+
206220
/**
207221
Publishes a value for external use of the plugin.
208222
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#include <map>
2+
#include <memory>
3+
#include <string>
4+
5+
#include "FlutterPlatformViews_Internal.h"
6+
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
7+
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h"
8+
9+
@implementation FlutterPlatformViewsController {
10+
fml::scoped_nsobject<FlutterMethodChannel> _channel;
11+
std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> _factories;
12+
std::map<long, fml::scoped_nsobject<NSObject<FlutterPlatformView>>> _views;
13+
}
14+
15+
- (instancetype)init:(NSObject<FlutterBinaryMessenger>*)withMessenger {
16+
if (self = [super init]) {
17+
_channel.reset([[FlutterMethodChannel alloc]
18+
initWithName:@"flutter/platform_views"
19+
binaryMessenger:withMessenger
20+
codec:[FlutterStandardMethodCodec sharedInstance]]);
21+
[_channel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
22+
[self methodCallHandler:call withResult:result];
23+
}];
24+
}
25+
return self;
26+
}
27+
28+
- (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
29+
withId:(NSString*)factoryId {
30+
std::string idString([factoryId UTF8String]);
31+
NSAssert(_factories.count(idString) == 0,
32+
([NSString stringWithFormat:@"Can't register an already registered view factory: %@",
33+
factoryId]));
34+
_factories[idString] =
35+
fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>([factory retain]);
36+
}
37+
38+
- (void)methodCallHandler:(FlutterMethodCall*)call withResult:(FlutterResult)result {
39+
if ([[call method] isEqualToString:@"create"]) {
40+
[self handleCreate:call withResult:result];
41+
} else if ([[call method] isEqualToString:@"dispose"]) {
42+
[self handleDispose:call withResult:result];
43+
} else {
44+
result(FlutterMethodNotImplemented);
45+
}
46+
}
47+
48+
- (void)handleCreate:(FlutterMethodCall*)call withResult:(FlutterResult)result {
49+
NSDictionary<NSString*, id>* args = [call arguments];
50+
51+
long viewId = [args[@"id"] longValue];
52+
std::string viewType([args[@"viewType"] UTF8String]);
53+
54+
if (_views[viewId] != nil) {
55+
result([FlutterError errorWithCode:@"recreating_view"
56+
message:@"trying to create an already created view"
57+
details:[NSString stringWithFormat:@"view id: '%ld'", viewId]]);
58+
}
59+
60+
NSObject<FlutterPlatformViewFactory>* factory = _factories[viewType].get();
61+
if (factory == nil) {
62+
result([FlutterError errorWithCode:@"unregistered_view_type"
63+
message:@"trying to create a view with an unregistered type"
64+
details:[NSString stringWithFormat:@"unregistered view type: '%@'",
65+
args[@"viewType"]]]);
66+
return;
67+
}
68+
69+
// TODO(amirh): decode and pass the creation args.
70+
_views[viewId] =
71+
fml::scoped_nsobject<NSObject<FlutterPlatformView>>([[factory createWithFrame:CGRectZero
72+
andArgs:nil] retain]);
73+
result(nil);
74+
}
75+
76+
- (void)handleDispose:(FlutterMethodCall*)call withResult:(FlutterResult)result {
77+
NSDictionary<NSString*, id>* args = [call arguments];
78+
long viewId = [args[@"id"] longValue];
79+
80+
if (_views[viewId] == nil) {
81+
result([FlutterError errorWithCode:@"unknown_view"
82+
message:@"trying to dispose an unknown"
83+
details:[NSString stringWithFormat:@"view id: '%ld'", viewId]]);
84+
return;
85+
}
86+
87+
[_views[viewId] dispose];
88+
_views.erase(viewId);
89+
result(nil);
90+
}
91+
92+
@end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
7+
8+
#include "flutter/shell/common/shell.h"
9+
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterBinaryMessenger.h"
10+
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
11+
12+
@interface FlutterPlatformViewsController : NSObject
13+
14+
- (instancetype)init:(NSObject<FlutterBinaryMessenger>*)withMessenger;
15+
16+
- (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
17+
withId:(NSString*)factoryId;
18+
19+
@end
20+
21+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_

shell/platform/darwin/ios/framework/Source/FlutterViewController.mm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#define FML_USED_ON_EMBEDDER
66

7+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
78
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
89

910
#include <memory>
@@ -52,6 +53,7 @@ @implementation FlutterViewController {
5253
fml::scoped_nsobject<FlutterView> _flutterView;
5354
fml::scoped_nsobject<UIView> _splashScreenView;
5455
fml::ScopedBlock<void (^)(void)> _flutterViewRenderedCallback;
56+
fml::scoped_nsobject<FlutterPlatformViewsController> _platformViewsController;
5557
UIInterfaceOrientationMask _orientationPreferences;
5658
UIStatusBarStyle _statusBarStyle;
5759
blink::ViewportMetrics _viewportMetrics;
@@ -105,6 +107,7 @@ - (void)performCommonViewControllerInitialization {
105107
[self setupChannels];
106108
[self setupNotificationCenterObservers];
107109

110+
_platformViewsController.reset([[FlutterPlatformViewsController alloc] init:self]);
108111
_pluginPublications = [NSMutableDictionary new];
109112
}
110113
}
@@ -1056,6 +1059,12 @@ - (void)onPreferredStatusBarStyleUpdated:(NSNotification*)notification {
10561059
});
10571060
}
10581061

1062+
#pragma mark - Platform views
1063+
1064+
- (FlutterPlatformViewsController*)platformViewsController {
1065+
return _platformViewsController.get();
1066+
}
1067+
10591068
#pragma mark - FlutterBinaryMessenger
10601069

10611070
- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
@@ -1162,6 +1171,11 @@ - (void)dealloc {
11621171
return _flutterViewController;
11631172
}
11641173

1174+
- (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1175+
withId:(NSString*)factoryId {
1176+
[[_flutterViewController platformViewsController] registerViewFactory:factory withId:factoryId];
1177+
}
1178+
11651179
- (void)publish:(NSObject*)value {
11661180
_flutterViewController.pluginPublications[_pluginKey] = value;
11671181
}

0 commit comments

Comments
 (0)