官方解决方案:https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps

这一篇讲一下iOS老项目集成Flutter流程。并且实现

  1. iOS 页面跳转到 Flutter 页面
  2. Flutter 页面跳转到 iOS 页面
一、iOS老项目集成Flutter
  1. 创建一个iOS项目或者在老项目上操作 这里我有工程:ProtocolTest 集成了Cocoapods
  2. 将IOS SDK制作Flutter插件 ios开发flutter_iOS页面跳转Flutter页面


  3. iOS工程Enable Bitcode 需要关闭,因为Flutter混合开发不支持Bitcode
  4. ProtocolTest的父级文件夹Flutter_OC创建flutter_module
cd ProtocolTest`的父级文件夹`Flutter_OC
flutter create -t module flutter_module

将IOS SDK制作Flutter插件 ios开发flutter_iOS页面跳转Flutter页面_02


执行完flutter create -t module flutter_module命令后目录如下

将IOS SDK制作Flutter插件 ios开发flutter_将IOS SDK制作Flutter插件_03

  1. 添加脚本
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

将IOS SDK制作Flutter插件 ios开发flutter_iOS老项目集成Flutter流程_04

注意: Run Script 在Target Dependencies或者[CP]Check pods Manifest.lock后面
  1. 我们打开Podfile修改一下,以便将flutter包括在里面
platform :ios, '9.0'
target 'myproject' do

end

#新添加的代码
flutter_application_path = '../'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

我的Podfile如下

# Uncomment this line to define a global platform for your project
use_frameworks!

source 'https://github.com/CocoaPods/Specs.git' # 公开的第三方库
source 'https://gitee.com/muyushifang07/MYCode_tools_repos.git' # 私有库

platform :ios, '9.0'
target 'ProtocolTest' do
    
    #不带:path  的pod install 成功后会生成Pods 文件夹,里面都是远端github的库
    pod 'AFNetworking'
    
    #pod 'RSAHandlerDemo' ,:path => 'https://github.com/muyushifang07/RSAHandlerDemo.git'
    
    pod 'MYHexTool','~>0.1.0'
    
    ## ==============Flutter ==============_
    ## Flutter 模块的路径 pod update --verbose --no-repo-update_
    ##绝对路径_
    flutter_application_path = '/Users/suning/Desktop/flutterdemos/Flutter_OC/flutter_module'
    eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
    ## ==============Flutter ==============_

end

终端执行 pod install

将IOS SDK制作Flutter插件 ios开发flutter_iOS页面跳转Flutter页面_05


执行后pod installPod 文件目录如下:flutter被包涵进来了

将IOS SDK制作Flutter插件 ios开发flutter_Flutter 页面跳转到 iOS 页面_06

  1. 到这里,编译下工程没有报错。证明在OC项目中配置flutter完毕,我们开始开发功能。
OC中调用Flutter Module

在OC中调用Flutter Module有两种方式

1)直接使用FlutterViewController的方式;
2) 使用FlutterEngine的方式;

我这里实现了第一种方式:跳转路径

  1. 在OC 的页面上放置一个按钮:pushToFlutterPage 点击跳到Flutter 的main.dart页面。
  2. 在FLutter main.dart页面放置按钮Push 到 FLutter的FirstScreen.dart 页面
  3. 在FLutter FirstScreen.dart页面放置按钮Push 到 OC的SettingViewController 页面

    实现下面这样的跳转
1. OC端代码

ViewController.m

#import "ViewController.h"
#import <Flutter/Flutter.h>
#include "GeneratedPluginRegistrant.h"
#import "SettingViewController.h"

@interface ViewController ()
{
    FlutterViewController *flutterVC;
    FlutterMethodChannel *batteryChannel;
}
@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.title = @"我是iOS 页面";
    
    flutterVC = [[FlutterViewController alloc]initWithProject:nil nibName:nil bundle:nil];
    flutterVC.title = @"我是Flutter页面";
    batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.dev/battery" binaryMessenger:flutterVC];
}


- (IBAction)pushNext:(id)sender {
    NSLog(@"你好吗?");
    
    //如果使用了插件显示view
    [GeneratedPluginRegistrant registerWithRegistry:flutterVC];
    //[flutterVC setInitialRoute:@"myApp12"];
    [flutterVC setInitialRoute:@"myApp"];
    [self.navigationController pushViewController:flutterVC animated:YES];
    
    __weak typeof(self) weakSelf = self;
    [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
        // Note: this method is invoked on the UI thread.
        if ([@"getBatteryLevel" isEqualToString:call.method])
        {
            int batteryLevel = [weakSelf getBatteryLevel];
            if (batteryLevel == -1) {
                result([FlutterError errorWithCode:@"UNAVAILABLE" message:@"Battery info unavailable" details:nil]);
            } else {
                result(@(batteryLevel));
            }
            
        } else if ([@"backToNavigatorIndex" isEqualToString:call.method]) {
            NSArray *arguments = call.arguments;
            
            NSNumber *inde = arguments[0];
            NSLog(@"arguments :%@",inde);
            int batteryLevel = [weakSelf backToNavigatorIndex:inde];
            result(@(batteryLevel));
        } else {
            result(FlutterMethodNotImplemented);
        }
    }];
}


