When using Flutter hybrid development, you will encounter some native controls that are better than Flutter. If you don’t want to use Flutter’s controls, you want to use native controls in Flutter. At this time, you will use the native view embedded in the Flutter page. Here is a brief introduction to a view embedded in iOS.
Note: FlutterBoost is used here. Most of the codes on the Internet cannot be executed. In this case, at least it can be used normally.
- Native part.
Here we start processing in the native part. - Custom view
FlutterIosTextLabel
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface FlutterIosTextLabel : NSObject<FlutterPlatformView>
@property (nonatomic, strong) UILabel *label;
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
NS_ASSUME_NONNULL_END
#import "FlutterIosTextLabel.h"
@implementation FlutterIosTextLabel
//在这里只是创建了一个UILabel
- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
if (self = [super init]) {
self.label = [UILabel new];
self.label.backgroundColor = [UIColor yellowColor];
self.label.textColor = [UIColor redColor];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.numberOfLines = 0;
NSDictionary *dict = (NSDictionary *)args;
NSString *textValue = dict[@"content"];
self.label.text = [NSString stringWithFormat:@"我是iOSView \n在显示:%@", textValue];
}
return self;
}
- (nonnull UIView *)view {
return self.label;
}
@end
- create
FlutterIosTextLabelFactory
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface FlutterIosTextLabelFactory : NSObject<FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
NS_ASSUME_NONNULL_END
#import "FlutterIosTextLabelFactory.h"
#import "FlutterIosTextLabel.h"
@implementation FlutterIosTextLabelFactory
{
NSObject<FlutterBinaryMessenger> *_messenger;
}
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
self = [super init];
if (self) {
_messenger = messenger;
}
return self;
}
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args {
return [[FlutterIosTextLabel alloc] initWithFrame:frame viewIdentifier:viewId arguments:args binaryMessenger:_messenger];
}
-(NSObject<FlutterMessageCodec> *)createArgsCodec{
return [FlutterStandardMessageCodec sharedInstance];
}
- create
FlutterIosTextLabelPlugin
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface FlutterIosTextLabelPlugin : NSObject<FlutterPlugin>
+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar> *)registrar;
@end
NS_ASSUME_NONNULL_END
#import "FlutterIosTextLabelPlugin.h"
#import "FlutterIosTextLabelFactory.h"
@implementation FlutterIosTextLabelPlugin
+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar> *)registrar {
//注册插件
//注册 FlutterIosTextLabelFactory
//custom_platform_view 为flutter 调用此 textLabel 的标识
[registrar registerViewFactory:[[FlutterIosTextLabelFactory alloc] initWithMessenger:registrar.messenger] withId:@"custom_platform_view"];
}
@end
At this point, the native integration is half complete, and the focus is on the next part.
Integrated use in AppDelegate
Modification AppDelegate.h
: Modify inheritance to FlutterAppDelegate
(not required) and delete window
attributes, because FlutterAppDelegate
AppDelegate already has its own window
attributes.
The original AppDelegate inheritance relationship does not have to inherit FlutterAppDelegate, as long as it is correctly registered in FlutterBoost.instance.
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
@interface AppDelegate : FlutterAppDelegate
@end
AppDelegate.m
Introduce relevant header files in
#import "FlutterIosTextLabel.h"
#import "GeneratedPluginRegistrant.h"
#import "FlutterIosTextLabelPlugin.h"
Register the plug-in in AppDelegate.m. When introduced flutter_boost
, you need to wait for flutter_boost initialization to be completed before FlutterEngine
initializing the plug-in.
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
HYFlutterBoostDelegate* delegate = [[HYFlutterBoostDelegate alloc]init];
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
HYTabBarController *tab = [[HYTabBarController alloc]init];
self.window.rootViewController = tab;
[self.window makeKeyAndVisible];
[FlutterBoost.instance setup:application delegate:delegate callback:^(FlutterEngine *engine) {
NSLog(@"FlutterBoost 开始操作");
// 使用 MethodChannel
[HYFlutterNavChannel start];
[HYFlutterCommonChannel start];
// 初始化Flutter内嵌iOSView插件
// NSObject<FlutterPluginRegistrar> *registrar = [engine registrarForPlugin:@"custom_platform_view_plugin"];
// FlutterIosTextLabelFactory *factory = [[FlutterIosTextLabelFactory alloc] initWithMessenger:registrar.messenger];
// [registrar registerViewFactory:factory withId:@"custom_platform_view"];
// `升级处理` 这里正确注册使用即可
NSObject<FlutterPluginRegistrar> *registrar = [engine registrarForPlugin:@"custom_platform_view_plugin"];
[FlutterIosTextLabelPlugin registerWithRegistrar:registrar];
}];
return YES;
}
@end
Now that the native integration is complete, let’s integrate it in Flutter.
- Flutter part
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CMNativePage extends StatelessWidget {
const CMNativePage({
Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("详情"),
),
body: const Center(
child: IOSCompositionWidget(),
),
);
}
}
class IOSCompositionWidget extends StatelessWidget {
const IOSCompositionWidget({
super.key});
Widget build(BuildContext context) {
// This is used in the platform side to register the view.
const String viewType = 'custom_platform_view';
// Pass parameters to the platform side.
final Map<String, dynamic> creationParams = {
'content': 'Flutter传给原生iOSView的参数'
};
return UiKitView(
viewType: viewType,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}
}
Register route
static const String nativaPage = '/nativaPage';
nativaPage: (settings, uniqued) {
return MaterialPageRoute(
settings: settings,
builder: (_) {
return const CMNativePage();
});
},
Used in Flutter
TextButton(
child: const Text("加载原生控件"),
onPressed: () {
BoostNavigator.instance
.push(HYRouter.nativaPage, arguments: {
"home": "home页面传递数值"});
// showBottomWidget(context, const CMNativePage());
},
),
At this point, the integration in Flutter is also completed.
If you want some pop-up styles, handle it yourself. Here we simply use Flutter to embed iOS native views.
Things to note :
FlutterIosTextLabelFactory
The methods increateArgsCodec
must not be omitted, otherwise the value transfer will be unsuccessful. The type must also be consistent withDart
the partialnative.dart
->IOSCompositionWidget
->UiKitView
-> .creationParamsCodec
Otherwise it will cause a crash.- There is no problem if you use the writing method in the official documents, but in this case flutter_boost is used, and problems will arise if you integrate it with the official website. The initialization needs to
flutter_boost
be completed beforeFlutterEngine
initializing the plug-in. - Among them
withId:xxx
, xxx represents the ID of the control, which needs to be consistent with the oneIOSCompositionWidget
in the Dart part.viewType
Named:custom_platform_view
. - Among them
registrarForPlugin:xxx
, xxx represents the ID of the plug-in. Named:custom_platform_view_plugin
.
Native and flutter communicate with each other: