Flutter hybrid development: a detailed guide to integrating flutter modules in iOS projects

This article starts with WeChat public's "Android development tour". Welcome to pay more attention to get more dry goods.


The previous article explained how Android native project integrates with Flutter project, Flutter hybrid development (I): detailed guide to integrating flutter module in Android project , this article will take you to learn how to integrate Flutter with native iOS projects.

Because the integration logic of each version is different, here is the integration version of the next article:

Flutter (channel dev,v1.10.16)
dart (v2.7.0)
Xcode (v11.2)
cocoapds (1.8.4)

Create a fluent module

If the path of iOS Project is as follows: flitter / flitter  hybrid / iOS Project, then we need to create the flitter module in flitter  hybrid, the directory on the upper layer of iOS Project.

cd flutter/flutter_hybrid/

flutter create -t module flutter_module

After input, the console will print as follows:

$ flutter create -t module flutter_module
Creating project flutter_module...
  flutter_module/test/widget_test.dart (created)
  flutter_module/flutter_module.iml (created)
  flutter_module/.gitignore (created)
  flutter_module/.metadata (created)
  flutter_module/pubspec.yaml (created)
  flutter_module/README.md (created)
  flutter_module/lib/main.dart (created)
  flutter_module/flutter_module_android.iml (created)
  flutter_module/.idea/libraries/Flutter_for_Android.xml (created)
  flutter_module/.idea/libraries/Dart_SDK.xml (created)
  flutter_module/.idea/modules.xml (created)
  flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module...                      1.2s
Wrote 12 files.

All done!
Your module code is in flutter_module/lib/main.dart.

Seeing All done means that our project has been created. The whole module directory is basically the same as the native Flutter, mainly including Android, iOS hosting project, lib directory and pubspec.yaml file.

Add the Flutter module dependency

To add dependencies for iOS projects, you need to use CocoaPods. If you haven't used CocoaPods, please refer to https://cocoapods.org/ Follow the instructions above to install CocoaPods.

If your project has not used cocoapods before, you need to initialize to generate a podfile file and enter the root directory of the iOS project to execute:

pod init

Then open the podfile file to configure:

# To configure
flutter_application_path = '../flutter_module/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'iOSFlutterHybrid' do
  # Comment the next line if you don't want to use dynamic frameworks

  # Pods for iOSFlutterHybrid
  # To configure

  target 'iOSFlutterHybridTests' do
    inherit! :search_paths
    # Pods for testing

  target 'iOSFlutterHybridUITests' do
    # Pods for testing

After the configuration is added, run the following command in the project root directory to install:

pod install

Console output:

Analyzing dependencies
Downloading dependencies
Installing Flutter (1.0.0)
Installing FlutterPluginRegistrant (0.0.1)
Installing flutter_module (0.0.1)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `iOSFlutterHybrid.xcworkspace` for this project from now on.
Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.

[!] Automatically assigning platform `iOS` with version `13.2` on target `iOSFlutterHybrid` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

Here we see three dependencies installed. And remind us to close the current project and use iOSFlutterHybrid.xcworkspace under the root directory to open the running project. Many people may find that there are 0 dependencies to complete when executing the command. There may be a problem with your Xcode version. Because the minimum required version of Flutter is 10.2 and above.

When you add a Flutter plug-in in the flitter module / pubspec.yaml, you need to run it in the flitter module Directory:

flutter packages get

To refresh the list of plug-ins in the podhelper.rb script, and then run it in the iOS Directory:

pod install

In this way, the podhelper.rb script can ensure that the added plug-ins and Flutter.framework can be added to the iOS project.

At present, Bitcode is not supported by Flutter, so Bitcode needs to be disabled for iOS projects integrated with Flutter.

Locate and disable Bitcode at:

Build Settings->Build Options->Enable Bitcode 

Previous versions of flutter needed to add build phase to build Dart code, but the latest version doesn't need to be added, and can be built automatically.

Call fluent module

Flutter provides us with two call modes: FlutterViewController and FlutterEngine. When using FlutterEngine, there will be some problems, which will be explained in the following.

Fluterviewcontroller mode:

