- First, create the Flutter module;
- Add Flutter module dependencies to existing iOS applications;
- Call Flutter module in Object-c;
- Write Dart code;
- Run the project;
- Hot restart/reload;
- Debugging Dart code;
- publish applications;
- flutter_hybrid - flutter_module - FlutterHybridAndroid - FlutterHybridiOS
Below flutter_hybrid are the flutter module, the native Android module, and the native iOS module, and these three modules are in parallel structure.
1. Create Flutter module
Before doing hybrid development, we first need to create a Flutter module.
If your Native project looks like this: xxx/flutter_hybrid/FlutterHybridiOS
:
$ cd xxx/flutter_hybrid/ $ flutter create -t module flutter_module
The above code will switch to the upper-level directory of your iOS project and create a flutter module:
//flutter_module/ .android .gitignore .idea .ios .metadata .packages build flutter_module_android.iml flutter_module.iml lib pubspec.lock pubspec.yaml README.md test
The above is the file structure in flutter_module
. You will find that it contains .android
and .ios
. These two folders are hidden files. This is also the flutter_module
host project:
.android
– Android host project offlutter_module
;.ios
– iOS host project offlutter_module
;lib
– The code for the Dart part offlutter_module
;pubspec.yaml
–flutter_module
‘s project dependency configuration file;
Because of the existence of the host project, our
flutter_module
can run independently without additional configuration. Open thisflutter_module
through AndroidStudio with Flutter and Dart plug-ins installed. Project, you can run it directly through the run button.
2. Add Flutter module dependencies to existing iOS applications
Next we need to configure the Flutter module dependencies of our iOS project. The next configuration requires CocoaPods. If you have not used CocoaPods yet, you can refer to the instructions above on CocoaPods.org to install CocoaPods.
2.1 Add flutter
dependencies in the Podfile
file
If there is no Podfile
file in your iOS project, you can pass:
pod init
Initialize one.
Next add the script:
Check your Flutter version through the flutter doctor
command. Different Flutter versions require different configurations:
The following is the configuration added by Flutter >= v1.10.14 version:
-Flutter >= v1.10.14 version configuration START-
# Step1 flutter_application_path = 'path/to/my_flutter/' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') #Step2 install_all_flutter_pods(flutter_application_path)
For example:
Below is the reference configuration from the Podfile:
# Step1: Add flutter_application_path = '../flutter_module/' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'FlutterHybridiOS' do # Step2 Add install_all_flutter_pods(flutter_application_path) target 'FlutterHybridiOSTests' do inherit! :search_paths # Pods for testing end target 'FlutterHybridiOSUITests' do inherit! :search_paths # Pods for testing end end
-Flutter >= v1.10.14 version configurationEND-
Configurations that need to be added in the old version of Flutter:
-Old version of Flutter configuration START-
flutter_application_path = 'path/to/my_flutter/' eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
For example:
target 'FlutterHybridiOS' do flutter_application_path = '../flutter_module/' eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding) target 'FlutterHybridiOSTests' do inherit! :search_paths end target 'FlutterHybridiOSUITests' do inherit! :search_paths end end
In addition, the old version of flutter also needs to add a build phase to build Dart code
Create a build phase
according to the prompts in the picture above, then expand Run Script
and add the following configuration:
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
Finally, remember to follow the prompts in the picture above and place Run Script
next toTarget Dependencies phase
, and then you can pass ?B
Build your project.
-Old version Flutter configurationEND-
2.2 Installation dependencies
Run in the root directory of your iOS project:
pod install
you will see:
pod install Analyzing dependencies Fetching podspec for `Flutter` from `../flutter_module/.ios/Flutter/engine` Fetching podspec for `FlutterPluginRegistrant` from `../flutter_module/.ios/Flutter/FlutterPluginRegistrant` Downloading dependencies Installing Flutter (1.0.0) Installing FlutterPluginRegistrant (0.0.1) Generating Pods project Integrating client project [!] Please close any current Xcode sessions and use `FlutterHybridiOS.xcworkspace` for this project from now on. Sending stats Pod installation complete! There are 2 dependencies from the Podfile and 2 total pods installed. [!] Automatically assigning platform `ios` with version `12.1` on target `FlutterHybridiOS` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/ podfile.html#platform`.
When you add a Flutter plug-in in flutter_module/pubspec.yaml
, you need to run it in the flutter_module
directory:
flutter packages get
To refresh the plugin list in the podhelper.rb
script, then run it in the iOS directory:
pod install
In this way, the podhelper.rb
script can ensure that your plug-in and Flutter.framework can be added to your iOS project.
2.3 Disable Bitcode
Currently, Flutter does not support Bitcode, so iOS projects that integrate Flutter need to disable Bitcode:
Open your project with XCode such as: xxx.xcworkspace
:
Then in:
Build Settings->Build Options->Enable Bitcode
Disable Bitcode in:
3. Call Flutter module in Object-c
At this point, we have added the necessary dependencies for Flutter to our iOS project. Next, let’s look at how to call the Flutter module in Object-c:
There are two ways to call Flutter module in Object-c:
- Directly use
FlutterViewController
; - Using
FlutterEngine
;
3.1 Directly using FlutterViewController
// ?flutter_hybrid? ?FlutterHybridiOS? ?FlutterHybridiOS? ?ViewController.m
#import
#import “AppDelegate.h”
#import “ViewController.h”
#import
FlutterViewController *flutterViewController = [FlutterViewController new]; GeneratedPluginRegistrant.register(with: flutterViewController);//If you need to use the Flutter plug-in [flutterViewController setInitialRoute:@”route1″];
[self presentViewController:flutterViewController animated:true completion:nil];
In this way we can use the flutterViewController setInitialRoute
method to pass the string “route1” to tell the Dart code which widget to display in the Flutter view. The lib/main.dart
file of the Flutter module project needs to obtain the route name specified by Native to be displayed through window.defaultRouteName
to determine which widget to create and pass it to runApp:
import 'dart:ui'; import 'package:flutter/material.dart'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'route1': return SomeWidget(...); case 'route2': return SomeOtherWidget(...); default: return Center( child: Text('Unknown route: $route', textDirection: TextDirection.ltr), ); } }
3.2 How to use FlutterEngine
AppDelegate.h
#import <UIKit/UIKit.h> #import <Flutter/Flutter.h> @interface AppDelegate : FlutterAppDelegate @property (nonatomic,strong) FlutterEngine *flutterEngine; @end
AppDelegate.m
#import
@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]; }
@end
If your project’s AppDelegate.h already has other integrations, you can refer to the method of implementing FlutterAppLifeCycleProvider for configuration.
ViewController.m
// ?flutter_hybrid? ?FlutterHybridiOS? ?FlutterHybridiOS? ?ViewController.m FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine]; FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil]; [self presentViewController:flutterViewController animated:false completion:nil];
Because we initialized
FlutterEngine
in AppDelegate.m in advance, opening a Flutter module in this way is faster than the first way.
3.3 Pass data when calling Flutter module
In the above, whether we use FlutterViewController
directly or FlutterEngine
, we are allowed to pass a String type initialRoute when loading the Flutter module.
Parameter, from the parameter name, it is used as the route name, but since Flutter has opened this hole for us, can we do something and pass other parameters we want to pass, such as:
[flutterViewController setInitialRoute:@"{name:'devio',dataList:['aa','bb',''cc]}"];
Then get it in the Flutter module as follows:
import 'dart:ui';//To use the window object, it must be imported String initParams=window.defaultRouteName; //Serialize into Dart obj, you can do whatever you want ...
Through the explanation of the above scheme, have you shared a new idea with everyone?
Note that calling
setInitialRoute
when usingFlutterEngine
will be invalid. You will find that Dart always gets “/”. This is a bug of Flutter SDK, so if you must rely onsetInitialRoute
Then please use method 1;
4. Write Dart code
The next step is to write Dart under the lib in the Flutter module. Go to Enjoy Coding
! ! !
5. Run the project
Next, we can run it. After the above steps, we can run an iOS project integrated with Flutter through XCode in the same way as a normal iOS project.
6. Hot restart/reload
Everyone knows that when we are doing Flutter development, it has a hot restart/reload function, but you may find that when the Flutter project is integrated into the iOS project during hybrid development, Flutter’s hot restart/reload function seems to be invalid. , then how to enable hot restart/reloading of Flutter for hybrid development:
- Open an emulator or connect a device to your computer;
- Close our APP, and then run
flutter attach
;
$ cd flutter_hybrid/flutter_module $ flutter attach Checking for advertised Dart observatories... Waiting for a connection from Flutter on iPhone X...
Note that if you have multiple emulators or connected devices at the same time, running
flutter attach
will prompt you to select a device:
Android SDK built for x86 ? emulator-5554 ? android-x86 ? Android 8.1.0 (API 27) (emulator) iPhone X ? 3E3FA943-715F-482F-B003-D46F5902C56C ? ios ? iOS 12.1 (simulator)
Next we need flutter attach -d
to specify a device:
flutter attach -d 'emulator-5554'
Note the device ID following -d
.
Run the APP and you will see:
$ flutter attach More than one device connected; please specify a device with the ‘-d
It means that the connection is successful. You can then use the above prompts to perform hot reloading/hot restarting. Enter in the terminal:
- r: hot loading;
- R: hot restart;
- h: Get help;
- d: disconnect;
7. Debugging Dart code
How can we debug our code better and more efficiently under the hybrid development mode? Next, I will share with you a way to debug the code efficiently under the hybrid development mode:
- Close APP (This step is very important)
- Click the
Flutter Attach
button of AndroidStudio (you need to install the Flutter and Dart plug-ins first) - Start APP
Next, you can debug the Dart code in the hybrid development mode just like debugging a normal Flutter project.
Except for the differences in the above steps, the following debugging is common to the Flutter debugging skills in our previous courses. Students who need it can learn from our previous courses;
One more thing to note:
Everyone must use XCode when running iOS projects, because AndroidStudio in Flutter mode runs the iOS project in
.ios
under the Flutter module.
8. Publish application
To publish an iOS app, we need a $99 account to upload the app to the AppStore, or a $299 enterprise-level account to publish the app to our own company’s server or a third-party company’s server.
Next, we need to apply for an APPID, create an application in Tunes Connect, package the program, and submit the application to the app store.