How to call a swift view controller using the navigation controller in flutter through the Flutter Method Channel

Viewed 1723

I am trying to call a UINavigationController I have defined in a separate file called "MainNavigationController.swift" through a private function I have defined in my AppDelegate.swift file called "callNavigator()" I am calling that method from the Flutter side through a method channel that is successfully sending back a message that some communication is happening "There is no problem on the Flutter/Dart side". I want the function to push a view on top of the flutter screen using the navigator defined in "MainNavigationController.swift".The code in my MainNavigationController.swift is as follows:

import Foundation
    import UIKit

    class MainNavigationController: UINavigationController{
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        private func navigateToMainInterface() {
            let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
           guard let mainNavigationVc = mainStoryboard.instantiateViewController(withIdentifier:"MainNavigationController") as? MainNavigationController else {
                return

            }
            present(mainNavigationVc, animated: true, completion: nil)

        }
    }
Then I am trying to call this class in my "AppDelegate.swift file" through my "callNavigator()" private function as a constructor. The code is as follows in the Appdelegate.swift file :


    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?

      ) -> Bool {
        let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
        GeneratedPluginRegistrant.register(with: self)      

        let navigatorChannel = FlutterMethodChannel(name: "com.fluttertonative/navigateToCameraSDK", binaryMessenger:  controller.binaryMessenger)
       navigatorChannel.setMethodCallHandler ({
          [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
          // Note: this method is invoked on the UI thread.
          guard call.method == "getSwiftNavigator" else {
            result(FlutterMethodNotImplemented)
            return
          }
          self?.callNavigator()

       })
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
        private func receiveGreeting(result: FlutterResult){
            result("Hello from Swift Code...")
        }
        private func callNavigator(){
            MainNavigationController()

        }
    }

However, I am getting a warning in Xcode that the "callNavigator" function trying to call "MainNavigationController" is not using its result it's saying "Result of 'UINavigationController' initializer is unused". I am new to swift and I am not sure what to do.

I have set the Initial navigator to the FlutterViewController in my Main.storyBoard where I have placed some dummy text filed. I want when I call the method channel from the Flutter side the "callNavigator" function to be run which in turn calls the " MainNavigationController" in the " MainNavigationController.swift" file, which should push a new view on top of the view in the Flutter screen.

I need some help achieving this as I am new to the Swift Language

then my dart code is as follows:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const navigateToCameraSDK = const MethodChannel('com.fluttertonative/navigateToCameraSDK');

  String _greeting = 'awaiting swift call..';


  Future _getnavigator() async{
    try {
      final result = navigateToCameraSDK.invokeMapMethod('getSwiftNavigator');
      print(result);
    } on PlatformException catch (e){
      print('error:$e');
      _greeting = 'error occured:$e';
    }
    setState(() {
      _greeting ='call successful you have got the swift Navigator';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Text(_greeting),
              CupertinoButton(
                child: Text('call swift to get the navigator'),
                onPressed: _getnavigator,
                borderRadius:BorderRadius.all(Radius.circular(13.0)),
                color: Colors.blue[300],
              ),
            ],
          ),
        ));
  }
}

and my storyboard is as follows-the Flutter View Controller is the initial View Controller. enter image description here: enter image description here

1 Answers

By default, the Flutter iOS application does not have a UINavigationViewController. This is required in order to push view controllers on to the navigation stack.

It's quite easy to add this through the AppDelegate class though.


import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    
    var navigationController: UINavigationController!
    
    override func application(_ application: UIApplication,
                            didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
      
      
        let controller = window?.rootViewController as! FlutterViewController
        GeneratedPluginRegistrant.register(with: self)
        
        // create and then add a new UINavigationController
        self.navigationController = UINavigationController(rootViewController: controller)
        self.window.rootViewController = self.navigationController
        self.navigationController.setNavigationBarHidden(true, animated: false)
        self.window.makeKeyAndVisible()
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

}

Later on when you add a FlutterMethodChannel to your app delegate, you can simple push/show a new UIViewController in the standard iOS way.

    // called from within the FlutterMethodChannel handler
    private func pushViewController() {
        //get view controller from StoryBoard, XIB or in code
        let vc = ...       
        self.navigationController.setNavigationBarHidden(false, animated: true)
        self.navigationController.pushViewController(vc, animated: true)
    }
Related