- (IBAction)passArgusToFlutter:(id)sender {

    NSLog(@"passArgusToFlutter");
    [batteryChannel invokeMethod:@"passArgusToFlutter" arguments:@[@12,@"huahua"] result:^(id  _Nullable result) {
        NSString *ggg = (NSString *)result;
        NSLog(@"result----:%@",ggg);
    }];
}


- (int)getBatteryLevel {
    NSLog(@"nihao!!!!!");    
    SettingViewController *settingVC = [[SettingViewController alloc]init];
    [flutterVC.navigationController pushViewController:settingVC animated:YES];
    
    return 66;
}


- (int)backToNavigatorIndex:(NSNumber*)index {
    NSLog(@"backToNavigatorIndex!!!!!");
    UIViewController *VC = flutterVC.navigationController.viewControllers[0];
    [flutterVC.navigationController popToViewController:VC animated:YES];
    
    return 33;
}
SettingViewController 没有任何其他代码就是新建一个控制器
2. Flutter端代码

新建一个页面FirstScreen.dartmain.dart改动代码

  1. 导入
import 'dart:ui' as ui;
import 'package:flutter_module/FirstScreen.dart';
  1. 修改
//void main() => runApp(MyApp());
void main() => runApp(_widgetForRoute(ui.window.defaultRouteName));

Widget _widgetForRoute(String route) {
  switch (route) {
    case 'myApp':
      return MyApp();
    default:
      return MaterialApp(
        home: Center(
          child: Text('没找到'),
        ),
      );
  }
}

增加一个函数跳转:FirstScreen.dart

class _MyHomePageState extends State<MyHomePage> {
......
  Future<void> _goOCPage(BuildContext context) async {
    print('我要去Flutter 的下一个页面了');
    Navigator.push(context, MaterialPageRoute(builder: (context){
      return new FirstScreen();
    }));
  }
......
}

在body的{} 中添加一个文本和按钮FlatButton用于跳转到FirstScreen.dart

Text(
              '自我介绍,我是flutter页面',
            ),

            FlatButton(
              child: Text("去下一个Flutter页面"),
              textColor: Colors.blue,
              onPressed: (){
                _goOCPage(context);
              },
            ),

FirstScreen.dart 的全部代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

class FirstScreen extends StatelessWidget {
  static const platform = const MethodChannel('samples.flutter.dev/battery');

  Future<void> _goOCPage() async {
    print('我要去OC 页面了');
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }

    print('调用了$batteryLevel');
  }

  Future<void> _goSomePage() async {
    print('我要去导航的指定页面了');
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('backToNavigatorIndex',[1]);
      batteryLevel = 'backSmoePahe $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to backSmoePahe: '${e.message}'.";
    }

    print('back$batteryLevel');
  }

  @override
    Widget build(BuildContext context) {

      Future<dynamic> _handler(MethodCall methodCall) {
        if ("passArgusToFlutter" == methodCall.method) {
          print('methodCall-arguments:${methodCall.arguments}');
        }
        return Future.value(123);
      }
      platform..setMethodCallHandler(_handler);

      return Scaffold(
      appBar: AppBar(
        title: Text('FirstScreen 页面'),
      ),
      body: Center(
        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '自我介绍,我是flutter页面',
            ),

            FlatButton(
              child: Text("backLastPage"),
              textColor: Colors.blue,
              onPressed: (){
                Navigator.pop(context);
              },
            ),

            FlatButton(
              child: Text("goOCPage"),
              textColor: Colors.blue,
              onPressed: (){
                _goOCPage();
              },
            ),

            FlatButton(
              child: Text("backToSomePage"),
              textColor: Colors.blue,
              onPressed: (){
                _goSomePage();
              },
            ),

          ],
        ),
      ),
    );
  }
}

Xcode 运行项目即可。

使用FlutterEngine的方式请查阅

Flutter基础系列之混合开发(二)  

Q : 如何在原生项目中调试flutter?

A : 首先在命令行启动flutter的监听

flutter attach

如果有多台设备,需要选择一下设备

flutter attach -d 设备标志
参考文章

flutter和原生项目混合开发Flutter基础系列之混合开发(二)