今天来学习下Flutter如何集成在老的iOS项目中 参考iOS老项目如何集成Flutter
方式一
代码语言:javascript复制cd some/path/
flutter create --template module my_flutter
方式二
使用Android Studio 创建Flutter Module,一直Next
屏幕快照 2019-12-17 15.28.11.png
创建好的工程目录如下 some/path/ ├── my_flutter/ │ └── .ios/ │ └── Flutter/ │ └── podhelper.rb └── MyApp/ └── Podfile
屏幕快照 2019-12-17 14.54.23.png
Flutter目录和iOS目录必须是同级目录
将Flutter模块嵌入到现有App
有两种方法可以将Flutter嵌入到现有应用程序中。 1.Use the CocoaPods dependency manager and installed Flutter SDK. (Recommended.) 2.Create frameworks for the Flutter engine, your compiled Dart code, and all Flutter plugins. Manually embed the frameworks, and update your existing application’s build settings in Xcode.
iOS CocoaPods引入Flutter
代码语言:javascript复制source 'https://github.com/CocoaPods/Specs.git'
platform :ios, "10.0"
flutter_application_path = '../my_flutter/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
def install_pods
pod 'AFNetworking', '~> 3.2.1'
end
target 'MyApp' do
install_pods
install_all_flutter_pods(flutter_application_path)
end
执行 pod install
用Flutter撸一个登录页面
代码语言:javascript复制import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() {
return _LoginPageState();
}
}
class _LoginPageState extends State<LoginPage> {
TextEditingController _pwdEditController;
TextEditingController _userNameEditController;
final FocusNode _userNameFocusNode = FocusNode();
final FocusNode _pwdFocusNode = FocusNode();
@override
void initState() {
super.initState();
_pwdEditController = TextEditingController();
_userNameEditController = TextEditingController();
_pwdEditController.addListener(() => setState(() => {}));
_userNameEditController.addListener(() => setState(() => {}));
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[400],
elevation: 0,
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
buildTopWidget(context),
SizedBox(height: 80),
buildEditWidget(context),
buildLoginButton()
],
),
),
);
}
/// 头部
Widget buildTopWidget(BuildContext context) {
double height = 200.0;
double width = MediaQuery.of(context).size.width;
return Container(
width: width,
height: height,
color: Colors.blue[400],
child: Stack(
overflow: Overflow.visible, // 超出部分显示
children: <Widget>[
Positioned(
left: (width - 90) / 2.0,
top: height - 45,
child: Container(
width: 90.0,
height: 90.0,
decoration: BoxDecoration(
///阴影
boxShadow: [
BoxShadow(color: Theme.of(context).cardColor, blurRadius: 4.0)
],
///形状
shape: BoxShape.circle,
///图片
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1569298229946&di=ea4ffb2b140ef40035772bbcee7bbdd5&imgtype=0&src=http://cimg2.163.com/catchimg/20090909/8112139_3.jpg'),
),
),
),
)
],
),
);
}
/// 输入框
Widget buildEditWidget(BuildContext context) {
return Container(
margin: EdgeInsets.only(left: 15, right: 15),
child: Column(
children: <Widget>[
buildLoginNameTextField(),
SizedBox(height: 20.0),
buildPwdTextField(),
],
),
);
}
/// 用户名
Widget buildLoginNameTextField() {
return Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
child: Stack(
children: <Widget>[
Positioned(
left: 16,
top: 11,
width: 18,
height: 18,
child: Image.asset('images/login_user.png'),
),
Positioned(
left: 45,
top: 10,
bottom: 10,
width: 1,
child: Container(
color: Colors.black,
),
),
Positioned(
left: 55,
right: 10,
top: 10,
height: 30,
child: TextField(
controller: _userNameEditController,
focusNode: _userNameFocusNode,
decoration: InputDecoration(
hintText: "请输入用户名",
border: InputBorder.none,
),
style: TextStyle(fontSize: 14),
),
)
],
),
);
}
/// 密码
Widget buildPwdTextField() {
return Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
child: Stack(
children: <Widget>[
Positioned(
left: 16,
top: 11,
width: 18,
height: 18,
child: Image.asset('images/login_pwd.png'),
),
Positioned(
left: 45,
top: 10,
bottom: 10,
width: 1,
child: Container(
color: Colors.black,
),
),
Positioned(
left: 55,
right: 10,
top: 10,
height: 30,
child: TextField(
controller: _pwdEditController,
focusNode: _pwdFocusNode,
decoration: InputDecoration(
hintText: "请输入密码",
border: InputBorder.none,
),
style: TextStyle(fontSize: 14),
obscureText: true, /// 设置密码
),
)
],
));
}
/// 登录按钮
Widget buildLoginButton(){
return Container(
margin: EdgeInsets.only(top: 40,left: 10,right: 10),
padding: EdgeInsets.all(0),
width: MediaQuery.of(context).size.width-20,
height: 40,
child: RaisedButton(
onPressed: () {
_getNativeMessage();
},
child: Text("登录"),
color: Colors.blue[400],
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
),
);
}
void _getNativeMessage() async{
// 对应OC中的FlutterMethodChannel
const platform = const MethodChannel('com.allen.test.call');
String message = 'null message';
String result;
try {
var map = { "userName": "develop","pwd":"Aqi123456"};
// OC回调中对应的”约定” : getFlutterMessage,[1,2,3]:传递参数
result = await platform.invokeMethod('getFlutterMessage',map);
} on PlatformException catch (e) {
result = "error message $e";
}
setState(() {
message = result;
});
}
bool checkInput(){
if(_userNameEditController.text.length == 0){
return false;
}
else if (_pwdEditController.text.length == 0){
return false;
}
return true;
}
}
OC端代码
代码语言:javascript复制#import <Flutter/Flutter.h>
- (IBAction)goFlutterAction:(UIButton *)sender {
FlutterViewController *flutterViewController = [FlutterViewController new];
[flutterViewController setInitialRoute:@"flutter_login"];
[self.navigationController pushViewController:flutterViewController animated:YES];
__weak typeof(self) weakSelf = self;
FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"com.allen.test.call" binaryMessenger:flutterViewController];
[channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
// Flutter invokeMethod 特定方法的时候会触发到这里
if ([call.method isEqualToString:@"getFlutterMessage"]) {
result(@"接收到flutter的消息,回传信息from OC");
NSLog(@"接收到flutter的参数:%@",call.arguments);
[weakSelf goOCVC:call.arguments];
}
}];
}
下面代码的作用就是我们要跳转指定的Flutter 登录页面
代码语言:javascript复制[flutterViewController setInitialRoute:@"flutter_login"];
Flutter 端设置跳转登录的路由 flutter_login
代码语言:javascript复制import 'package:flutter/material.dart';
import 'widget/home_page.dart';
import 'widget/login_page.dart';
void main(){
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,// 显示和隐藏
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
routes: <String ,WidgetBuilder>{
"flutter_login": (_) => new LoginPage(),
},
);
}
}
Flutter端传参数给OC
代码语言:javascript复制void _getNativeMessage() async{
// 对应OC中的FlutterMethodChannel
const platform = const MethodChannel('com.allen.test.call');
String message = 'null message';
String result;
try {
var map = { "userName": "develop","pwd":"123456"};
// OC回调中对应的”约定” : getFlutterMessage,[1,2,3]:传递参数
result = await platform.invokeMethod('getFlutterMessage',map);
} on PlatformException catch (e) {
result = "error message $e";
}
setState(() {
message = result;
});
}
调用goFlutterAction方法就会跳转到Flutter的登录页面,点击Flutter的登录就会把参数传给OC,这就是简单的集成。