Development

Flutterエンジニアがネイティブ学習で困ったこととその乗り越え方

1. はじめに

Flutterを使ったモバイルアプリ開発は、UIをコードで柔軟かつ効率的に構築できる点が魅力です。筆者もFlutterを入り口にモバイル開発を学び、Widgetの考え方やDartのシンプルな言語仕様に慣れたことで、快適にアプリ開発を進めてきました。

しかし、ネイティブアプリ開発に初めて関わった際、これまでの経験が思った以上に通用しないことに直面しました。。
AndroidでUIをXMLファイルによって設計する方法や、iOSのStoryboardの操作、さらにはKotlinやSwiftといった言語の違いなど、すべてが新鮮で同時に大きな課題となりました。

この記事では、ネイティブを学習する際に筆者が抱えた課題の中から、4つのテーマを深掘りし、初心者が躓きがちなポイントを整理しました。

2. UIの構築: レイアウトはどこで作る?

Flutterでは、Widgetを使い、コードで簡単にUI構築ができますが、筆者が関わることになったネイティブアプリではXML・Storyboardを使用しており、そのどちらも馴染みがなく混乱しました。

最近のネイティブアプリではJetpackComposeや、SwiftUIが使われていることも多いようですが、筆者が関わったプロジェクトでは既存の形式に従う必要があり、これら最新技術を活用することは難しい状況でした。

そもそも、レイアウトファイルとソースコードが分離している仕組み自体が馴染みがなかったため、「この画面はどこにあるんだ、、?」と困惑する場面が多々ありました。

まずは概念を知る

  • Androidでは、XMLファイルでレイアウトを作成し、そこで定義したUIのIDをネイティブコードから呼び出して処理などを実装する。
  • iOSではStoryboardを利用してレイアウトを作成し、それをSwiftコードとツール上で紐付けて処理を実装する。
これらの基本的な概念を理解するだけで、コードの解読は大幅に楽になりました。次の課題は実際にUIを作成してみることです。

UIを作ろう

Android
XMLファイルはコードベースで記述した内容がレイアウトのプレビューに即時反映されるので、かなり取っ付きやすかったです。
例えば、UIのサイズや余白等も、XMLのコード内に直接記述できるので、どの部分を編集すればどこが変わるのかが一目で分かりやすい点が良かったです。

また、UIの構造はFlutterのツリー構造に似ているため、比較的早く馴染むことができました。特に「ConstraintLayout」を使用すると、UI同士の配置関係がコードで簡単に記述できるため、単純な要素から始めて最終的に1画面を完成させる流れで学習を進めることができました。

慣れないと感じたポイントのひとつは、枠線や角丸をつける際に背景ファイルを別途作成して適用する必要がある点です。
Flutterでは、例えばContainerに枠線をつける場合、次のように簡単に記述できます。

decoration: BoxDecoration(border: Border.all(color: Colors.grey))
しかし、XMLの場合は、枠線を付けるために別途XMLファイルを作成し、その中で枠線や背景色を指定してUIに適用する必要があります。このやり方ではファイル数が増えたり、「このファイルは何のために存在しているのか」がわからなくなることもあり、注意が必要でした。

iOS
StoryboardとAuto Layoutについては、現在もまだ馴染めていない状態です。

Storyboardはツール上で直感的にレイアウト作成・操作でき、Auto Layoutを使うことでレスポンシブな対応が可能になる便利な機能ではあります。しかし、ツールの操作性には一癖も二癖もあり、慣れるには時間がかかりそうです。

UIKitでソースコード側からレイアウトを操作する方法もありますが、筆者が関わることになったプロジェクトではStoryboardで全てのレイアウトを指定するという方針でした。

画面を1から作成する場合はそこまで難しくはないと思うのですが、既存画面を編集する際には問題が発生しがちです。
例えば、Auto Layoutが崩れてしまうと、Storyboard全体に様々なエラーが発生してしまうので、ボタン1つ移動するだけでも慎重な操作が必要でした。
これはまだ完全に解消できておらず、改善が必要だと感じています。

StoryboardとAuto Layoutについては、概念を理解したことで少しずつ扱えるようにはなったものの、最終的には「とにかく触って慣れるしかない」というのが現状の率直な感想です。ツールの使い方については動画コンテンツやチュートリアルを参考にしながら、地道に学んでいく必要があると感じています。

3. タップイベントの実装: タップしたいだけなのに

Flutterでは、ボタンにタップイベントを実装したければ、「onPressed」に処理を記述すればよく、画像やテキストなどのボタン以外のUIに対しては「GestureDetector」でタップ処理を付与することができます。これにより、非常にシンプルな実装が可能でした。しかし、ネイティブではレイアウトとロジックが完全に分離しているので、最初はその仕組みが複雑に感じられました。

タップイベントを実装しよう

Android
Androidでは、タップを検知したら何をする?というのを最初に全て定義する必要があります。
ネイティブのソースコード側で、XMLに定義したUIコンポーネントの名前を呼び出し、「OnClickListener」でそのコンポーネントがタップされたらこの処理を実行する というコードを書いてあげる必要があります。

