[Flutter]ネイティブの画面(ViewController)を表示する方法(iOS編)

Flutter

はじめに

Flutterはクロスプラットフォームに対応しているのでモバイル向けのiOS、Androidのアプリを作るのに非常に便利です。

しかし、ネイティブには対応しているけどFlutterには対応していないSDKは多々あります。そこで今回はネイティブ連携のひとつ、Flutterの画面の上にネイティブの画面を表示する方法を紹介しようと思います。

またサンプルをGitHubに公開しているので、参考にしてみてください。

nobushiueshi/flutter_app_native_sample
Contribute to nobushiueshi/flutter_app_native_sample development by creating an account on GitHub.

解説

Flutterと各プラットフォームとの連携はMethodChannelというものを使って実現します。

私が解説するよりも公式のドキュメントのほうがわかりやすく説明してくれてるので是非一読してみてください。

Writing custom platform-specific code
Learn how to write custom platform-specific code in your app.

読むのがめんどくさい人に一言で説明するとMethodChannelというAPIを使ってFlutter側とネイティブ側でメッセージをやりとりしているといった感じです。

環境

  • Flutter 1.22.4
  • Android Studio 4.1.1
  • Xcode 12.2

※Android StudioでFlutterプロジェクトを開発している想定で記述します。

実装方法

Flutter側にMethodChannelを追加

今回はチャンネル名「com.sample.sample/sample」、メソッド名「sample」を使います。

これはネイティブ側でも必ず合わせる必要があります。

MethodChannel _channel = const MethodChannel('com.sample.sample/sample');

Future _launchNativeScreen() async {
  await _channel.invokeMethod('sample');
}

Xcodeで開く

次にAndroid StudioからXcodeを開きます。Android Studioのままでもコードは書けるのですが、コード補完等が効かないですし、ViewControllerの追加等も多少手間なのでここからはXcodeを使います。

開き方は簡単です。iosフォルダ右クリックして[Flutter]→[Open iOS module in Xcode]をクリックするだけです。

Swiftファイルを追加

まずは追加するViewControllerのSwiftファイルを追加します。Xcodeプロジェクト配下のRunnerフォルダ内で右クリック→[New File…]を選択

Cocoa Touch Classを選択して[Next]

以下の設定で[Next]

  • Class : SampleViewController (任意の名前でOK)
  • Subclass of : UIViewController
  • Also create XIB file : チェックなし
  • Language : Swift

保存するパスを聞かれるのでプロジェクト配下のios/Funnterフォルダを選択して[Create]

するとプロジェクトに先程指定したSampleViewController.swiftが無事作成されます

画面の作成とSwiftコードとの紐付け

Main.storyboardを選択すると、デフォルトの画面サイズをを聞かれるのでお好きな解像度を選択してください。

次にXcode画面の右上にある[+]を押すと以下のようなダイアログが出てくるのでViewControllerを、さきほど開いたMain.storyboardの画面上ドラッグ・アンド・ドロップしてください。

上手くいくと以下のようになります。

さきほど追加したViewControllerを選択して[Custom Class]と[Storyboard ID]に「SampleViewController」を設定します。

※ViewControllerを選択するには下記画像の赤枠に囲まれた部分を選択してください。

次に[Presentation]を「Full Screen」に設定します。この設定をしないと全画面表示ではなくモーダル表示されてしまいます。

これだけだと分かりづらいのLabelButtonをさきほど同じ要領で今度は追加したViewControllerにドラッグ・アンド・ドロップします。

さらにこのままだとViewControllerが開いた後、画面を閉じる術がないのでボタンをタップしたときの処理を追加します。

下記画面のように左側にMain.storyboard、右側に紐付けされているSampleViewController.swiftを開きます。そして、Buttonから右クリックでSampleViewControllerの空いている部分にドラッグ・アンド・ドロップします。

すると下記のようなダイアログが出るのでName(メソッド名)を「onClickedButton(任意)」に設定します。

すると自動的にメソッドが追加されます。

Native側にMethodChannelを追加

Flutter側で設定したチャンネル名とメソッド名を使ってMethodChannelに登録します。

またViewController呼び出し時にStoryboard IDで設定した名前を使います。

AppDelegate.swift

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    setiOSChannel();
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  func setiOSChannel() {
    let controller : FlutterViewController = self.window?.rootViewController as! FlutterViewController
    let channel = FlutterMethodChannel.init(name: "com.sample.sample/sample", binaryMessenger: controller.binaryMessenger)
    channel.setMethodCallHandler({
        (call, result) -> Void in
        if call.method == "sample" {
            let nextController = controller.storyboard?.instantiateViewController(withIdentifier: "SampleViewController")
            controller.present(nextController!, animated: true, completion: nil)
        }
    })
  }

}

ViewControllerを閉じる処理を追加

先程追加したonClickedButtonにViewControllerを閉じる処理を追加します。

SampleViewController.swift

import UIKit

class SampleViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    @IBAction func onClickedButton(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }

}

これで完成です!

結果

無事表示されました。

さいごに

Unityとかと比べたらデバッグがしやすいのでめちゃめちゃ連携が簡単でした!

控えめに言って最高です。

来週はAndroidのActivityを表示する方法を書こうと思います。

おすすめ参考書

コメント

  1. gas より:

    初っ端「Flutter側にMethodChannelを追加」をどのファイルに編集するのかわからないので、
    それ以上読み進む記事ではないと思いました。

    • nobushiueshi nobushiueshi より:

      結論からいうと自分の好きなファイルで問題ありません。

      MethodChannelというクラスを通して、ネイティブ側(SwiftやKotlin)とやりとりをしています。
      なのでMethodChannelをローカル変数にして毎回処理しても良いですし、staticにしていつでも呼び出せるようにしても良いです。

タイトルとURLをコピーしました