We open the ViewController.m file, add a method to load the flitter page and add a button to call:

#import "ViewController.h"
#import <Flutter/Flutter.h>
#import "AppDelegate.h"

@interface ViewController ()


@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self action:@selector(handleButtonAction) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Load Flutter" forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor blueColor]];
    button.frame = CGRectMake(100, 100, 160, 60);
    [self.view addSubview:button];

- (void)handleButtonAction{
    FlutterViewController *flutterViewController =[FlutterViewController new];
    //Set route parameters
    [flutterViewController setInitialRoute:@"route2"];
    [self presentViewController:flutterViewController animated:false completion:nil];


When we run the project and click the load fluettr button, the Flutter page will be called. As with Android project integration, setInitialRoute here can set a json array to pass the parameters that need to be interacted. And use window.defaultRouteName in the fluent to get the passed parameters.

Fluterengine mode:

We need to initialize the fluterengine in AppDelegate. To open the AppDelegate.h file:

#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>

@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,strong) FlutterEngine *flutterEngine;

To open the AppDelegate.m file:

// If you need to use the Flutter plug-in
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> 
#include "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
  [self.flutterEngine runWithEntrypoint:nil];
  [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine]; //If you need to use the Flutter plug-in
  return [super application:application didFinishLaunchingWithOptions:launchOptions];

It is then invoked in the handleButtonAction defined in the ViewController.m file:

- (void)handleButtonAction{
    FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
    FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
    [flutterViewController setInitialRoute:@"route2"];
    [self presentViewController:flutterViewController animated:false completion:nil];

When we run the project and click the load shuttle button, the shuttle page will be called. As mentioned earlier, there will be problems when using the fluterengine, that is, the parameters passed by our setInitialRoute will always get "/" in the flitter. This is a Bug of the flitter SDK, so if you have to rely on the setInitialRoute, or use the form of the fluterviewcontroller to load the flitter module.

Hot restart / reload

When you write a pure Flutter application, you know that there is a hot restart / reload function, but in the process of mixed development, you will find that the hot restart / reload function fails. So how to turn on hot restart / reload in hybrid development?

  • First access our device or simulator
  • Close our App, exit the background, and run the fluent attach command in terminal
$ flutter attach
Waiting for a connection from Flutter on Android SDK built for x86...

The copy code is now waiting for the device to connect. Note here that if the computer is connected to multiple devices, you need to use the - d command to specify a device, and the parameter is the device id.

flutter attach -d 'Your equipment id'

Then launch our application and you will see the console output:

Syncing files to device Android SDK built for x86...             1,393ms

🔥  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on Android SDK built for x86 is available at:
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".

This means that we have successfully connected. The output log also tells us how to use the hot restart / reload function.

Enter the following command in Terminal:

r: hot load;
R: Hot restart;
h: get help;
d: disconnect;
q: exit;

The d and q commands here have exit debugging. The difference is that the d command simply disconnects and the q command will exit the application to the background.

Debug Dart code

How do we debug dart code in the process of mixed development?

  • Close our app
  • Click the shuttle attach button on the Android Studio toolbar (you need to install the shuttle and Dart plug-ins)

  • Launch our app

Next, you can debug Dart code in mixed development mode just like you can debug a normal Flutter project.


This article mainly explains the steps of iOS integrating the Flutter project, and some problems are encountered. Due to my lower Xcode version, the dependency of iOS project has failed in the process of integration. Finally, it was found that there was a version problem with Xcode. It takes a lot of time to troubleshoot the problem, so there are problems in the process of integration, you can pay attention to the public number plus my WeChat, give me a message, I will help you solve the problem.

All Demo source code has been uploaded to the backstage, focusing on the public reply to "hybrid development" to get download links.

If you think the article is not bad, please like it and share it with me. Your affirmation is my greatest encouragement and support.

Recommended reading

Dart Foundation: dart quick start

Flutter hybrid development (I): detailed guide to integrating flutter module in Android project

Scan below the two-dimensional code to pay attention to the public number and get more dry goods.

Tags: iOS Android xcode xml

Posted on Tue, 12 Nov 2019 08:10:26 -0500 by ToddAtWSU