Flutter Module in iOS App
In the previous story, I wrote how to implement a Flutter module into an existing Android App. Today, I’ll mention the implementation of a Flutter module into an iOS App that is generated with Objective-C. And, I’ll invoke native methods on the Flutter screen.
First, I created a Flutter module on the sibling directory with my host app with the following command:
flutter create --template module my_flutter
And then I embedded this module with the Cocoapods dependency manager as recommended way of the official documentation with the following Podfile:
flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')target 'TomorrowsApp'
do
install_all_flutter_pods(flutter_application_path)
end
In my host app, I modified the AppDelegate.h file with importing the Flutter like this:
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>@interface AppDelegate : FlutterAppDelegate <UIApplicationDelegate, FlutterAppLifeCycleProvider>@property (nonatomic,strong) FlutterEngine *flutterEngine;@end
And, modified the AppDelegate.m file to run the Flutter Engine in the `didFinishLaunchingWithOptions` method:
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>// ...- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {self.flutterEngine = [[FlutterEngine alloc] initWithName:@"engine name"];// Runs the default Dart entrypoint with a default Flutter route.
[self.flutterEngine run];// Used to connect plugins (only if you have plugins with iOS platform code).
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
And, I have a button to navigate to the Dart side in my ViewController.m:
- (IBAction)toDartSide:(UIButton *)sender {FlutterEngine *flutterEngine = ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;FlutterViewController *flutterViewController =[[FlutterViewController alloc] initWithEngine:flutterEngine
nibName:nil
bundle:nil];FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"channelName" binaryMessenger:flutterViewController];[channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"flutter gives me:\nmethod=%@ \narguments = %@", call.method, call.arguments);if ([call.method isEqualToString:@"initialMethod"]) {
result(self.yourMessage.text);
} else if ([call.method isEqualToString:@"aNativeMethod"]) {
if (result) {
result(@"This is a message");
}
} else if ([call.method isEqualToString:@"anotherNativeMethod"]) {
NSLog(@"%@",call.arguments);
result(@"Another message");
} else if ([call.method isEqualToString:@"oneMoreNativeMethod"]) {
NSLog(@"%@",call.arguments);
result(@"One more message");
}
}];[self presentViewController:flutterViewController animated:YES completion:nil];
}
Now, I can easily invoke these methods with arguments and handle the native result models from my Flutter screen:
Map<String, String> map = {"title": "This is a parameter from flutter"};
dynamic result = await methodChannel.invokeMethod('aNativeMethod', map);
Special thanks go to CoderXO to help the understanding of the usage of Flutter in Objective-C. You can access the related GitHub repository of mine from here: