Flutter’s MethodChannel to invoke Activity in Android and View Controller in iOS
Published: 2023-06-11 10:59:59

Flutter lets you use Dart’s inbuilt cross-platform standard library for general-purpose programming requirements (i.e., I/O, Math, etc.). It also offers the platform channels API to communicate with platform-specific code to use operating-system-level APIs or invoke code segments written in the native app development language.

**Getting Started**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/12x0igv2aqgqcoq7jtlb.png)

To trigger native screens from the Flutter side, we will create an Activity in Android and a View Controller in iOS. We can achieve this by utilizing the method channel. The process is as follows:

**Android:**

- Create an Activity in Android to represent the native screen.
- Set up the method channel to listen for triggers from Flutter.
- Handle the method call in the method channel's method call handler to launch the native screen.

**iOS:**

- Create a View Controller in iOS to display the native screen.
- Set up the method channel to receive triggers from Flutter.
- Implement the method call handler to present or push the native screen.

By implementing this approach, we can seamlessly trigger the native screens from Flutter using the method channel. It's an exciting and powerful feature that allows seamless integration between Flutter and the native platforms.

**First Code**
 I assume you already own your Flutter SDK, Android SDK, XCode (with iOS SDK absolutely), and integrate it with your IDE. So I start with creating new project like usual, here I use Android Studio as my IDE because Android Studio is my daily weapon as Native Android Engineer, you can use your IDE here. Create your first project, if you don’t know how to do it, please search in google like How to create Flutter project . After that Flutter will generate new code, see the code in lib folder and you can found main.dart as the only one files.
```
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const platform = MethodChannel("com.valar.morghulis");

  _MyHomePageState() {
    platform.setMethodCallHandler(_methodHandler);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'Take me to native screen',
            ),
            MaterialButton(
              child: Text("Navigate"),
              onPressed: _didTapButton,
              color: Colors.grey,
            ),
          ],
        ),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  Future<Null> _didTapButton() async {
    var result = await platform.invokeMethod("method_name");
  }

  Future<dynamic> _methodHandler(MethodCall call) async {
    switch (call.method) {
      case "message":
        debugPrint(call.arguments);
        return new Future.value("");
    }
  }
}
```
This is class will show as our Main Page, there is one button if you click it will trigger the _didTapButton() method. This method will use platform variable, which is the Bridge that use MethodChannel.


## Kotlin Code
To receive triggers from the Flutter side, we need to write code in Kotlin. The first step is to initialize the method channel handler, which will be called from Flutter. Please refer to the code below:

```
class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
                call, result ->
            val intent = Intent(this, SecondActivity::class.java)
            startActivity(intent)
            result.success(true)
        }

    }

    companion object {
        const val CHANNEL = "com.valar.morghulis"
    }
}
```
In the code above, replace channel name(com.valar.morghulis) with the actual name of your method channel. This code sets up the handler to receive method calls from Flutter and allows you to handle them accordingly in Kotlin.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzuzo07r5uiplriahgq8.gif)


## Let's write some code in Xcode
For Swift, we need to set up a method handler to receive triggers from Flutter, similar to what we did in Android.

```
import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
      
      let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

      let methodChannel = FlutterMethodChannel(name: "com.valar.morghulis", binaryMessenger:controller.binaryMessenger)

      methodChannel.setMethodCallHandler({
        (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
              
        if call.method == "method_name" {
            DispatchQueue.main.async {
                let storyboard = UIStoryboard(name: "Main", bundle: nil)
                let vc: CustomViewController = storyboard.instantiateViewController(withIdentifier: "CustonVC") as! CustomViewController
                controller.present(vc, animated: true, completion: nil)
            }
        } else {
          result(FlutterMethodNotImplemented)
          return
        }
      })
      
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
```

## Result

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zka2dxb3knhppnk07w7w.gif)

## Conclusion
We studied the Flutter platform channels API and tested the MethodChannel class with practical examples in this tutorial.  This tutorial focused on calling Kotlin and Swift code from Flutter.

We typically have to call Kotlin code either to reuse it or to call Android SDK functions. If you’ve migrated to Flutter from a native Android app, but you still have a lot of business logic written in a Kotlin/Java package or you need to reuse your Java-based web API’s business logic, you can use MethodChannel for calling your existing Kotlin code efficiently.

We made use of method channel to trigger view controller in ios and Activity in android. I have not convered how to create activity and view controller since it is out of scope.