今天来学习下Flutter如何集成在iOS项目中

方式一
cd some/path/
flutter create --template module my_flutter
方式二

使用Android Studio 创建Flutter Module,一直Next


创建好的工程目录如下

some/path/
 ├── my_flutter/
 │   └── .ios/
 │       └── Flutter/
 │         └── podhelper.rb
 └── MyApp/
 └── Podfile

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
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撸一个登录页面
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://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3145573887,3597137496&fm=26&gp=0.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端代码
#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 登录页面
[flutterViewController setInitialRoute:@"flutter_login"];
Flutter 端设置跳转登录的路由 flutter_login
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
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,这就是简单的集成。
查看原文
如果您觉得还不错,麻烦在文末 “点个赞” 或者 下方评论,谢谢您的支持
最后推送一波福利想了解Flutter或进阶Flutter的可以关注iOS交流群或许有你需要的资料!!!