本文通过傻瓜式的图文结合方式,来讲解iOS项目接入Flutter项目的配置过程,以及iOS代码如何与Flutter代码交互,适合初学者。全文是基于自己的学习和理解,通过实际操作实践,整理的纯技术学习笔记,如有不对的地方或者不详细之处,请大家批评指正。
开发环境
- macOS10.15.5
- Xcode 11.5
- Cocoapods 1.9.3
- Android Studio 3.5.3
- Flutter 1.12.13
备注:本文假设大家都已安装好iOS和Flutter开发环境。
Flutter项目工程
-
使用Android Studio新建一个Flutter Module工程,暂且命名为flutter_module。(或者使用命令行新建一个Flutter Module工程)
-
打开flutter_module工程下的配置文件pubspec.yaml,在文件的头部菜单点击“Packages get”按钮,运行配置。
-
Flutter项目工程完成配置,紧接着配置iOS项目工程。
iOS项目工程
-
使用Xcode新建一个Single View App,暂且命名为“FlutterApp”,项目保存于flutter_module同一目录下。
-
在FlutterApp工程目录下,新建一个Podfile文件,用于管理iOS第三方库和Flutter关联配置。
-
文件目录结构以及Podfile内容如下图所示
-
以下提供Podfile内容配置代码,可供大家复制粘贴使用。
platform :ios, '9.0' use_frameworks! ##添加如下两行代码,支持flutter混合开发 ## 该路径是Module工程flutter_module工程的路径,我把它放在与iOS App(FlutterApp)工程同一个目录下 ##(也可以放在其他目录,只要把路径配置正确即可) flutter_application_path = '../flutter_module/' ## 加载flutter_module的Xcode和pod配置 load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'FlutterApp' do pod 'AFNetworking', '~> 2.6' ## 加载flutter_module使用到的第三方库 install_all_flutter_pods(flutter_application_path) end
-
-
使用macOS自带的终端,切换到Podfile所在的文件目录下,执行“pod install”命令,即可在FlutterApp工程目录下生成FlutterApp.xcworkspace工程。
-
使用Xcode打开FlutterApp.xcworkspace工程,运行项目,此时混合环境已经配置完成。
iOS与Flutter交互
- 使用Android Studio打开flutter_module工程,在main.dart文件,编辑代码如下:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Module',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
debugShowCheckedModeBanner: false, //隐藏调试模式标签
);
}
}
class MyHomePage extends StatelessWidget {
//消息通道(原生代码也需要用到这个通道名称,两者必须命名一致)
final MethodChannel _channel = MethodChannel("com.abc.flutter/channel");
MyHomePage() {
//接收App原生代码端发起的交互请求
Future<dynamic> callback(MethodCall call) async {
//App原生代码发起的交互:pageInfo请求
if (call.method == "pageInfo") {
//处理请求
}
}
this._channel.setMethodCallHandler(callback); //配置响应函数
}
//点击了“退出”按钮
void _onClickBackButtonHandler() {
//flutter发起的交互:点击了导航栏“退出”按钮
this._channel.invokeMethod("navigateExit");
}
//点击了“信息”按钮
void _onClickInfoButtonHandler() {
//flutter发起的交互:点击了导航栏“信息”按钮
this._channel.invokeMethod("navigateInfo");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Page"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: _onClickBackButtonHandler,
), //导航栏“退出”按钮
actions: <Widget>[
IconButton(
icon: Icon(Icons.info),
onPressed: _onClickInfoButtonHandler,
)
], //导航栏“信息”按钮
),
body: Center(
child: Text("我是flutter_module默认路由页面");
), //页面内容
);
}
}
-
保存main.dart,无需运行。
-
使用Xcode打开FlutterApp.xcworkspace工程,在ViewController.m文件,编辑代码如下:
#import "ViewController.h" #import <Flutter/Flutter.h> @interface ViewController () @property (nonatomic, strong) FlutterViewController *flutterVC; //flutter视图控制器,展示flutter页面内容 @property (nonatomic, strong) FlutterMethodChannel *flutterChannel;//消息通道(flutter与原生交互) @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化flutter页面控制器 self.flutterVC = [[FlutterViewController alloc] init]; //初始化flutter消息通道(消息通道名称必须与flutter_module命名一致) NSObject<FlutterBinaryMessenger> *bm = (NSObject<FlutterBinaryMessenger> *)self.flutterVC; self.flutterChannel = [FlutterMethodChannel methodChannelWithName:@"com.abc.flutter/channel" binaryMessenger:bm]; //配置flutter消息通道与原生通讯 [self setupFlutterMethodChannel]; //添加按钮,打开flutter页面控制器 UIButton *btn = [[UIButton alloc] init]; [btn setTitle:@"进入flutter页面" forState:UIControlStateNormal]; [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(onClickFlutterButtonHandler) forControlEvents:UIControlEventTouchUpInside]; btn.frame = CGRectMake(0, 0, 200, 45); btn.center = self.view.center; [self.view addSubview:btn]; } //点击“进入flutter页面”按钮 - (void)onClickFlutterButtonHandler { //进入flutter页面,默认进入flutter_module的根页面 //[self.flutterVC setInitialRoute:@""]; //可通过setInitialRoute设置flutter模块的某个页面路由,控制进入某个页面 [self presentViewController:self.flutterVC animated:true completion:nil]; } //设置flutter与iOS原生项目的通讯 - (void)setupFlutterMethodChannel { __weak typeof(self) weakSelf = self; [self.flutterChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { __strong typeof(weakSelf) strongSelf = weakSelf; //接收来自flutter页面的交互 if ([@"navigateExit" isEqualToString:call.method]) { //接收到flutter_module的“退出”请求 [strongSelf.flutterVC dismissViewControllerAnimated:YES completion:nil]; } else if ([@"navigateInfo" isEqualToString:call.method]) { //接收到flutter_module的“信息”请求,然后反发起pageInfo请求到flutter_module [strongSelf.flutterChannel invokeMethod:@"pageInfo" arguments:@{@"name": @"Flutter 中国"}]; } }]; } @end -
保存代码,编译运行,即可完成简单的iOS与Flutter交互功能。 运行效果如下:
-
flutter_module工程的代码,每次编辑后,只需保存即可,然后需要在Xcode中打开FlutterApp工程代码重新编译并运行,才能生效。