Flutterでは、レイアウトも処理もWidget内に並べて書くので、「このコンポーネントはこんなデザインで、こんな処理がある」というのが一目で分かるようになっています。そのため、レイアウトと処理が分離しているのは新鮮でした。
ですが、「setOnClickListener」と書かれている部分を見れば、一目で「タップ処理を付けている」ということが理解できる仕組みになっており、構造を把握して慣れてくると、読みやすさを感じる場面も多くなりました。
UIとロジックが分離しているネイティブのアプローチは、処理分担が明確になるというメリットもあると思います。

iOS
iOSでは、Storyboardとロジック(ViewController)の紐付けを直感的に行うことができ、自分にとってはかなりやりやすいと感じました。

具体的には、Storyboardでボタンなどイベントを付与したいUI要素を作成した後、ViewControllerで「@IBAction」を利用してドラッグで紐付けるだけで簡単にアクションを付与できます。
さらに、ViewControllerのコード側から「どのUIコンポーネントと繋がっているか」を確認することが簡単に行えるだけでなく、その逆(Storyboard側からViewController)も分かりやすい仕組みになっています。これにより、レイアウトとロジックが分離されていても、その関連性を視覚的に確認できるため、初学者でも操作しやすくなっている点がありがたいと感じました。

4. エディタの使い方: Xcodeが使えない

見出しの通りですが、Flutterの開発ではAndroid Studioを使用していたので、Xcodeをほとんど使用したことがなく、エディタの操作に慣れることに時間がかかりました。(Xcodeを使用するのは、証明書適用のときくらいでした、、)
エディタの使い方に関しては慣れるしかなかったのですが、Android StudioのショートカットとXcodeのショートカットを比較していただいているページなどを参考にしたりして、少しずつ慣れていきました。

XcodeとAndroid Studioのショートカットキー比較(Mac)

チームメンバーもXcodeはあまり使ったことがないという人が多かったので、互いに使い方を共有しながら慣れていきました。

余談ですが、Xcodeでネイティブアプリをビルドすると、爆速でビルドが完了したので驚きました。(FlutterでiOSビルドすると5分10分かかることもざら)

5. 言語の違い: Dart vs Java/Kotlin/Swift

Flutterで使われているDart言語は、JavaやJavaScriptを元に作られたシンプルな構文が特徴です。そのため、プログラミング言語を少しでも触れたことがある人なら、比較的学習コストは低く、スムーズに習得できると思います。筆者もDartにはすぐ慣れ、Flutterでのアプリ開発を問題なく進めることができました。

しかし、ネイティブアプリ開発では、Dart以外の言語、例えばJavaやKotlin(Android)、Swift(iOS)と向き合う必要が出てきます。Dartの経験を活かしてJavaコードを読むことはできましたが、特に記述が長く複雑に感じる部分があり、作業効率が低下しているように思いました。一方で、KotlinやSwiftはそもそも見慣れない構文が多く、習得に時間がかかりました。

KotlinとSwiftが読めない

本当に初歩的なところですが、まずは定数宣言の記述に戸惑いました。Kotlinでは定数を「val」、Swiftでは「let」で定義しますが、この時点で書き方がDartと異なることに気付き、「もう全然違う世界に来たな…」という感覚を覚えました。

学習の方針としては、とにかく「Dartと比較して覚えていく」という手法を取りました。
KotlinやSwiftといった未知の言語を一から習得するよりは、読み慣れているDartと比較して、その都度覚えていくのがよいのでは?と考え、「Swiftのこの記法はDartで書くとどう書くんだろう」「Dartで書いた処理をKotlinで書くならどうなるんだろう」というように比較する手法で学習していきました。

初めは全く読めなかったKotlin/Swiftも、Dartと比較してみれば「なんだこんなもんか」と簡単に感じることができるようになり、次第にKotlin/Swift単体でも読めるようになっていきました。

パッケージ使わないんですか

Flutterでは、困ったらパッケージを探して、それを組み込むことを前提にアプリを作っていました。デバイス機能との連携も、パッケージにいろいろとお任せして、自分ではあまりコードを書かずに実装できるというのが便利でした。(それゆえにネイティブの知識も薄かった)

それに対し、KotlinやSwiftでは、標準ライブラリが豊富で、基本的なUIや機能の実装であれば外部パッケージを必要としない場面が多いことに驚きました。
Flutterではパッケージを積極的に活用することで、複雑な実装を簡潔にコーディングできますが、パッケージのメンテナンスに左右されることも多く、パッケージの選定には慎重になる必要がありました。
しかし、KotlinやSwiftでは標準ライブラリが非常に充実しているため、こうした「他者が作ったコードに依存する」という前提が少ないことに気付きました。

ネイティブではデバイス機能の連携やカスタマイズも、標準的なAPIを使って自分でコーディングすることが基本であり、それが学びの深さに繋がっているように感じます。結果として、ネイティブ開発では「仕組みを理解しながらコードを書いていく」というプロセスを自然と踏むことが多く、Flutterで感じていた「便利さ」とは異なる学びの楽しさがあるように思いました。

6. おわりに

Flutterとネイティブ開発の違いを実際に体験することで、新しい視点を得ることができました。
Flutterの便利さや効率性は、スピード感のあるマルチプラットフォーム開発には非常に適している反面、ネイティブ開発における標準ライブラリの豊富さやカスタマイズ性にはまた違った魅力があることを学びました。

この両者の開発手法の特性を理解し、それぞれの強みを活かすことで、より幅広い技術領域を習得し、柔軟性のあるエンジニアとして成長していけると感じました。


Latest最新記事

Popular人気の記事