はじめに
Flutterはクロスプラットフォームに対応しているのでモバイル向けのiOS、Androidのアプリを作るのに非常に便利です。
しかし、ネイティブには対応しているけどFlutterには対応していないSDKは多々あります。そこで今回はネイティブ連携のひとつ、Flutterの画面の上にネイティブの画面を表示する方法を紹介しようと思います。
またサンプルをGitHubに公開しているので、参考にしてみてください。
解説
Flutterと各プラットフォームとの連携はMethodChannelというものを使って実現します。
私が解説するよりも公式のドキュメントのほうがわかりやすく説明してくれてるので是非一読してみてください。
読むのがめんどくさい人に一言で説明すると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」に設定します。この設定をしないと全画面表示ではなくモーダル表示されてしまいます。
これだけだと分かりづらいのLabelとButtonをさきほど同じ要領で今度は追加した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を表示する方法を書こうと思います。
コメント
初っ端「Flutter側にMethodChannelを追加」をどのファイルに編集するのかわからないので、
それ以上読み進む記事ではないと思いました。
結論からいうと自分の好きなファイルで問題ありません。
MethodChannelというクラスを通して、ネイティブ側(SwiftやKotlin)とやりとりをしています。
なのでMethodChannelをローカル変数にして毎回処理しても良いですし、staticにしていつでも呼び出せるようにしても良いです。